diff options
Diffstat (limited to 'net')
| -rw-r--r-- | net/bluetooth/af_bluetooth.c | 6 | ||||
| -rw-r--r-- | net/bluetooth/hci_core.c | 4 | ||||
| -rw-r--r-- | net/bluetooth/hci_sock.c | 12 | ||||
| -rw-r--r-- | net/bluetooth/hidp/core.c | 13 | ||||
| -rw-r--r-- | net/bluetooth/rfcomm/Makefile | 2 | ||||
| -rw-r--r-- | net/bluetooth/rfcomm/core.c | 43 | ||||
| -rw-r--r-- | net/bluetooth/rfcomm/crc.c | 71 | ||||
| -rw-r--r-- | net/core/dev.c | 14 | ||||
| -rw-r--r-- | net/core/ethtool.c | 53 | ||||
| -rw-r--r-- | net/core/skbuff.c | 75 | ||||
| -rw-r--r-- | net/ipv4/ip_output.c | 83 | ||||
| -rw-r--r-- | net/ipv6/ip6_output.c | 71 | ||||
| -rw-r--r-- | net/ipv6/mcast.c | 2 |
13 files changed, 351 insertions, 98 deletions
diff --git a/net/bluetooth/af_bluetooth.c b/net/bluetooth/af_bluetooth.c index 12b43345b54f..03532062a46a 100644 --- a/net/bluetooth/af_bluetooth.c +++ b/net/bluetooth/af_bluetooth.c | |||
| @@ -308,12 +308,6 @@ static struct net_proto_family bt_sock_family_ops = { | |||
| 308 | .create = bt_sock_create, | 308 | .create = bt_sock_create, |
| 309 | }; | 309 | }; |
| 310 | 310 | ||
| 311 | extern int hci_sock_init(void); | ||
| 312 | extern int hci_sock_cleanup(void); | ||
| 313 | |||
| 314 | extern int bt_sysfs_init(void); | ||
| 315 | extern int bt_sysfs_cleanup(void); | ||
| 316 | |||
| 317 | static int __init bt_init(void) | 311 | static int __init bt_init(void) |
| 318 | { | 312 | { |
| 319 | BT_INFO("Core ver %s", VERSION); | 313 | BT_INFO("Core ver %s", VERSION); |
diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c index 55dc42eac92c..cf0df1c8c933 100644 --- a/net/bluetooth/hci_core.c +++ b/net/bluetooth/hci_core.c | |||
| @@ -87,7 +87,7 @@ int hci_unregister_notifier(struct notifier_block *nb) | |||
| 87 | return notifier_chain_unregister(&hci_notifier, nb); | 87 | return notifier_chain_unregister(&hci_notifier, nb); |
| 88 | } | 88 | } |
| 89 | 89 | ||
| 90 | void hci_notify(struct hci_dev *hdev, int event) | 90 | static void hci_notify(struct hci_dev *hdev, int event) |
| 91 | { | 91 | { |
| 92 | notifier_call_chain(&hci_notifier, event, hdev); | 92 | notifier_call_chain(&hci_notifier, event, hdev); |
| 93 | } | 93 | } |
| @@ -1347,7 +1347,7 @@ static inline void hci_scodata_packet(struct hci_dev *hdev, struct sk_buff *skb) | |||
| 1347 | kfree_skb(skb); | 1347 | kfree_skb(skb); |
| 1348 | } | 1348 | } |
| 1349 | 1349 | ||
| 1350 | void hci_rx_task(unsigned long arg) | 1350 | static void hci_rx_task(unsigned long arg) |
| 1351 | { | 1351 | { |
| 1352 | struct hci_dev *hdev = (struct hci_dev *) arg; | 1352 | struct hci_dev *hdev = (struct hci_dev *) arg; |
| 1353 | struct sk_buff *skb; | 1353 | struct sk_buff *skb; |
diff --git a/net/bluetooth/hci_sock.c b/net/bluetooth/hci_sock.c index 32ef7975a139..799e448750ad 100644 --- a/net/bluetooth/hci_sock.c +++ b/net/bluetooth/hci_sock.c | |||
| @@ -66,20 +66,20 @@ static struct hci_sec_filter hci_sec_filter = { | |||
| 66 | /* Packet types */ | 66 | /* Packet types */ |
| 67 | 0x10, | 67 | 0x10, |
| 68 | /* Events */ | 68 | /* Events */ |
| 69 | { 0x1000d9fe, 0x0000300c }, | 69 | { 0x1000d9fe, 0x0000b00c }, |
| 70 | /* Commands */ | 70 | /* Commands */ |
| 71 | { | 71 | { |
| 72 | { 0x0 }, | 72 | { 0x0 }, |
| 73 | /* OGF_LINK_CTL */ | 73 | /* OGF_LINK_CTL */ |
| 74 | { 0xbe000006, 0x00000001, 0x0000, 0x00 }, | 74 | { 0xbe000006, 0x00000001, 0x000000, 0x00 }, |
| 75 | /* OGF_LINK_POLICY */ | 75 | /* OGF_LINK_POLICY */ |
| 76 | { 0x00005200, 0x00000000, 0x0000, 0x00 }, | 76 | { 0x00005200, 0x00000000, 0x000000, 0x00 }, |
| 77 | /* OGF_HOST_CTL */ | 77 | /* OGF_HOST_CTL */ |
| 78 | { 0xaab00200, 0x2b402aaa, 0x0154, 0x00 }, | 78 | { 0xaab00200, 0x2b402aaa, 0x020154, 0x00 }, |
| 79 | /* OGF_INFO_PARAM */ | 79 | /* OGF_INFO_PARAM */ |
| 80 | { 0x000002be, 0x00000000, 0x0000, 0x00 }, | 80 | { 0x000002be, 0x00000000, 0x000000, 0x00 }, |
| 81 | /* OGF_STATUS_PARAM */ | 81 | /* OGF_STATUS_PARAM */ |
| 82 | { 0x000000ea, 0x00000000, 0x0000, 0x00 } | 82 | { 0x000000ea, 0x00000000, 0x000000, 0x00 } |
| 83 | } | 83 | } |
| 84 | }; | 84 | }; |
| 85 | 85 | ||
diff --git a/net/bluetooth/hidp/core.c b/net/bluetooth/hidp/core.c index de8af5f42394..860444a7fc0f 100644 --- a/net/bluetooth/hidp/core.c +++ b/net/bluetooth/hidp/core.c | |||
| @@ -520,7 +520,7 @@ static int hidp_session(void *arg) | |||
| 520 | 520 | ||
| 521 | if (session->input) { | 521 | if (session->input) { |
| 522 | input_unregister_device(session->input); | 522 | input_unregister_device(session->input); |
| 523 | kfree(session->input); | 523 | session->input = NULL; |
| 524 | } | 524 | } |
| 525 | 525 | ||
| 526 | up_write(&hidp_session_sem); | 526 | up_write(&hidp_session_sem); |
| @@ -536,6 +536,8 @@ static inline void hidp_setup_input(struct hidp_session *session, struct hidp_co | |||
| 536 | 536 | ||
| 537 | input->private = session; | 537 | input->private = session; |
| 538 | 538 | ||
| 539 | input->name = "Bluetooth HID Boot Protocol Device"; | ||
| 540 | |||
| 539 | input->id.bustype = BUS_BLUETOOTH; | 541 | input->id.bustype = BUS_BLUETOOTH; |
| 540 | input->id.vendor = req->vendor; | 542 | input->id.vendor = req->vendor; |
| 541 | input->id.product = req->product; | 543 | input->id.product = req->product; |
| @@ -582,16 +584,15 @@ int hidp_add_connection(struct hidp_connadd_req *req, struct socket *ctrl_sock, | |||
| 582 | return -ENOTUNIQ; | 584 | return -ENOTUNIQ; |
| 583 | 585 | ||
| 584 | session = kmalloc(sizeof(struct hidp_session), GFP_KERNEL); | 586 | session = kmalloc(sizeof(struct hidp_session), GFP_KERNEL); |
| 585 | if (!session) | 587 | if (!session) |
| 586 | return -ENOMEM; | 588 | return -ENOMEM; |
| 587 | memset(session, 0, sizeof(struct hidp_session)); | 589 | memset(session, 0, sizeof(struct hidp_session)); |
| 588 | 590 | ||
| 589 | session->input = kmalloc(sizeof(struct input_dev), GFP_KERNEL); | 591 | session->input = input_allocate_device(); |
| 590 | if (!session->input) { | 592 | if (!session->input) { |
| 591 | kfree(session); | 593 | kfree(session); |
| 592 | return -ENOMEM; | 594 | return -ENOMEM; |
| 593 | } | 595 | } |
| 594 | memset(session->input, 0, sizeof(struct input_dev)); | ||
| 595 | 596 | ||
| 596 | down_write(&hidp_session_sem); | 597 | down_write(&hidp_session_sem); |
| 597 | 598 | ||
| @@ -651,8 +652,10 @@ unlink: | |||
| 651 | 652 | ||
| 652 | __hidp_unlink_session(session); | 653 | __hidp_unlink_session(session); |
| 653 | 654 | ||
| 654 | if (session->input) | 655 | if (session->input) { |
| 655 | input_unregister_device(session->input); | 656 | input_unregister_device(session->input); |
| 657 | session->input = NULL; /* don't try to free it here */ | ||
| 658 | } | ||
| 656 | 659 | ||
| 657 | failed: | 660 | failed: |
| 658 | up_write(&hidp_session_sem); | 661 | up_write(&hidp_session_sem); |
diff --git a/net/bluetooth/rfcomm/Makefile b/net/bluetooth/rfcomm/Makefile index aecec45ec68d..fe07988a3705 100644 --- a/net/bluetooth/rfcomm/Makefile +++ b/net/bluetooth/rfcomm/Makefile | |||
| @@ -4,5 +4,5 @@ | |||
| 4 | 4 | ||
| 5 | obj-$(CONFIG_BT_RFCOMM) += rfcomm.o | 5 | obj-$(CONFIG_BT_RFCOMM) += rfcomm.o |
| 6 | 6 | ||
| 7 | rfcomm-y := core.o sock.o crc.o | 7 | rfcomm-y := core.o sock.o |
| 8 | rfcomm-$(CONFIG_BT_RFCOMM_TTY) += tty.o | 8 | rfcomm-$(CONFIG_BT_RFCOMM_TTY) += tty.o |
diff --git a/net/bluetooth/rfcomm/core.c b/net/bluetooth/rfcomm/core.c index 35adce6482b6..c3d56ead840c 100644 --- a/net/bluetooth/rfcomm/core.c +++ b/net/bluetooth/rfcomm/core.c | |||
| @@ -133,6 +133,49 @@ static inline void rfcomm_session_put(struct rfcomm_session *s) | |||
| 133 | 133 | ||
| 134 | /* ---- RFCOMM FCS computation ---- */ | 134 | /* ---- RFCOMM FCS computation ---- */ |
| 135 | 135 | ||
| 136 | /* reversed, 8-bit, poly=0x07 */ | ||
| 137 | static unsigned char rfcomm_crc_table[256] = { | ||
| 138 | 0x00, 0x91, 0xe3, 0x72, 0x07, 0x96, 0xe4, 0x75, | ||
| 139 | 0x0e, 0x9f, 0xed, 0x7c, 0x09, 0x98, 0xea, 0x7b, | ||
| 140 | 0x1c, 0x8d, 0xff, 0x6e, 0x1b, 0x8a, 0xf8, 0x69, | ||
| 141 | 0x12, 0x83, 0xf1, 0x60, 0x15, 0x84, 0xf6, 0x67, | ||
| 142 | |||
| 143 | 0x38, 0xa9, 0xdb, 0x4a, 0x3f, 0xae, 0xdc, 0x4d, | ||
| 144 | 0x36, 0xa7, 0xd5, 0x44, 0x31, 0xa0, 0xd2, 0x43, | ||
| 145 | 0x24, 0xb5, 0xc7, 0x56, 0x23, 0xb2, 0xc0, 0x51, | ||
| 146 | 0x2a, 0xbb, 0xc9, 0x58, 0x2d, 0xbc, 0xce, 0x5f, | ||
| 147 | |||
| 148 | 0x70, 0xe1, 0x93, 0x02, 0x77, 0xe6, 0x94, 0x05, | ||
| 149 | 0x7e, 0xef, 0x9d, 0x0c, 0x79, 0xe8, 0x9a, 0x0b, | ||
| 150 | 0x6c, 0xfd, 0x8f, 0x1e, 0x6b, 0xfa, 0x88, 0x19, | ||
| 151 | 0x62, 0xf3, 0x81, 0x10, 0x65, 0xf4, 0x86, 0x17, | ||
| 152 | |||
| 153 | 0x48, 0xd9, 0xab, 0x3a, 0x4f, 0xde, 0xac, 0x3d, | ||
| 154 | 0x46, 0xd7, 0xa5, 0x34, 0x41, 0xd0, 0xa2, 0x33, | ||
| 155 | 0x54, 0xc5, 0xb7, 0x26, 0x53, 0xc2, 0xb0, 0x21, | ||
| 156 | 0x5a, 0xcb, 0xb9, 0x28, 0x5d, 0xcc, 0xbe, 0x2f, | ||
| 157 | |||
| 158 | 0xe0, 0x71, 0x03, 0x92, 0xe7, 0x76, 0x04, 0x95, | ||
| 159 | 0xee, 0x7f, 0x0d, 0x9c, 0xe9, 0x78, 0x0a, 0x9b, | ||
| 160 | 0xfc, 0x6d, 0x1f, 0x8e, 0xfb, 0x6a, 0x18, 0x89, | ||
| 161 | 0xf2, 0x63, 0x11, 0x80, 0xf5, 0x64, 0x16, 0x87, | ||
| 162 | |||
| 163 | 0xd8, 0x49, 0x3b, 0xaa, 0xdf, 0x4e, 0x3c, 0xad, | ||
| 164 | 0xd6, 0x47, 0x35, 0xa4, 0xd1, 0x40, 0x32, 0xa3, | ||
| 165 | 0xc4, 0x55, 0x27, 0xb6, 0xc3, 0x52, 0x20, 0xb1, | ||
| 166 | 0xca, 0x5b, 0x29, 0xb8, 0xcd, 0x5c, 0x2e, 0xbf, | ||
| 167 | |||
| 168 | 0x90, 0x01, 0x73, 0xe2, 0x97, 0x06, 0x74, 0xe5, | ||
| 169 | 0x9e, 0x0f, 0x7d, 0xec, 0x99, 0x08, 0x7a, 0xeb, | ||
| 170 | 0x8c, 0x1d, 0x6f, 0xfe, 0x8b, 0x1a, 0x68, 0xf9, | ||
| 171 | 0x82, 0x13, 0x61, 0xf0, 0x85, 0x14, 0x66, 0xf7, | ||
| 172 | |||
| 173 | 0xa8, 0x39, 0x4b, 0xda, 0xaf, 0x3e, 0x4c, 0xdd, | ||
| 174 | 0xa6, 0x37, 0x45, 0xd4, 0xa1, 0x30, 0x42, 0xd3, | ||
| 175 | 0xb4, 0x25, 0x57, 0xc6, 0xb3, 0x22, 0x50, 0xc1, | ||
| 176 | 0xba, 0x2b, 0x59, 0xc8, 0xbd, 0x2c, 0x5e, 0xcf | ||
| 177 | }; | ||
| 178 | |||
| 136 | /* CRC on 2 bytes */ | 179 | /* CRC on 2 bytes */ |
| 137 | #define __crc(data) (rfcomm_crc_table[rfcomm_crc_table[0xff ^ data[0]] ^ data[1]]) | 180 | #define __crc(data) (rfcomm_crc_table[rfcomm_crc_table[0xff ^ data[0]] ^ data[1]]) |
| 138 | 181 | ||
diff --git a/net/bluetooth/rfcomm/crc.c b/net/bluetooth/rfcomm/crc.c deleted file mode 100644 index 1011bc4a8692..000000000000 --- a/net/bluetooth/rfcomm/crc.c +++ /dev/null | |||
| @@ -1,71 +0,0 @@ | |||
| 1 | /* | ||
| 2 | RFCOMM implementation for Linux Bluetooth stack (BlueZ). | ||
| 3 | Copyright (C) 2002 Maxim Krasnyansky <maxk@qualcomm.com> | ||
| 4 | Copyright (C) 2002 Marcel Holtmann <marcel@holtmann.org> | ||
| 5 | |||
| 6 | This program is free software; you can redistribute it and/or modify | ||
| 7 | it under the terms of the GNU General Public License version 2 as | ||
| 8 | published by the Free Software Foundation; | ||
| 9 | |||
| 10 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS | ||
| 11 | OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
| 12 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS. | ||
| 13 | IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY | ||
| 14 | CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES | ||
| 15 | WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN | ||
| 16 | ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF | ||
| 17 | OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | ||
| 18 | |||
| 19 | ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS, | ||
| 20 | COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS | ||
| 21 | SOFTWARE IS DISCLAIMED. | ||
| 22 | */ | ||
| 23 | |||
| 24 | /* | ||
| 25 | * RFCOMM FCS calculation. | ||
| 26 | * | ||
| 27 | * $Id: crc.c,v 1.2 2002/09/21 09:54:32 holtmann Exp $ | ||
| 28 | */ | ||
| 29 | |||
| 30 | /* reversed, 8-bit, poly=0x07 */ | ||
| 31 | unsigned char rfcomm_crc_table[256] = { | ||
| 32 | 0x00, 0x91, 0xe3, 0x72, 0x07, 0x96, 0xe4, 0x75, | ||
| 33 | 0x0e, 0x9f, 0xed, 0x7c, 0x09, 0x98, 0xea, 0x7b, | ||
| 34 | 0x1c, 0x8d, 0xff, 0x6e, 0x1b, 0x8a, 0xf8, 0x69, | ||
| 35 | 0x12, 0x83, 0xf1, 0x60, 0x15, 0x84, 0xf6, 0x67, | ||
| 36 | |||
| 37 | 0x38, 0xa9, 0xdb, 0x4a, 0x3f, 0xae, 0xdc, 0x4d, | ||
| 38 | 0x36, 0xa7, 0xd5, 0x44, 0x31, 0xa0, 0xd2, 0x43, | ||
| 39 | 0x24, 0xb5, 0xc7, 0x56, 0x23, 0xb2, 0xc0, 0x51, | ||
| 40 | 0x2a, 0xbb, 0xc9, 0x58, 0x2d, 0xbc, 0xce, 0x5f, | ||
| 41 | |||
| 42 | 0x70, 0xe1, 0x93, 0x02, 0x77, 0xe6, 0x94, 0x05, | ||
| 43 | 0x7e, 0xef, 0x9d, 0x0c, 0x79, 0xe8, 0x9a, 0x0b, | ||
| 44 | 0x6c, 0xfd, 0x8f, 0x1e, 0x6b, 0xfa, 0x88, 0x19, | ||
| 45 | 0x62, 0xf3, 0x81, 0x10, 0x65, 0xf4, 0x86, 0x17, | ||
| 46 | |||
| 47 | 0x48, 0xd9, 0xab, 0x3a, 0x4f, 0xde, 0xac, 0x3d, | ||
| 48 | 0x46, 0xd7, 0xa5, 0x34, 0x41, 0xd0, 0xa2, 0x33, | ||
| 49 | 0x54, 0xc5, 0xb7, 0x26, 0x53, 0xc2, 0xb0, 0x21, | ||
| 50 | 0x5a, 0xcb, 0xb9, 0x28, 0x5d, 0xcc, 0xbe, 0x2f, | ||
| 51 | |||
| 52 | 0xe0, 0x71, 0x03, 0x92, 0xe7, 0x76, 0x04, 0x95, | ||
| 53 | 0xee, 0x7f, 0x0d, 0x9c, 0xe9, 0x78, 0x0a, 0x9b, | ||
| 54 | 0xfc, 0x6d, 0x1f, 0x8e, 0xfb, 0x6a, 0x18, 0x89, | ||
| 55 | 0xf2, 0x63, 0x11, 0x80, 0xf5, 0x64, 0x16, 0x87, | ||
| 56 | |||
| 57 | 0xd8, 0x49, 0x3b, 0xaa, 0xdf, 0x4e, 0x3c, 0xad, | ||
| 58 | 0xd6, 0x47, 0x35, 0xa4, 0xd1, 0x40, 0x32, 0xa3, | ||
| 59 | 0xc4, 0x55, 0x27, 0xb6, 0xc3, 0x52, 0x20, 0xb1, | ||
| 60 | 0xca, 0x5b, 0x29, 0xb8, 0xcd, 0x5c, 0x2e, 0xbf, | ||
| 61 | |||
| 62 | 0x90, 0x01, 0x73, 0xe2, 0x97, 0x06, 0x74, 0xe5, | ||
| 63 | 0x9e, 0x0f, 0x7d, 0xec, 0x99, 0x08, 0x7a, 0xeb, | ||
| 64 | 0x8c, 0x1d, 0x6f, 0xfe, 0x8b, 0x1a, 0x68, 0xf9, | ||
| 65 | 0x82, 0x13, 0x61, 0xf0, 0x85, 0x14, 0x66, 0xf7, | ||
| 66 | |||
| 67 | 0xa8, 0x39, 0x4b, 0xda, 0xaf, 0x3e, 0x4c, 0xdd, | ||
| 68 | 0xa6, 0x37, 0x45, 0xd4, 0xa1, 0x30, 0x42, 0xd3, | ||
| 69 | 0xb4, 0x25, 0x57, 0xc6, 0xb3, 0x22, 0x50, 0xc1, | ||
| 70 | 0xba, 0x2b, 0x59, 0xc8, 0xbd, 0x2c, 0x5e, 0xcf | ||
| 71 | }; | ||
diff --git a/net/core/dev.c b/net/core/dev.c index a44eeef24edf..8d1541595277 100644 --- a/net/core/dev.c +++ b/net/core/dev.c | |||
| @@ -2717,6 +2717,20 @@ int register_netdevice(struct net_device *dev) | |||
| 2717 | dev->name); | 2717 | dev->name); |
| 2718 | dev->features &= ~NETIF_F_TSO; | 2718 | dev->features &= ~NETIF_F_TSO; |
| 2719 | } | 2719 | } |
| 2720 | if (dev->features & NETIF_F_UFO) { | ||
| 2721 | if (!(dev->features & NETIF_F_HW_CSUM)) { | ||
| 2722 | printk(KERN_ERR "%s: Dropping NETIF_F_UFO since no " | ||
| 2723 | "NETIF_F_HW_CSUM feature.\n", | ||
| 2724 | dev->name); | ||
| 2725 | dev->features &= ~NETIF_F_UFO; | ||
| 2726 | } | ||
| 2727 | if (!(dev->features & NETIF_F_SG)) { | ||
| 2728 | printk(KERN_ERR "%s: Dropping NETIF_F_UFO since no " | ||
| 2729 | "NETIF_F_SG feature.\n", | ||
| 2730 | dev->name); | ||
| 2731 | dev->features &= ~NETIF_F_UFO; | ||
| 2732 | } | ||
| 2733 | } | ||
| 2720 | 2734 | ||
| 2721 | /* | 2735 | /* |
| 2722 | * nil rebuild_header routine, | 2736 | * nil rebuild_header routine, |
diff --git a/net/core/ethtool.c b/net/core/ethtool.c index 404b761e82ce..0350586e9195 100644 --- a/net/core/ethtool.c +++ b/net/core/ethtool.c | |||
| @@ -93,6 +93,20 @@ int ethtool_op_get_perm_addr(struct net_device *dev, struct ethtool_perm_addr *a | |||
| 93 | } | 93 | } |
| 94 | 94 | ||
| 95 | 95 | ||
| 96 | u32 ethtool_op_get_ufo(struct net_device *dev) | ||
| 97 | { | ||
| 98 | return (dev->features & NETIF_F_UFO) != 0; | ||
| 99 | } | ||
| 100 | |||
| 101 | int ethtool_op_set_ufo(struct net_device *dev, u32 data) | ||
| 102 | { | ||
| 103 | if (data) | ||
| 104 | dev->features |= NETIF_F_UFO; | ||
| 105 | else | ||
| 106 | dev->features &= ~NETIF_F_UFO; | ||
| 107 | return 0; | ||
| 108 | } | ||
| 109 | |||
| 96 | /* Handlers for each ethtool command */ | 110 | /* Handlers for each ethtool command */ |
| 97 | 111 | ||
| 98 | static int ethtool_get_settings(struct net_device *dev, void __user *useraddr) | 112 | static int ethtool_get_settings(struct net_device *dev, void __user *useraddr) |
| @@ -483,6 +497,11 @@ static int __ethtool_set_sg(struct net_device *dev, u32 data) | |||
| 483 | return err; | 497 | return err; |
| 484 | } | 498 | } |
| 485 | 499 | ||
| 500 | if (!data && dev->ethtool_ops->set_ufo) { | ||
| 501 | err = dev->ethtool_ops->set_ufo(dev, 0); | ||
| 502 | if (err) | ||
| 503 | return err; | ||
| 504 | } | ||
| 486 | return dev->ethtool_ops->set_sg(dev, data); | 505 | return dev->ethtool_ops->set_sg(dev, data); |
| 487 | } | 506 | } |
| 488 | 507 | ||
| @@ -569,6 +588,32 @@ static int ethtool_set_tso(struct net_device *dev, char __user *useraddr) | |||
| 569 | return dev->ethtool_ops->set_tso(dev, edata.data); | 588 | return dev->ethtool_ops->set_tso(dev, edata.data); |
| 570 | } | 589 | } |
| 571 | 590 | ||
| 591 | static int ethtool_get_ufo(struct net_device *dev, char __user *useraddr) | ||
| 592 | { | ||
| 593 | struct ethtool_value edata = { ETHTOOL_GTSO }; | ||
| 594 | |||
| 595 | if (!dev->ethtool_ops->get_ufo) | ||
| 596 | return -EOPNOTSUPP; | ||
| 597 | edata.data = dev->ethtool_ops->get_ufo(dev); | ||
| 598 | if (copy_to_user(useraddr, &edata, sizeof(edata))) | ||
| 599 | return -EFAULT; | ||
| 600 | return 0; | ||
| 601 | } | ||
| 602 | static int ethtool_set_ufo(struct net_device *dev, char __user *useraddr) | ||
| 603 | { | ||
| 604 | struct ethtool_value edata; | ||
| 605 | |||
| 606 | if (!dev->ethtool_ops->set_ufo) | ||
| 607 | return -EOPNOTSUPP; | ||
| 608 | if (copy_from_user(&edata, useraddr, sizeof(edata))) | ||
| 609 | return -EFAULT; | ||
| 610 | if (edata.data && !(dev->features & NETIF_F_SG)) | ||
| 611 | return -EINVAL; | ||
| 612 | if (edata.data && !(dev->features & NETIF_F_HW_CSUM)) | ||
| 613 | return -EINVAL; | ||
| 614 | return dev->ethtool_ops->set_ufo(dev, edata.data); | ||
| 615 | } | ||
| 616 | |||
| 572 | static int ethtool_self_test(struct net_device *dev, char __user *useraddr) | 617 | static int ethtool_self_test(struct net_device *dev, char __user *useraddr) |
| 573 | { | 618 | { |
| 574 | struct ethtool_test test; | 619 | struct ethtool_test test; |
| @@ -854,6 +899,12 @@ int dev_ethtool(struct ifreq *ifr) | |||
| 854 | case ETHTOOL_GPERMADDR: | 899 | case ETHTOOL_GPERMADDR: |
| 855 | rc = ethtool_get_perm_addr(dev, useraddr); | 900 | rc = ethtool_get_perm_addr(dev, useraddr); |
| 856 | break; | 901 | break; |
| 902 | case ETHTOOL_GUFO: | ||
| 903 | rc = ethtool_get_ufo(dev, useraddr); | ||
| 904 | break; | ||
| 905 | case ETHTOOL_SUFO: | ||
| 906 | rc = ethtool_set_ufo(dev, useraddr); | ||
| 907 | break; | ||
| 857 | default: | 908 | default: |
| 858 | rc = -EOPNOTSUPP; | 909 | rc = -EOPNOTSUPP; |
| 859 | } | 910 | } |
| @@ -882,3 +933,5 @@ EXPORT_SYMBOL(ethtool_op_set_sg); | |||
| 882 | EXPORT_SYMBOL(ethtool_op_set_tso); | 933 | EXPORT_SYMBOL(ethtool_op_set_tso); |
| 883 | EXPORT_SYMBOL(ethtool_op_set_tx_csum); | 934 | EXPORT_SYMBOL(ethtool_op_set_tx_csum); |
| 884 | EXPORT_SYMBOL(ethtool_op_set_tx_hw_csum); | 935 | EXPORT_SYMBOL(ethtool_op_set_tx_hw_csum); |
| 936 | EXPORT_SYMBOL(ethtool_op_set_ufo); | ||
| 937 | EXPORT_SYMBOL(ethtool_op_get_ufo); | ||
diff --git a/net/core/skbuff.c b/net/core/skbuff.c index ef9d46b91eb9..95501e40100e 100644 --- a/net/core/skbuff.c +++ b/net/core/skbuff.c | |||
| @@ -176,6 +176,8 @@ struct sk_buff *__alloc_skb(unsigned int size, gfp_t gfp_mask, | |||
| 176 | skb_shinfo(skb)->tso_size = 0; | 176 | skb_shinfo(skb)->tso_size = 0; |
| 177 | skb_shinfo(skb)->tso_segs = 0; | 177 | skb_shinfo(skb)->tso_segs = 0; |
| 178 | skb_shinfo(skb)->frag_list = NULL; | 178 | skb_shinfo(skb)->frag_list = NULL; |
| 179 | skb_shinfo(skb)->ufo_size = 0; | ||
| 180 | skb_shinfo(skb)->ip6_frag_id = 0; | ||
| 179 | out: | 181 | out: |
| 180 | return skb; | 182 | return skb; |
| 181 | nodata: | 183 | nodata: |
| @@ -1696,6 +1698,78 @@ unsigned int skb_find_text(struct sk_buff *skb, unsigned int from, | |||
| 1696 | return textsearch_find(config, state); | 1698 | return textsearch_find(config, state); |
| 1697 | } | 1699 | } |
| 1698 | 1700 | ||
| 1701 | /** | ||
| 1702 | * skb_append_datato_frags: - append the user data to a skb | ||
| 1703 | * @sk: sock structure | ||
| 1704 | * @skb: skb structure to be appened with user data. | ||
| 1705 | * @getfrag: call back function to be used for getting the user data | ||
| 1706 | * @from: pointer to user message iov | ||
| 1707 | * @length: length of the iov message | ||
| 1708 | * | ||
| 1709 | * Description: This procedure append the user data in the fragment part | ||
| 1710 | * of the skb if any page alloc fails user this procedure returns -ENOMEM | ||
| 1711 | */ | ||
| 1712 | int skb_append_datato_frags(struct sock *sk, struct sk_buff *skb, | ||
| 1713 | int getfrag(void *from, char *to, int offset, | ||
| 1714 | int len, int odd, struct sk_buff *skb), | ||
| 1715 | void *from, int length) | ||
| 1716 | { | ||
| 1717 | int frg_cnt = 0; | ||
| 1718 | skb_frag_t *frag = NULL; | ||
| 1719 | struct page *page = NULL; | ||
| 1720 | int copy, left; | ||
| 1721 | int offset = 0; | ||
| 1722 | int ret; | ||
| 1723 | |||
| 1724 | do { | ||
| 1725 | /* Return error if we don't have space for new frag */ | ||
| 1726 | frg_cnt = skb_shinfo(skb)->nr_frags; | ||
| 1727 | if (frg_cnt >= MAX_SKB_FRAGS) | ||
| 1728 | return -EFAULT; | ||
| 1729 | |||
| 1730 | /* allocate a new page for next frag */ | ||
| 1731 | page = alloc_pages(sk->sk_allocation, 0); | ||
| 1732 | |||
| 1733 | /* If alloc_page fails just return failure and caller will | ||
| 1734 | * free previous allocated pages by doing kfree_skb() | ||
| 1735 | */ | ||
| 1736 | if (page == NULL) | ||
| 1737 | return -ENOMEM; | ||
| 1738 | |||
| 1739 | /* initialize the next frag */ | ||
| 1740 | sk->sk_sndmsg_page = page; | ||
| 1741 | sk->sk_sndmsg_off = 0; | ||
| 1742 | skb_fill_page_desc(skb, frg_cnt, page, 0, 0); | ||
| 1743 | skb->truesize += PAGE_SIZE; | ||
| 1744 | atomic_add(PAGE_SIZE, &sk->sk_wmem_alloc); | ||
| 1745 | |||
| 1746 | /* get the new initialized frag */ | ||
| 1747 | frg_cnt = skb_shinfo(skb)->nr_frags; | ||
| 1748 | frag = &skb_shinfo(skb)->frags[frg_cnt - 1]; | ||
| 1749 | |||
| 1750 | /* copy the user data to page */ | ||
| 1751 | left = PAGE_SIZE - frag->page_offset; | ||
| 1752 | copy = (length > left)? left : length; | ||
| 1753 | |||
| 1754 | ret = getfrag(from, (page_address(frag->page) + | ||
| 1755 | frag->page_offset + frag->size), | ||
| 1756 | offset, copy, 0, skb); | ||
| 1757 | if (ret < 0) | ||
| 1758 | return -EFAULT; | ||
| 1759 | |||
| 1760 | /* copy was successful so update the size parameters */ | ||
| 1761 | sk->sk_sndmsg_off += copy; | ||
| 1762 | frag->size += copy; | ||
| 1763 | skb->len += copy; | ||
| 1764 | skb->data_len += copy; | ||
| 1765 | offset += copy; | ||
| 1766 | length -= copy; | ||
| 1767 | |||
| 1768 | } while (length > 0); | ||
| 1769 | |||
| 1770 | return 0; | ||
| 1771 | } | ||
| 1772 | |||
| 1699 | void __init skb_init(void) | 1773 | void __init skb_init(void) |
| 1700 | { | 1774 | { |
| 1701 | skbuff_head_cache = kmem_cache_create("skbuff_head_cache", | 1775 | skbuff_head_cache = kmem_cache_create("skbuff_head_cache", |
| @@ -1747,3 +1821,4 @@ EXPORT_SYMBOL(skb_prepare_seq_read); | |||
| 1747 | EXPORT_SYMBOL(skb_seq_read); | 1821 | EXPORT_SYMBOL(skb_seq_read); |
| 1748 | EXPORT_SYMBOL(skb_abort_seq_read); | 1822 | EXPORT_SYMBOL(skb_abort_seq_read); |
| 1749 | EXPORT_SYMBOL(skb_find_text); | 1823 | EXPORT_SYMBOL(skb_find_text); |
| 1824 | EXPORT_SYMBOL(skb_append_datato_frags); | ||
diff --git a/net/ipv4/ip_output.c b/net/ipv4/ip_output.c index 87e350069abb..17758234a3e3 100644 --- a/net/ipv4/ip_output.c +++ b/net/ipv4/ip_output.c | |||
| @@ -275,7 +275,8 @@ int ip_output(struct sk_buff *skb) | |||
| 275 | { | 275 | { |
| 276 | IP_INC_STATS(IPSTATS_MIB_OUTREQUESTS); | 276 | IP_INC_STATS(IPSTATS_MIB_OUTREQUESTS); |
| 277 | 277 | ||
| 278 | if (skb->len > dst_mtu(skb->dst) && !skb_shinfo(skb)->tso_size) | 278 | if (skb->len > dst_mtu(skb->dst) && |
| 279 | !(skb_shinfo(skb)->ufo_size || skb_shinfo(skb)->tso_size)) | ||
| 279 | return ip_fragment(skb, ip_finish_output); | 280 | return ip_fragment(skb, ip_finish_output); |
| 280 | else | 281 | else |
| 281 | return ip_finish_output(skb); | 282 | return ip_finish_output(skb); |
| @@ -688,6 +689,60 @@ csum_page(struct page *page, int offset, int copy) | |||
| 688 | return csum; | 689 | return csum; |
| 689 | } | 690 | } |
| 690 | 691 | ||
| 692 | inline int ip_ufo_append_data(struct sock *sk, | ||
| 693 | int getfrag(void *from, char *to, int offset, int len, | ||
| 694 | int odd, struct sk_buff *skb), | ||
| 695 | void *from, int length, int hh_len, int fragheaderlen, | ||
| 696 | int transhdrlen, int mtu,unsigned int flags) | ||
| 697 | { | ||
| 698 | struct sk_buff *skb; | ||
| 699 | int err; | ||
| 700 | |||
| 701 | /* There is support for UDP fragmentation offload by network | ||
| 702 | * device, so create one single skb packet containing complete | ||
| 703 | * udp datagram | ||
| 704 | */ | ||
| 705 | if ((skb = skb_peek_tail(&sk->sk_write_queue)) == NULL) { | ||
| 706 | skb = sock_alloc_send_skb(sk, | ||
| 707 | hh_len + fragheaderlen + transhdrlen + 20, | ||
| 708 | (flags & MSG_DONTWAIT), &err); | ||
| 709 | |||
| 710 | if (skb == NULL) | ||
| 711 | return err; | ||
| 712 | |||
| 713 | /* reserve space for Hardware header */ | ||
| 714 | skb_reserve(skb, hh_len); | ||
| 715 | |||
| 716 | /* create space for UDP/IP header */ | ||
| 717 | skb_put(skb,fragheaderlen + transhdrlen); | ||
| 718 | |||
| 719 | /* initialize network header pointer */ | ||
| 720 | skb->nh.raw = skb->data; | ||
| 721 | |||
| 722 | /* initialize protocol header pointer */ | ||
| 723 | skb->h.raw = skb->data + fragheaderlen; | ||
| 724 | |||
| 725 | skb->ip_summed = CHECKSUM_HW; | ||
| 726 | skb->csum = 0; | ||
| 727 | sk->sk_sndmsg_off = 0; | ||
| 728 | } | ||
| 729 | |||
| 730 | err = skb_append_datato_frags(sk,skb, getfrag, from, | ||
| 731 | (length - transhdrlen)); | ||
| 732 | if (!err) { | ||
| 733 | /* specify the length of each IP datagram fragment*/ | ||
| 734 | skb_shinfo(skb)->ufo_size = (mtu - fragheaderlen); | ||
| 735 | __skb_queue_tail(&sk->sk_write_queue, skb); | ||
| 736 | |||
| 737 | return 0; | ||
| 738 | } | ||
| 739 | /* There is not enough support do UFO , | ||
| 740 | * so follow normal path | ||
| 741 | */ | ||
| 742 | kfree_skb(skb); | ||
| 743 | return err; | ||
| 744 | } | ||
| 745 | |||
| 691 | /* | 746 | /* |
| 692 | * ip_append_data() and ip_append_page() can make one large IP datagram | 747 | * ip_append_data() and ip_append_page() can make one large IP datagram |
| 693 | * from many pieces of data. Each pieces will be holded on the socket | 748 | * from many pieces of data. Each pieces will be holded on the socket |
| @@ -777,6 +832,15 @@ int ip_append_data(struct sock *sk, | |||
| 777 | csummode = CHECKSUM_HW; | 832 | csummode = CHECKSUM_HW; |
| 778 | 833 | ||
| 779 | inet->cork.length += length; | 834 | inet->cork.length += length; |
| 835 | if (((length > mtu) && (sk->sk_protocol == IPPROTO_UDP)) && | ||
| 836 | (rt->u.dst.dev->features & NETIF_F_UFO)) { | ||
| 837 | |||
| 838 | if(ip_ufo_append_data(sk, getfrag, from, length, hh_len, | ||
| 839 | fragheaderlen, transhdrlen, mtu, flags)) | ||
| 840 | goto error; | ||
| 841 | |||
| 842 | return 0; | ||
| 843 | } | ||
| 780 | 844 | ||
| 781 | /* So, what's going on in the loop below? | 845 | /* So, what's going on in the loop below? |
| 782 | * | 846 | * |
| @@ -1008,14 +1072,23 @@ ssize_t ip_append_page(struct sock *sk, struct page *page, | |||
| 1008 | return -EINVAL; | 1072 | return -EINVAL; |
| 1009 | 1073 | ||
| 1010 | inet->cork.length += size; | 1074 | inet->cork.length += size; |
| 1075 | if ((sk->sk_protocol == IPPROTO_UDP) && | ||
| 1076 | (rt->u.dst.dev->features & NETIF_F_UFO)) | ||
| 1077 | skb_shinfo(skb)->ufo_size = (mtu - fragheaderlen); | ||
| 1078 | |||
| 1011 | 1079 | ||
| 1012 | while (size > 0) { | 1080 | while (size > 0) { |
| 1013 | int i; | 1081 | int i; |
| 1014 | 1082 | ||
| 1015 | /* Check if the remaining data fits into current packet. */ | 1083 | if (skb_shinfo(skb)->ufo_size) |
| 1016 | len = mtu - skb->len; | 1084 | len = size; |
| 1017 | if (len < size) | 1085 | else { |
| 1018 | len = maxfraglen - skb->len; | 1086 | |
| 1087 | /* Check if the remaining data fits into current packet. */ | ||
| 1088 | len = mtu - skb->len; | ||
| 1089 | if (len < size) | ||
| 1090 | len = maxfraglen - skb->len; | ||
| 1091 | } | ||
| 1019 | if (len <= 0) { | 1092 | if (len <= 0) { |
| 1020 | struct sk_buff *skb_prev; | 1093 | struct sk_buff *skb_prev; |
| 1021 | char *data; | 1094 | char *data; |
diff --git a/net/ipv6/ip6_output.c b/net/ipv6/ip6_output.c index 563b442ffab8..614296a920c6 100644 --- a/net/ipv6/ip6_output.c +++ b/net/ipv6/ip6_output.c | |||
| @@ -147,7 +147,8 @@ static int ip6_output2(struct sk_buff *skb) | |||
| 147 | 147 | ||
| 148 | int ip6_output(struct sk_buff *skb) | 148 | int ip6_output(struct sk_buff *skb) |
| 149 | { | 149 | { |
| 150 | if (skb->len > dst_mtu(skb->dst) || dst_allfrag(skb->dst)) | 150 | if ((skb->len > dst_mtu(skb->dst) && !skb_shinfo(skb)->ufo_size) || |
| 151 | dst_allfrag(skb->dst)) | ||
| 151 | return ip6_fragment(skb, ip6_output2); | 152 | return ip6_fragment(skb, ip6_output2); |
| 152 | else | 153 | else |
| 153 | return ip6_output2(skb); | 154 | return ip6_output2(skb); |
| @@ -768,6 +769,65 @@ out_err_release: | |||
| 768 | *dst = NULL; | 769 | *dst = NULL; |
| 769 | return err; | 770 | return err; |
| 770 | } | 771 | } |
| 772 | inline int ip6_ufo_append_data(struct sock *sk, | ||
| 773 | int getfrag(void *from, char *to, int offset, int len, | ||
| 774 | int odd, struct sk_buff *skb), | ||
| 775 | void *from, int length, int hh_len, int fragheaderlen, | ||
| 776 | int transhdrlen, int mtu,unsigned int flags) | ||
| 777 | |||
| 778 | { | ||
| 779 | struct sk_buff *skb; | ||
| 780 | int err; | ||
| 781 | |||
| 782 | /* There is support for UDP large send offload by network | ||
| 783 | * device, so create one single skb packet containing complete | ||
| 784 | * udp datagram | ||
| 785 | */ | ||
| 786 | if ((skb = skb_peek_tail(&sk->sk_write_queue)) == NULL) { | ||
| 787 | skb = sock_alloc_send_skb(sk, | ||
| 788 | hh_len + fragheaderlen + transhdrlen + 20, | ||
| 789 | (flags & MSG_DONTWAIT), &err); | ||
| 790 | if (skb == NULL) | ||
| 791 | return -ENOMEM; | ||
| 792 | |||
| 793 | /* reserve space for Hardware header */ | ||
| 794 | skb_reserve(skb, hh_len); | ||
| 795 | |||
| 796 | /* create space for UDP/IP header */ | ||
| 797 | skb_put(skb,fragheaderlen + transhdrlen); | ||
| 798 | |||
| 799 | /* initialize network header pointer */ | ||
| 800 | skb->nh.raw = skb->data; | ||
| 801 | |||
| 802 | /* initialize protocol header pointer */ | ||
| 803 | skb->h.raw = skb->data + fragheaderlen; | ||
| 804 | |||
| 805 | skb->ip_summed = CHECKSUM_HW; | ||
| 806 | skb->csum = 0; | ||
| 807 | sk->sk_sndmsg_off = 0; | ||
| 808 | } | ||
| 809 | |||
| 810 | err = skb_append_datato_frags(sk,skb, getfrag, from, | ||
| 811 | (length - transhdrlen)); | ||
| 812 | if (!err) { | ||
| 813 | struct frag_hdr fhdr; | ||
| 814 | |||
| 815 | /* specify the length of each IP datagram fragment*/ | ||
| 816 | skb_shinfo(skb)->ufo_size = (mtu - fragheaderlen) - | ||
| 817 | sizeof(struct frag_hdr); | ||
| 818 | ipv6_select_ident(skb, &fhdr); | ||
| 819 | skb_shinfo(skb)->ip6_frag_id = fhdr.identification; | ||
| 820 | __skb_queue_tail(&sk->sk_write_queue, skb); | ||
| 821 | |||
| 822 | return 0; | ||
| 823 | } | ||
| 824 | /* There is not enough support do UPD LSO, | ||
| 825 | * so follow normal path | ||
| 826 | */ | ||
| 827 | kfree_skb(skb); | ||
| 828 | |||
| 829 | return err; | ||
| 830 | } | ||
| 771 | 831 | ||
| 772 | int ip6_append_data(struct sock *sk, int getfrag(void *from, char *to, | 832 | int ip6_append_data(struct sock *sk, int getfrag(void *from, char *to, |
| 773 | int offset, int len, int odd, struct sk_buff *skb), | 833 | int offset, int len, int odd, struct sk_buff *skb), |
| @@ -860,6 +920,15 @@ int ip6_append_data(struct sock *sk, int getfrag(void *from, char *to, | |||
| 860 | */ | 920 | */ |
| 861 | 921 | ||
| 862 | inet->cork.length += length; | 922 | inet->cork.length += length; |
| 923 | if (((length > mtu) && (sk->sk_protocol == IPPROTO_UDP)) && | ||
| 924 | (rt->u.dst.dev->features & NETIF_F_UFO)) { | ||
| 925 | |||
| 926 | if(ip6_ufo_append_data(sk, getfrag, from, length, hh_len, | ||
| 927 | fragheaderlen, transhdrlen, mtu, flags)) | ||
| 928 | goto error; | ||
| 929 | |||
| 930 | return 0; | ||
| 931 | } | ||
| 863 | 932 | ||
| 864 | if ((skb = skb_peek_tail(&sk->sk_write_queue)) == NULL) | 933 | if ((skb = skb_peek_tail(&sk->sk_write_queue)) == NULL) |
| 865 | goto alloc_new_skb; | 934 | goto alloc_new_skb; |
diff --git a/net/ipv6/mcast.c b/net/ipv6/mcast.c index 39a96c768102..c4f2a0ef7489 100644 --- a/net/ipv6/mcast.c +++ b/net/ipv6/mcast.c | |||
| @@ -164,7 +164,7 @@ static int ip6_mc_leave_src(struct sock *sk, struct ipv6_mc_socklist *iml, | |||
| 164 | #define MLDV2_MASK(value, nb) ((nb)>=32 ? (value) : ((1<<(nb))-1) & (value)) | 164 | #define MLDV2_MASK(value, nb) ((nb)>=32 ? (value) : ((1<<(nb))-1) & (value)) |
| 165 | #define MLDV2_EXP(thresh, nbmant, nbexp, value) \ | 165 | #define MLDV2_EXP(thresh, nbmant, nbexp, value) \ |
| 166 | ((value) < (thresh) ? (value) : \ | 166 | ((value) < (thresh) ? (value) : \ |
| 167 | ((MLDV2_MASK(value, nbmant) | (1<<(nbmant+nbexp))) << \ | 167 | ((MLDV2_MASK(value, nbmant) | (1<<(nbmant))) << \ |
| 168 | (MLDV2_MASK((value) >> (nbmant), nbexp) + (nbexp)))) | 168 | (MLDV2_MASK((value) >> (nbmant), nbexp) + (nbexp)))) |
| 169 | 169 | ||
| 170 | #define MLDV2_QQIC(value) MLDV2_EXP(0x80, 4, 3, value) | 170 | #define MLDV2_QQIC(value) MLDV2_EXP(0x80, 4, 3, value) |
