Browse Source

Merge git://git.kernel.org/pub/scm/linux/kernel/git/davem/net-next-2.6

* git://git.kernel.org/pub/scm/linux/kernel/git/davem/net-next-2.6: (1480 commits)
  bonding: enable netpoll without checking link status
  xfrm: Refcount destination entry on xfrm_lookup
  net: introduce rx_handler results and logic around that
  bonding: get rid of IFF_SLAVE_INACTIVE netdev->priv_flag
  bonding: wrap slave state work
  net: get rid of multiple bond-related netdevice->priv_flags
  bonding: register slave pointer for rx_handler
  be2net: Bump up the version number
  be2net: Copyright notice change. Update to Emulex instead of ServerEngines
  e1000e: fix kconfig for crc32 dependency
  netfilter ebtables: fix xt_AUDIT to work with ebtables
  xen network backend driver
  bonding: Improve syslog message at device creation time
  bonding: Call netif_carrier_off after register_netdevice
  bonding: Incorrect TX queue offset
  net_sched: fix ip_tos2prio
  xfrm: fix __xfrm_route_forward()
  be2net: Fix UDP packet detected status in RX compl
  Phonet: fix aligned-mode pipe socket buffer header reserve
  netxen: support for GbE port settings
  ...

Fix up conflicts in drivers/staging/brcm80211/brcmsmac/wl_mac80211.c
with the staging updates.
master
Linus Torvalds 11 years ago
parent
commit
7a6362800c
  1. 26
      Documentation/feature-removal-schedule.txt
  2. 16
      Documentation/networking/batman-adv.txt
  3. 26
      Documentation/networking/bonding.txt
  4. 11
      Documentation/networking/ip-sysctl.txt
  5. 67
      Documentation/networking/phonet.txt
  6. 10
      MAINTAINERS
  7. 10
      arch/sh/include/asm/sh_eth.h
  8. 2
      crypto/Makefile
  9. 835
      crypto/authencesn.c
  10. 2
      drivers/block/drbd/drbd_nl.c
  11. 287
      drivers/bluetooth/ath3k.c
  12. 13
      drivers/bluetooth/btusb.c
  13. 1
      drivers/bluetooth/hci_ldisc.c
  14. 31
      drivers/infiniband/core/addr.c
  15. 22
      drivers/infiniband/hw/cxgb3/iwch_cm.c
  16. 22
      drivers/infiniband/hw/cxgb4/cm.c
  17. 3
      drivers/infiniband/hw/nes/nes.c
  18. 8
      drivers/infiniband/hw/nes/nes_cm.c
  19. 2
      drivers/md/dm-log-userspace-transfer.c
  20. 90
      drivers/net/Kconfig
  21. 2
      drivers/net/Makefile
  22. 15
      drivers/net/atl1c/atl1c_hw.c
  23. 43
      drivers/net/atl1c/atl1c_hw.h
  24. 5
      drivers/net/atl1c/atl1c_main.c
  25. 12
      drivers/net/atl1e/atl1e_ethtool.c
  26. 34
      drivers/net/atl1e/atl1e_hw.c
  27. 111
      drivers/net/atl1e/atl1e_hw.h
  28. 10
      drivers/net/atl1e/atl1e_main.c
  29. 77
      drivers/net/atlx/atl1.c
  30. 2
      drivers/net/atlx/atl2.c
  31. 810
      drivers/net/ax88796.c
  32. 55
      drivers/net/benet/be.h
  33. 202
      drivers/net/benet/be_cmds.c
  34. 96
      drivers/net/benet/be_cmds.h
  35. 87
      drivers/net/benet/be_ethtool.c
  36. 110
      drivers/net/benet/be_hw.h
  37. 620
      drivers/net/benet/be_main.c
  38. 108
      drivers/net/bna/bnad.c
  39. 2
      drivers/net/bna/bnad.h
  40. 16
      drivers/net/bnx2.c
  41. 6
      drivers/net/bnx2.h
  42. 35
      drivers/net/bnx2x/bnx2x.h
  43. 70
      drivers/net/bnx2x/bnx2x_cmn.c
  44. 6
      drivers/net/bnx2x/bnx2x_cmn.h
  45. 137
      drivers/net/bnx2x/bnx2x_dcb.c
  46. 5
      drivers/net/bnx2x/bnx2x_dcb.h
  47. 58
      drivers/net/bnx2x/bnx2x_ethtool.c
  48. 114
      drivers/net/bnx2x/bnx2x_hsi.h
  49. 2527
      drivers/net/bnx2x/bnx2x_link.c
  50. 34
      drivers/net/bnx2x/bnx2x_link.h
  51. 600
      drivers/net/bnx2x/bnx2x_main.c
  52. 1
      drivers/net/bnx2x/bnx2x_reg.h
  53. 3
      drivers/net/bonding/Makefile
  54. 2
      drivers/net/bonding/bond_3ad.c
  55. 2
      drivers/net/bonding/bond_alb.c
  56. 638
      drivers/net/bonding/bond_main.c
  57. 275
      drivers/net/bonding/bond_procfs.c
  58. 23
      drivers/net/bonding/bond_sysfs.c
  59. 111
      drivers/net/bonding/bonding.h
  60. 2
      drivers/net/can/Kconfig
  61. 1
      drivers/net/can/Makefile
  62. 15
      drivers/net/can/c_can/Kconfig
  63. 8
      drivers/net/can/c_can/Makefile
  64. 1158
      drivers/net/can/c_can/c_can.c
  65. 86
      drivers/net/can/c_can/c_can.h
  66. 215
      drivers/net/can/c_can/c_can_platform.c
  67. 6
      drivers/net/can/usb/esd_usb2.c
  68. 209
      drivers/net/cnic.c
  69. 2
      drivers/net/cnic.h
  70. 8
      drivers/net/cnic_if.h
  71. 19
      drivers/net/cs89x0.c
  72. 5
      drivers/net/cxgb3/cxgb3_offload.c
  73. 1
      drivers/net/cxgb4/cxgb4_main.c
  74. 2
      drivers/net/davinci_emac.c
  75. 7
      drivers/net/dm9000.c
  76. 1
      drivers/net/e1000e/defines.h
  77. 5
      drivers/net/e1000e/e1000.h
  78. 92
      drivers/net/e1000e/ethtool.c
  79. 5
      drivers/net/e1000e/hw.h
  80. 48
      drivers/net/e1000e/ich8lan.c
  81. 4
      drivers/net/e1000e/lib.c
  82. 129
      drivers/net/e1000e/netdev.c
  83. 8
      drivers/net/e1000e/phy.c
  84. 2
      drivers/net/enic/Makefile
  85. 11
      drivers/net/enic/enic.h
  86. 221
      drivers/net/enic/enic_dev.c
  87. 41
      drivers/net/enic/enic_dev.h
  88. 326
      drivers/net/enic/enic_main.c
  89. 26
      drivers/net/enic/vnic_dev.c
  90. 8
      drivers/net/enic/vnic_dev.h
  91. 38
      drivers/net/enic/vnic_devcmd.h
  92. 5
      drivers/net/enic/vnic_rq.h
  93. 10
      drivers/net/eql.c
  94. 650
      drivers/net/fec.c
  95. 8
      drivers/net/forcedeth.c
  96. 1198
      drivers/net/ftmac100.c
  97. 180
      drivers/net/ftmac100.h
  98. 5
      drivers/net/hamradio/bpqether.c
  99. 296
      drivers/net/igb/e1000_82575.c
  100. 1
      drivers/net/igb/e1000_82575.h

26
Documentation/feature-removal-schedule.txt

@ -35,6 +35,17 @@ Who: Luis R. Rodriguez <lrodriguez@atheros.com>
---------------------------
What: AR9170USB
When: 2.6.40
Why: This driver is deprecated and the firmware is no longer
maintained. The replacement driver "carl9170" has been
around for a while, so the devices are still supported.
Who: Christian Lamparter <chunkeey@googlemail.com>
---------------------------
What: IRQF_SAMPLE_RANDOM
Check: IRQF_SAMPLE_RANDOM
When: July 2009
@ -604,6 +615,13 @@ Who: Jean Delvare <khali@linux-fr.org>
----------------------------
What: xt_connlimit rev 0
When: 2012
Who: Jan Engelhardt <jengelh@medozas.de>
Files: net/netfilter/xt_connlimit.c
----------------------------
What: noswapaccount kernel command line parameter
When: 2.6.40
Why: The original implementation of memsw feature enabled by
@ -619,3 +637,11 @@ Why: The original implementation of memsw feature enabled by
Who: Michal Hocko <mhocko@suse.cz>
----------------------------
What: ipt_addrtype match include file
When: 2012
Why: superseded by xt_addrtype
Who: Florian Westphal <fw@strlen.de>
Files: include/linux/netfilter_ipv4/ipt_addrtype.h
----------------------------

16
Documentation/networking/batman-adv.txt

@ -1,4 +1,4 @@
[state: 21-11-2010]
[state: 27-01-2011]
BATMAN-ADV
----------
@ -67,15 +67,16 @@ All mesh wide settings can be found in batman's own interface
folder:
# ls /sys/class/net/bat0/mesh/
# aggregated_ogms bonding fragmentation orig_interval
# vis_mode
# aggregated_ogms gw_bandwidth hop_penalty
# bonding gw_mode orig_interval
# fragmentation gw_sel_class vis_mode
There is a special folder for debugging informations:
# ls /sys/kernel/debug/batman_adv/bat0/
# originators socket transtable_global transtable_local
# vis_data
# gateways socket transtable_global vis_data
# originators softif_neigh transtable_local
Some of the files contain all sort of status information regard-
@ -230,9 +231,8 @@ CONTACT
Please send us comments, experiences, questions, anything :)
IRC: #batman on irc.freenode.org
Mailing-list: b.a.t.m.a.n@b.a.t.m.a.n@lists.open-mesh.org
(optional subscription at
https://lists.open-mesh.org/mm/listinfo/b.a.t.m.a.n)
Mailing-list: b.a.t.m.a.n@open-mesh.org (optional subscription
at https://lists.open-mesh.org/mm/listinfo/b.a.t.m.a.n)
You can also contact the Authors:

26
Documentation/networking/bonding.txt

@ -2558,18 +2558,15 @@ enslaved.
16. Resources and Links
=======================
The latest version of the bonding driver can be found in the latest
The latest version of the bonding driver can be found in the latest
version of the linux kernel, found on http://kernel.org
The latest version of this document can be found in either the latest
kernel source (named Documentation/networking/bonding.txt), or on the
bonding sourceforge site:
The latest version of this document can be found in the latest kernel
source (named Documentation/networking/bonding.txt).
http://www.sourceforge.net/projects/bonding
Discussions regarding the bonding driver take place primarily on the
bonding-devel mailing list, hosted at sourceforge.net. If you have
questions or problems, post them to the list. The list address is:
Discussions regarding the usage of the bonding driver take place on the
bonding-devel mailing list, hosted at sourceforge.net. If you have questions or
problems, post them to the list. The list address is:
bonding-devel@lists.sourceforge.net
@ -2578,6 +2575,17 @@ be found at:
https://lists.sourceforge.net/lists/listinfo/bonding-devel
Discussions regarding the developpement of the bonding driver take place
on the main Linux network mailing list, hosted at vger.kernel.org. The list
address is:
netdev@vger.kernel.org
The administrative interface (to subscribe or unsubscribe) can
be found at:
http://vger.kernel.org/vger-lists.html#netdev
Donald Becker's Ethernet Drivers and diag programs may be found at :
- http://web.archive.org/web/*/http://www.scyld.com/network/

11
Documentation/networking/ip-sysctl.txt

@ -280,6 +280,17 @@ tcp_max_orphans - INTEGER
more aggressively. Let me to remind again: each orphan eats
up to ~64K of unswappable memory.
tcp_max_ssthresh - INTEGER
Limited Slow-Start for TCP with large congestion windows (cwnd) defined in
RFC3742. Limited slow-start is a mechanism to limit growth of the cwnd
on the region where cwnd is larger than tcp_max_ssthresh. TCP increases cwnd
by at most tcp_max_ssthresh segments, and by at least tcp_max_ssthresh/2
segments per RTT when the cwnd is above tcp_max_ssthresh.
If TCP connection increased cwnd to thousands (or tens of thousands) segments,
and thousands of packets were being dropped during slow-start, you can set
tcp_max_ssthresh to improve performance for new TCP connection.
Default: 0 (off)
tcp_max_syn_backlog - INTEGER
Maximal number of remembered connection requests, which are
still did not receive an acknowledgment from connecting client.

67
Documentation/networking/phonet.txt

@ -154,9 +154,28 @@ connections, one per accept()'d socket.
write(cfd, msg, msglen);
}
Connections are established between two endpoints by a "third party"
application. This means that both endpoints are passive; so connect()
is not possible.
Connections are traditionally established between two endpoints by a
"third party" application. This means that both endpoints are passive.
As of Linux kernel version 2.6.39, it is also possible to connect
two endpoints directly, using connect() on the active side. This is
intended to support the newer Nokia Wireless Modem API, as found in
e.g. the Nokia Slim Modem in the ST-Ericsson U8500 platform:
struct sockaddr_spn spn;
int fd;
fd = socket(PF_PHONET, SOCK_SEQPACKET, PN_PROTO_PIPE);
memset(&spn, 0, sizeof(spn));
spn.spn_family = AF_PHONET;
spn.spn_obj = ...;
spn.spn_dev = ...;
spn.spn_resource = 0xD9;
connect(fd, (struct sockaddr *)&spn, sizeof(spn));
/* normal I/O here ... */
close(fd);
WARNING:
When polling a connected pipe socket for writability, there is an
@ -181,45 +200,9 @@ The pipe protocol provides two socket options at the SOL_PNPIPE level:
interface index of the network interface created by PNPIPE_ENCAP,
or zero if encapsulation is off.
Phonet Pipe-controller Implementation
-------------------------------------
Phonet Pipe-controller is enabled by selecting the CONFIG_PHONET_PIPECTRLR Kconfig
option. It is useful when communicating with those Nokia Modems which do not
implement Pipe controller in them e.g. Nokia Slim Modem used in ST-Ericsson
U8500 platform.
The implementation is based on the Data Connection Establishment Sequence
depicted in 'Nokia Wireless Modem API - Wireless_modem_user_guide.pdf'
document.
It allows a phonet sequenced socket (host-pep) to initiate a Pipe connection
between itself and a remote pipe-end point (e.g. modem).
The implementation adds socket options at SOL_PNPIPE level:
PNPIPE_PIPE_HANDLE
It accepts an integer argument for setting value of pipe handle.
PNPIPE_ENABLE accepts one integer value (int). If set to zero, the pipe
is disabled. If the value is non-zero, the pipe is enabled. If the pipe
is not (yet) connected, ENOTCONN is error is returned.
The implementation also adds socket 'connect'. On calling the 'connect', pipe
will be created between the source socket and the destination, and the pipe
state will be set to PIPE_DISABLED.
After a pipe has been created and enabled successfully, the Pipe data can be
exchanged between the host-pep and remote-pep (modem).
User-space would typically follow below sequence with Pipe controller:-
-socket
-bind
-setsockopt for PNPIPE_PIPE_HANDLE
-connect
-setsockopt for PNPIPE_ENCAP_IP
-setsockopt for PNPIPE_ENABLE
PNPIPE_HANDLE is a read-only integer value. It contains the underlying
identifier ("pipe handle") of the pipe. This is only defined for
socket descriptors that are already connected or being connected.
Authors

10
MAINTAINERS

@ -1231,7 +1231,7 @@ ATHEROS AR9170 WIRELESS DRIVER
M: Christian Lamparter <chunkeey@web.de>
L: linux-wireless@vger.kernel.org
W: http://wireless.kernel.org/en/users/Drivers/ar9170
S: Maintained
S: Obsolete
F: drivers/net/wireless/ath/ar9170/
CARL9170 LINUX COMMUNITY WIRELESS DRIVER
@ -1727,6 +1727,7 @@ S: Maintained
F: Documentation/zh_CN/
CISCO VIC ETHERNET NIC DRIVER
M: Christian Benvenuti <benve@cisco.com>
M: Vasanthy Kolluri <vkolluri@cisco.com>
M: Roopa Prabhu <roprabhu@cisco.com>
M: David Wang <dwang2@cisco.com>
@ -5169,6 +5170,7 @@ RALINK RT2X00 WIRELESS LAN DRIVER
P: rt2x00 project
M: Ivo van Doorn <IvDoorn@gmail.com>
M: Gertjan van Wingerde <gwingerde@gmail.com>
M: Helmut Schaa <helmut.schaa@googlemail.com>
L: linux-wireless@vger.kernel.org
L: users@rt2x00.serialmonkey.com (moderated for non-subscribers)
W: http://rt2x00.serialmonkey.com/
@ -6092,13 +6094,11 @@ F: sound/soc/codecs/twl4030*
TIPC NETWORK LAYER
M: Jon Maloy <jon.maloy@ericsson.com>
M: Allan Stephens <allan.stephens@windriver.com>
L: tipc-discussion@lists.sourceforge.net
L: netdev@vger.kernel.org (core kernel code)
L: tipc-discussion@lists.sourceforge.net (user apps, general discussion)
W: http://tipc.sourceforge.net/
W: http://tipc.cslab.ericsson.net/
T: git git://tipc.cslab.ericsson.net/pub/git/tipc.git
S: Maintained
F: include/linux/tipc*.h
F: include/net/tipc/
F: net/tipc/
TILE ARCHITECTURE

10
arch/sh/include/asm/sh_eth.h

@ -1,11 +1,21 @@
#ifndef __ASM_SH_ETH_H__
#define __ASM_SH_ETH_H__
#include <linux/phy.h>
enum {EDMAC_LITTLE_ENDIAN, EDMAC_BIG_ENDIAN};
enum {
SH_ETH_REG_GIGABIT,
SH_ETH_REG_FAST_SH4,
SH_ETH_REG_FAST_SH3_SH2
};
struct sh_eth_plat_data {
int phy;
int edmac_endian;
int register_type;
phy_interface_t phy_interface;
void (*set_mdio_gate)(unsigned long addr);
unsigned char mac_addr[6];
unsigned no_ether_link:1;

2
crypto/Makefile

@ -78,7 +78,7 @@ obj-$(CONFIG_CRYPTO_DEFLATE) += deflate.o
obj-$(CONFIG_CRYPTO_ZLIB) += zlib.o
obj-$(CONFIG_CRYPTO_MICHAEL_MIC) += michael_mic.o
obj-$(CONFIG_CRYPTO_CRC32C) += crc32c.o
obj-$(CONFIG_CRYPTO_AUTHENC) += authenc.o
obj-$(CONFIG_CRYPTO_AUTHENC) += authenc.o authencesn.o
obj-$(CONFIG_CRYPTO_LZO) += lzo.o
obj-$(CONFIG_CRYPTO_RNG2) += rng.o
obj-$(CONFIG_CRYPTO_RNG2) += krng.o

835
crypto/authencesn.c

@ -0,0 +1,835 @@
/*
* authencesn.c - AEAD wrapper for IPsec with extended sequence numbers,
* derived from authenc.c
*
* Copyright (C) 2010 secunet Security Networks AG
* Copyright (C) 2010 Steffen Klassert <steffen.klassert@secunet.com>
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
* Software Foundation; either version 2 of the License, or (at your option)
* any later version.
*
*/
#include <crypto/aead.h>
#include <crypto/internal/hash.h>
#include <crypto/internal/skcipher.h>
#include <crypto/authenc.h>
#include <crypto/scatterwalk.h>
#include <linux/err.h>
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/rtnetlink.h>
#include <linux/slab.h>
#include <linux/spinlock.h>
struct authenc_esn_instance_ctx {
struct crypto_ahash_spawn auth;
struct crypto_skcipher_spawn enc;
};
struct crypto_authenc_esn_ctx {
unsigned int reqoff;
struct crypto_ahash *auth;
struct crypto_ablkcipher *enc;
};
struct authenc_esn_request_ctx {
unsigned int cryptlen;
unsigned int headlen;
unsigned int trailen;
struct scatterlist *sg;
struct scatterlist hsg[2];
struct scatterlist tsg[1];
struct scatterlist cipher[2];
crypto_completion_t complete;
crypto_completion_t update_complete;
crypto_completion_t update_complete2;
char tail[];
};
static void authenc_esn_request_complete(struct aead_request *req, int err)
{
if (err != -EINPROGRESS)
aead_request_complete(req, err);
}
static int crypto_authenc_esn_setkey(struct crypto_aead *authenc_esn, const u8 *key,
unsigned int keylen)
{
unsigned int authkeylen;
unsigned int enckeylen;
struct crypto_authenc_esn_ctx *ctx = crypto_aead_ctx(authenc_esn);
struct crypto_ahash *auth = ctx->auth;
struct crypto_ablkcipher *enc = ctx->enc;
struct rtattr *rta = (void *)key;
struct crypto_authenc_key_param *param;
int err = -EINVAL;
if (!RTA_OK(rta, keylen))
goto badkey;
if (rta->rta_type != CRYPTO_AUTHENC_KEYA_PARAM)
goto badkey;
if (RTA_PAYLOAD(rta) < sizeof(*param))
goto badkey;
param = RTA_DATA(rta);
enckeylen = be32_to_cpu(param->enckeylen);
key += RTA_ALIGN(rta->rta_len);
keylen -= RTA_ALIGN(rta->rta_len);
if (keylen < enckeylen)
goto badkey;
authkeylen = keylen - enckeylen;
crypto_ahash_clear_flags(auth, CRYPTO_TFM_REQ_MASK);
crypto_ahash_set_flags(auth, crypto_aead_get_flags(authenc_esn) &
CRYPTO_TFM_REQ_MASK);
err = crypto_ahash_setkey(auth, key, authkeylen);
crypto_aead_set_flags(authenc_esn, crypto_ahash_get_flags(auth) &
CRYPTO_TFM_RES_MASK);
if (err)
goto out;
crypto_ablkcipher_clear_flags(enc, CRYPTO_TFM_REQ_MASK);
crypto_ablkcipher_set_flags(enc, crypto_aead_get_flags(authenc_esn) &
CRYPTO_TFM_REQ_MASK);
err = crypto_ablkcipher_setkey(enc, key + authkeylen, enckeylen);
crypto_aead_set_flags(authenc_esn, crypto_ablkcipher_get_flags(enc) &
CRYPTO_TFM_RES_MASK);
out:
return err;
badkey:
crypto_aead_set_flags(authenc_esn, CRYPTO_TFM_RES_BAD_KEY_LEN);
goto out;
}
static void authenc_esn_geniv_ahash_update_done(struct crypto_async_request *areq,
int err)
{
struct aead_request *req = areq->data;
struct crypto_aead *authenc_esn = crypto_aead_reqtfm(req);
struct crypto_authenc_esn_ctx *ctx = crypto_aead_ctx(authenc_esn);
struct authenc_esn_request_ctx *areq_ctx = aead_request_ctx(req);
struct ahash_request *ahreq = (void *)(areq_ctx->tail + ctx->reqoff);
if (err)
goto out;
ahash_request_set_crypt(ahreq, areq_ctx->sg, ahreq->result,
areq_ctx->cryptlen);
ahash_request_set_callback(ahreq, aead_request_flags(req) &
CRYPTO_TFM_REQ_MAY_SLEEP,
areq_ctx->update_complete2, req);
err = crypto_ahash_update(ahreq);
if (err)
goto out;
ahash_request_set_crypt(ahreq, areq_ctx->tsg, ahreq->result,
areq_ctx->trailen);
ahash_request_set_callback(ahreq, aead_request_flags(req) &
CRYPTO_TFM_REQ_MAY_SLEEP,
areq_ctx->complete, req);
err = crypto_ahash_finup(ahreq);
if (err)
goto out;
scatterwalk_map_and_copy(ahreq->result, areq_ctx->sg,
areq_ctx->cryptlen,
crypto_aead_authsize(authenc_esn), 1);
out:
authenc_esn_request_complete(req, err);
}
static void authenc_esn_geniv_ahash_update_done2(struct crypto_async_request *areq,
int err)
{
struct aead_request *req = areq->data;
struct crypto_aead *authenc_esn = crypto_aead_reqtfm(req);
struct crypto_authenc_esn_ctx *ctx = crypto_aead_ctx(authenc_esn);
struct authenc_esn_request_ctx *areq_ctx = aead_request_ctx(req);
struct ahash_request *ahreq = (void *)(areq_ctx->tail + ctx->reqoff);
if (err)
goto out;
ahash_request_set_crypt(ahreq, areq_ctx->tsg, ahreq->result,
areq_ctx->trailen);
ahash_request_set_callback(ahreq, aead_request_flags(req) &
CRYPTO_TFM_REQ_MAY_SLEEP,
areq_ctx->complete, req);
err = crypto_ahash_finup(ahreq);
if (err)
goto out;
scatterwalk_map_and_copy(ahreq->result, areq_ctx->sg,
areq_ctx->cryptlen,
crypto_aead_authsize(authenc_esn), 1);
out:
authenc_esn_request_complete(req, err);
}
static void authenc_esn_geniv_ahash_done(struct crypto_async_request *areq,
int err)
{
struct aead_request *req = areq->data;
struct crypto_aead *authenc_esn = crypto_aead_reqtfm(req);
struct crypto_authenc_esn_ctx *ctx = crypto_aead_ctx(authenc_esn);
struct authenc_esn_request_ctx *areq_ctx = aead_request_ctx(req);
struct ahash_request *ahreq = (void *)(areq_ctx->tail + ctx->reqoff);
if (err)
goto out;
scatterwalk_map_and_copy(ahreq->result, areq_ctx->sg,
areq_ctx->cryptlen,
crypto_aead_authsize(authenc_esn), 1);
out:
aead_request_complete(req, err);
}
static void authenc_esn_verify_ahash_update_done(struct crypto_async_request *areq,
int err)
{
u8 *ihash;
unsigned int authsize;
struct ablkcipher_request *abreq;
struct aead_request *req = areq->data;
struct crypto_aead *authenc_esn = crypto_aead_reqtfm(req);
struct crypto_authenc_esn_ctx *ctx = crypto_aead_ctx(authenc_esn);
struct authenc_esn_request_ctx *areq_ctx = aead_request_ctx(req);
struct ahash_request *ahreq = (void *)(areq_ctx->tail + ctx->reqoff);
unsigned int cryptlen = req->cryptlen;
if (err)
goto out;
ahash_request_set_crypt(ahreq, areq_ctx->sg, ahreq->result,
areq_ctx->cryptlen);
ahash_request_set_callback(ahreq,
aead_request_flags(req) &
CRYPTO_TFM_REQ_MAY_SLEEP,
areq_ctx->update_complete2, req);
err = crypto_ahash_update(ahreq);
if (err)
goto out;
ahash_request_set_crypt(ahreq, areq_ctx->tsg, ahreq->result,
areq_ctx->trailen);
ahash_request_set_callback(ahreq, aead_request_flags(req) &
CRYPTO_TFM_REQ_MAY_SLEEP,
areq_ctx->complete, req);
err = crypto_ahash_finup(ahreq);
if (err)
goto out;
authsize = crypto_aead_authsize(authenc_esn);
cryptlen -= authsize;
ihash = ahreq->result + authsize;
scatterwalk_map_and_copy(ihash, areq_ctx->sg, areq_ctx->cryptlen,
authsize, 0);
err = memcmp(ihash, ahreq->result, authsize) ? -EBADMSG : 0;
if (err)
goto out;
abreq = aead_request_ctx(req);
ablkcipher_request_set_tfm(abreq, ctx->enc);
ablkcipher_request_set_callback(abreq, aead_request_flags(req),
req->base.complete, req->base.data);
ablkcipher_request_set_crypt(abreq, req->src, req->dst,
cryptlen, req->iv);
err = crypto_ablkcipher_decrypt(abreq);
out:
authenc_esn_request_complete(req, err);
}
static void authenc_esn_verify_ahash_update_done2(struct crypto_async_request *areq,
int err)
{
u8 *ihash;
unsigned int authsize;
struct ablkcipher_request *abreq;
struct aead_request *req = areq->data;
struct crypto_aead *authenc_esn = crypto_aead_reqtfm(req);
struct crypto_authenc_esn_ctx *ctx = crypto_aead_ctx(authenc_esn);
struct authenc_esn_request_ctx *areq_ctx = aead_request_ctx(req);
struct ahash_request *ahreq = (void *)(areq_ctx->tail + ctx->reqoff);
unsigned int cryptlen = req->cryptlen;
if (err)
goto out;
ahash_request_set_crypt(ahreq, areq_ctx->tsg, ahreq->result,
areq_ctx->trailen);
ahash_request_set_callback(ahreq, aead_request_flags(req) &
CRYPTO_TFM_REQ_MAY_SLEEP,
areq_ctx->complete, req);
err = crypto_ahash_finup(ahreq);
if (err)
goto out;
authsize = crypto_aead_authsize(authenc_esn);
cryptlen -= authsize;
ihash = ahreq->result + authsize;
scatterwalk_map_and_copy(ihash, areq_ctx->sg, areq_ctx->cryptlen,
authsize, 0);
err = memcmp(ihash, ahreq->result, authsize) ? -EBADMSG : 0;
if (err)
goto out;
abreq = aead_request_ctx(req);
ablkcipher_request_set_tfm(abreq, ctx->enc);
ablkcipher_request_set_callback(abreq, aead_request_flags(req),
req->base.complete, req->base.data);
ablkcipher_request_set_crypt(abreq, req->src, req->dst,
cryptlen, req->iv);
err = crypto_ablkcipher_decrypt(abreq);
out:
authenc_esn_request_complete(req, err);
}
static void authenc_esn_verify_ahash_done(struct crypto_async_request *areq,
int err)
{
u8 *ihash;
unsigned int authsize;
struct ablkcipher_request *abreq;
struct aead_request *req = areq->data;
struct crypto_aead *authenc_esn = crypto_aead_reqtfm(req);
struct crypto_authenc_esn_ctx *ctx = crypto_aead_ctx(authenc_esn);
struct authenc_esn_request_ctx *areq_ctx = aead_request_ctx(req);
struct ahash_request *ahreq = (void *)(areq_ctx->tail + ctx->reqoff);
unsigned int cryptlen = req->cryptlen;
if (err)
goto out;
authsize = crypto_aead_authsize(authenc_esn);
cryptlen -= authsize;
ihash = ahreq->result + authsize;
scatterwalk_map_and_copy(ihash, areq_ctx->sg, areq_ctx->cryptlen,
authsize, 0);
err = memcmp(ihash, ahreq->result, authsize) ? -EBADMSG : 0;
if (err)
goto out;
abreq = aead_request_ctx(req);
ablkcipher_request_set_tfm(abreq, ctx->enc);
ablkcipher_request_set_callback(abreq, aead_request_flags(req),
req->base.complete, req->base.data);
ablkcipher_request_set_crypt(abreq, req->src, req->dst,
cryptlen, req->iv);
err = crypto_ablkcipher_decrypt(abreq);
out:
authenc_esn_request_complete(req, err);
}
static u8 *crypto_authenc_esn_ahash(struct aead_request *req,
unsigned int flags)
{
struct crypto_aead *authenc_esn = crypto_aead_reqtfm(req);
struct crypto_authenc_esn_ctx *ctx = crypto_aead_ctx(authenc_esn);
struct crypto_ahash *auth = ctx->auth;
struct authenc_esn_request_ctx *areq_ctx = aead_request_ctx(req);
struct ahash_request *ahreq = (void *)(areq_ctx->tail + ctx->reqoff);
u8 *hash = areq_ctx->tail;
int err;
hash = (u8 *)ALIGN((unsigned long)hash + crypto_ahash_alignmask(auth),
crypto_ahash_alignmask(auth) + 1);
ahash_request_set_tfm(ahreq, auth);
err = crypto_ahash_init(ahreq);
if (err)
return ERR_PTR(err);
ahash_request_set_crypt(ahreq, areq_ctx->hsg, hash, areq_ctx->headlen);
ahash_request_set_callback(ahreq, aead_request_flags(req) & flags,
areq_ctx->update_complete, req);
err = crypto_ahash_update(ahreq);
if (err)
return ERR_PTR(err);
ahash_request_set_crypt(ahreq, areq_ctx->sg, hash, areq_ctx->cryptlen);
ahash_request_set_callback(ahreq, aead_request_flags(req) & flags,
areq_ctx->update_complete2, req);
err = crypto_ahash_update(ahreq);
if (err)
return ERR_PTR(err);
ahash_request_set_crypt(ahreq, areq_ctx->tsg, hash,
areq_ctx->trailen);
ahash_request_set_callback(ahreq, aead_request_flags(req) & flags,
areq_ctx->complete, req);
err = crypto_ahash_finup(ahreq);
if (err)
return ERR_PTR(err);
return hash;
}
static int crypto_authenc_esn_genicv(struct aead_request *req, u8 *iv,
unsigned int flags)
{
struct crypto_aead *authenc_esn = crypto_aead_reqtfm(req);
struct authenc_esn_request_ctx *areq_ctx = aead_request_ctx(req);
struct scatterlist *dst = req->dst;
struct scatterlist *assoc = req->assoc;
struct scatterlist *cipher = areq_ctx->cipher;
struct scatterlist *hsg = areq_ctx->hsg;
struct scatterlist *tsg = areq_ctx->tsg;
struct scatterlist *assoc1;
struct scatterlist *assoc2;
unsigned int ivsize = crypto_aead_ivsize(authenc_esn);
unsigned int cryptlen = req->cryptlen;
struct page *dstp;
u8 *vdst;
u8 *hash;
dstp = sg_page(dst);
vdst = PageHighMem(dstp) ? NULL : page_address(dstp) + dst->offset;
if (ivsize) {
sg_init_table(cipher, 2);
sg_set_buf(cipher, iv, ivsize);
scatterwalk_crypto_chain(cipher, dst, vdst == iv + ivsize, 2);
dst = cipher;
cryptlen += ivsize;
}
if (sg_is_last(assoc))
return -EINVAL;
assoc1 = assoc + 1;
if (sg_is_last(assoc1))
return -EINVAL;
assoc2 = assoc + 2;
if (!sg_is_last(assoc2))
return -EINVAL;
sg_init_table(hsg, 2);
sg_set_page(hsg, sg_page(assoc), assoc->length, assoc->offset);
sg_set_page(hsg + 1, sg_page(assoc2), assoc2->length, assoc2->offset);
sg_init_table(tsg, 1);
sg_set_page(tsg, sg_page(assoc1), assoc1->length, assoc1->offset);
areq_ctx->cryptlen = cryptlen;
areq_ctx->headlen = assoc->length + assoc2->length;
areq_ctx->trailen = assoc1->length;
areq_ctx->sg = dst;
areq_ctx->complete = authenc_esn_geniv_ahash_done;
areq_ctx->update_complete = authenc_esn_geniv_ahash_update_done;
areq_ctx->update_complete2 = authenc_esn_geniv_ahash_update_done2;
hash = crypto_authenc_esn_ahash(req, flags);
if (IS_ERR(hash))
return PTR_ERR(hash);
scatterwalk_map_and_copy(hash, dst, cryptlen,
crypto_aead_authsize(authenc_esn), 1);
return 0;
}
static void crypto_authenc_esn_encrypt_done(struct crypto_async_request *req,
int err)
{
struct aead_request *areq = req->data;
if (!err) {
struct crypto_aead *authenc_esn = crypto_aead_reqtfm(areq);
struct crypto_authenc_esn_ctx *ctx = crypto_aead_ctx(authenc_esn);
struct ablkcipher_request *abreq = aead_request_ctx(areq);
u8 *iv = (u8 *)(abreq + 1) +
crypto_ablkcipher_reqsize(ctx->enc);
err = crypto_authenc_esn_genicv(areq, iv, 0);
}
authenc_esn_request_complete(areq, err);
}
static int crypto_authenc_esn_encrypt(struct aead_request *req)
{
struct crypto_aead *authenc_esn = crypto_aead_reqtfm(req);
struct crypto_authenc_esn_ctx *ctx = crypto_aead_ctx(authenc_esn);
struct authenc_esn_request_ctx *areq_ctx = aead_request_ctx(req);
struct crypto_ablkcipher *enc = ctx->enc;
struct scatterlist *dst = req->dst;
unsigned int cryptlen = req->cryptlen;
struct ablkcipher_request *abreq = (void *)(areq_ctx->tail
+ ctx->reqoff);
u8 *iv = (u8 *)abreq - crypto_ablkcipher_ivsize(enc);
int err;
ablkcipher_request_set_tfm(abreq, enc);
ablkcipher_request_set_callback(abreq, aead_request_flags(req),
crypto_authenc_esn_encrypt_done, req);
ablkcipher_request_set_crypt(abreq, req->src, dst, cryptlen, req->iv);
memcpy(iv, req->iv, crypto_aead_ivsize(authenc_esn));
err = crypto_ablkcipher_encrypt(abreq);
if (err)
return err;
return crypto_authenc_esn_genicv(req, iv, CRYPTO_TFM_REQ_MAY_SLEEP);
}
static void crypto_authenc_esn_givencrypt_done(struct crypto_async_request *req,
int err)
{
struct aead_request *areq = req->data;
if (!err) {
struct skcipher_givcrypt_request *greq = aead_request_ctx(areq);
err = crypto_authenc_esn_genicv(areq, greq->giv, 0);
}
authenc_esn_request_complete(areq, err);
}
static int crypto_authenc_esn_givencrypt(struct aead_givcrypt_request *req)
{
struct crypto_aead *authenc_esn = aead_givcrypt_reqtfm(req);
struct crypto_authenc_esn_ctx *ctx = crypto_aead_ctx(authenc_esn);
struct aead_request *areq = &req->areq;
struct skcipher_givcrypt_request *greq = aead_request_ctx(areq);
u8 *iv = req->giv;
int err;
skcipher_givcrypt_set_tfm(greq, ctx->enc);
skcipher_givcrypt_set_callback(greq, aead_request_flags(areq),
crypto_authenc_esn_givencrypt_done, areq);
skcipher_givcrypt_set_crypt(greq, areq->src, areq->dst, areq->cryptlen,
areq->iv);
skcipher_givcrypt_set_giv(greq, iv, req->seq);
err = crypto_skcipher_givencrypt(greq);
if (err)
return err;
return crypto_authenc_esn_genicv(areq, iv, CRYPTO_TFM_REQ_MAY_SLEEP);
}
static int crypto_authenc_esn_verify(struct aead_request *req)
{
struct crypto_aead *authenc_esn = crypto_aead_reqtfm(req);
struct authenc_esn_request_ctx *areq_ctx = aead_request_ctx(req);
u8 *ohash;
u8 *ihash;
unsigned int authsize;
areq_ctx->complete = authenc_esn_verify_ahash_done;
areq_ctx->update_complete = authenc_esn_verify_ahash_update_done;
ohash = crypto_authenc_esn_ahash(req, CRYPTO_TFM_REQ_MAY_SLEEP);
if (IS_ERR(ohash))
return PTR_ERR(ohash);
authsize = crypto_aead_authsize(authenc_esn);
ihash = ohash + authsize;
scatterwalk_map_and_copy(ihash, areq_ctx->sg, areq_ctx->cryptlen,
authsize, 0);
return memcmp(ihash, ohash, authsize) ? -EBADMSG : 0;
}
static int crypto_authenc_esn_iverify(struct aead_request *req, u8 *iv,
unsigned int cryptlen)
{
struct crypto_aead *authenc_esn = crypto_aead_reqtfm(req);
struct authenc_esn_request_ctx *areq_ctx = aead_request_ctx(req);
struct scatterlist *src = req->src;
struct scatterlist *assoc = req->assoc;
struct scatterlist *cipher = areq_ctx->cipher;
struct scatterlist *hsg = areq_ctx->hsg;
struct scatterlist *tsg = areq_ctx->tsg;
struct scatterlist *assoc1;
struct scatterlist *assoc2;
unsigned int ivsize = crypto_aead_ivsize(authenc_esn);
struct page *srcp;
u8 *vsrc;
srcp = sg_page(src);
vsrc = PageHighMem(srcp) ? NULL : page_address(srcp) + src->offset;
if (ivsize) {
sg_init_table(cipher, 2);
sg_set_buf(cipher, iv, ivsize);
scatterwalk_crypto_chain(cipher, src, vsrc == iv + ivsize, 2);
src = cipher;
cryptlen += ivsize;
}
if (sg_is_last(assoc))
return -EINVAL;
assoc1 = assoc + 1;
if (sg_is_last(assoc1))
return -EINVAL;
assoc2 = assoc + 2;
if (!sg_is_last(assoc2))
return -EINVAL;
sg_init_table(hsg, 2);
sg_set_page(hsg, sg_page(assoc), assoc->length, assoc->offset);
sg_set_page(hsg + 1, sg_page(assoc2), assoc2->length, assoc2->offset);
sg_init_table(tsg, 1);
sg_set_page(tsg, sg_page(assoc1), assoc1->length, assoc1->offset);
areq_ctx->cryptlen = cryptlen;
areq_ctx->headlen = assoc->length + assoc2->length;
areq_ctx->trailen = assoc1->length;
areq_ctx->sg = src;
areq_ctx->complete = authenc_esn_verify_ahash_done;
areq_ctx->update_complete = authenc_esn_verify_ahash_update_done;
areq_ctx->update_complete2 = authenc_esn_verify_ahash_update_done2;
return crypto_authenc_esn_verify(req);
}
static int crypto_authenc_esn_decrypt(struct aead_request *req)
{
struct crypto_aead *authenc_esn = crypto_aead_reqtfm(req);
struct crypto_authenc_esn_ctx *ctx = crypto_aead_ctx(authenc_esn);
struct ablkcipher_request *abreq = aead_request_ctx(req);
unsigned int cryptlen = req->cryptlen;
unsigned int authsize = crypto_aead_authsize(authenc_esn);
u8 *iv = req->iv;
int err;
if (cryptlen < authsize)
return -EINVAL;
cryptlen -= authsize;
err = crypto_authenc_esn_iverify(req, iv, cryptlen);
if (err)
return err;
ablkcipher_request_set_tfm(abreq, ctx->enc);
ablkcipher_request_set_callback(abreq, aead_request_flags(req),
req->base.complete, req->base.data);
ablkcipher_request_set_crypt(abreq, req->src, req->dst, cryptlen, iv);
return crypto_ablkcipher_decrypt(abreq);
}
static int crypto_authenc_esn_init_tfm(struct crypto_tfm *tfm)
{
struct crypto_instance *inst = crypto_tfm_alg_instance(tfm);
struct authenc_esn_instance_ctx *ictx = crypto_instance_ctx(inst);
struct crypto_authenc_esn_ctx *ctx = crypto_tfm_ctx(tfm);
struct crypto_ahash *auth;
struct crypto_ablkcipher *enc;
int err;
auth = crypto_spawn_ahash(&ictx->auth);
if (IS_ERR(auth))
return PTR_ERR(auth);
enc = crypto_spawn_skcipher(&ictx->enc);
err = PTR_ERR(enc);
if (IS_ERR(enc))
goto err_free_ahash;
ctx->auth = auth;
ctx->enc = enc;
ctx->reqoff = ALIGN(2 * crypto_ahash_digestsize(auth) +
crypto_ahash_alignmask(auth),
crypto_ahash_alignmask(auth) + 1) +
crypto_ablkcipher_ivsize(enc);
tfm->crt_aead.reqsize = sizeof(struct authenc_esn_request_ctx) +
ctx->reqoff +
max_t(unsigned int,
crypto_ahash_reqsize(auth) +
sizeof(struct ahash_request),
sizeof(struct skcipher_givcrypt_request) +
crypto_ablkcipher_reqsize(enc));
return 0;
err_free_ahash:
crypto_free_ahash(auth);
return err;
}
static void crypto_authenc_esn_exit_tfm(struct crypto_tfm *tfm)
{
struct crypto_authenc_esn_ctx *ctx = crypto_tfm_ctx(tfm);
crypto_free_ahash(ctx->auth);
crypto_free_ablkcipher(ctx->enc);
}
static struct crypto_instance *crypto_authenc_esn_alloc(struct rtattr **tb)
{
struct crypto_attr_type *algt;
struct crypto_instance *inst;
struct hash_alg_common *auth;
struct crypto_alg *auth_base;
struct crypto_alg *enc;
struct authenc_esn_instance_ctx *ctx;
const char *enc_name;
int err;
algt = crypto_get_attr_type(tb);
err = PTR_ERR(algt);
if (IS_ERR(algt))
return ERR_PTR(err);
if ((algt->type ^ CRYPTO_ALG_TYPE_AEAD) & algt->mask)
return ERR_PTR(-EINVAL);
auth = ahash_attr_alg(tb[1], CRYPTO_ALG_TYPE_HASH,
CRYPTO_ALG_TYPE_AHASH_MASK);
if (IS_ERR(auth))
return ERR_CAST(auth);
auth_base = &auth->base;
enc_name = crypto_attr_alg_name(tb[2]);
err = PTR_ERR(enc_name);
if (IS_ERR(enc_name))
goto out_put_auth;
inst = kzalloc(sizeof(*inst) + sizeof(*ctx), GFP_KERNEL);
err = -ENOMEM;
if (!inst)
goto out_put_auth;
ctx = crypto_instance_ctx(inst);
err = crypto_init_ahash_spawn(&ctx->auth, auth, inst);
if (err)
goto err_free_inst;
crypto_set_skcipher_spawn(&ctx->enc, inst);
err = crypto_grab_skcipher(&ctx->enc, enc_name, 0,
crypto_requires_sync(algt->type,
algt->mask));
if (err)
goto err_drop_auth;
enc = crypto_skcipher_spawn_alg(&ctx->enc);
err = -ENAMETOOLONG;
if (snprintf(inst->alg.cra_name, CRYPTO_MAX_ALG_NAME,
"authencesn(%s,%s)", auth_base->cra_name, enc->cra_name) >=
CRYPTO_MAX_ALG_NAME)
goto err_drop_enc;
if (snprintf(inst->alg.cra_driver_name, CRYPTO_MAX_ALG_NAME,
"authencesn(%s,%s)", auth_base->cra_driver_name,
enc->cra_driver_name) >= CRYPTO_MAX_ALG_NAME)
goto err_drop_enc;
inst->alg.cra_flags = CRYPTO_ALG_TYPE_AEAD;
inst->alg.cra_flags |= enc->cra_flags & CRYPTO_ALG_ASYNC;
inst->alg.cra_priority = enc->cra_priority *
10 + auth_base->cra_priority;
inst->alg.cra_blocksize = enc->cra_blocksize;
inst->alg.cra_alignmask = auth_base->cra_alignmask | enc->cra_alignmask;
inst->alg.cra_type = &crypto_aead_type;
inst->alg.cra_aead.ivsize = enc->cra_ablkcipher.ivsize;
inst->alg.cra_aead.maxauthsize = auth->digestsize;
inst->alg.cra_ctxsize = sizeof(struct crypto_authenc_esn_ctx);
inst->alg.cra_init = crypto_authenc_esn_init_tfm;
inst->alg.cra_exit = crypto_authenc_esn_exit_tfm;
inst->alg.cra_aead.setkey = crypto_authenc_esn_setkey;
inst->alg.cra_aead.encrypt = crypto_authenc_esn_encrypt;
inst->alg.cra_aead.decrypt = crypto_authenc_esn_decrypt;
inst->alg.cra_aead.givencrypt = crypto_authenc_esn_givencrypt;
out:
crypto_mod_put(auth_base);
return inst;
err_drop_enc:
crypto_drop_skcipher(&ctx->enc);
err_drop_auth:
crypto_drop_ahash(&ctx->auth);
err_free_inst:
kfree(inst);
out_put_auth:
inst = ERR_PTR(err);
goto out;
}
static void crypto_authenc_esn_free(struct crypto_instance *inst)
{
struct authenc_esn_instance_ctx *ctx = crypto_instance_ctx(inst);
crypto_drop_skcipher(&ctx->enc);
crypto_drop_ahash(&ctx->auth);
kfree(inst);
}
static struct crypto_template crypto_authenc_esn_tmpl = {
.name = "authencesn",
.alloc = crypto_authenc_esn_alloc,
.free = crypto_authenc_esn_free,
.module = THIS_MODULE,
};
static int __init crypto_authenc_esn_module_init(void)
{
return crypto_register_template(&crypto_authenc_esn_tmpl);
}
static void __exit crypto_authenc_esn_module_exit(void)
{
crypto_unregister_template(&crypto_authenc_esn_tmpl);
}
module_init(crypto_authenc_esn_module_init);
module_exit(crypto_authenc_esn_module_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Steffen Klassert <steffen.klassert@secunet.com>");
MODULE_DESCRIPTION("AEAD wrapper for IPsec with extended sequence numbers");

2
drivers/block/drbd/drbd_nl.c

@ -2177,7 +2177,7 @@ static void drbd_connector_callback(struct cn_msg *req, struct netlink_skb_parms
return;
}
if (!cap_raised(nsp->eff_cap, CAP_SYS_ADMIN)) {
if (!cap_raised(current_cap(), CAP_SYS_ADMIN)) {
retcode = ERR_PERM;
goto fail;
}

287
drivers/bluetooth/ath3k.c

@ -31,6 +31,30 @@
#define VERSION "1.0"
#define ATH3K_DNLOAD 0x01
#define ATH3K_GETSTATE 0x05
#define ATH3K_SET_NORMAL_MODE 0x07
#define ATH3K_GETVERSION 0x09
#define USB_REG_SWITCH_VID_PID 0x0a
#define ATH3K_MODE_MASK 0x3F
#define ATH3K_NORMAL_MODE 0x0E
#define ATH3K_PATCH_UPDATE 0x80
#define ATH3K_SYSCFG_UPDATE 0x40
#define ATH3K_XTAL_FREQ_26M 0x00
#define ATH3K_XTAL_FREQ_40M 0x01
#define ATH3K_XTAL_FREQ_19P2 0x02
#define ATH3K_NAME_LEN 0xFF
struct ath3k_version {
unsigned int rom_version;
unsigned int build_version;
unsigned int ram_version;
unsigned char ref_clock;
unsigned char reserved[0x07];
};
static struct usb_device_id ath3k_table[] = {
/* Atheros AR3011 */
@ -42,15 +66,31 @@ static struct usb_device_id ath3k_table[] = {
/* Atheros AR9285 Malbec with sflash firmware */
{ USB_DEVICE(0x03F0, 0x311D) },
/* Atheros AR3012 with sflash firmware*/
{ USB_DEVICE(0x0CF3, 0x3004) },
/* Atheros AR5BBU12 with sflash firmware */
{ USB_DEVICE(0x0489, 0xE02C) },
{ } /* Terminating entry */
};
MODULE_DEVICE_TABLE(usb, ath3k_table);
#define BTUSB_ATH3012 0x80
/* This table is to load patch and sysconfig files
* for AR3012 */
static struct usb_device_id ath3k_blist_tbl[] = {
/* Atheros AR3012 with sflash firmware*/
{ USB_DEVICE(0x0cf3, 0x3004), .driver_info = BTUSB_ATH3012 },
{ } /* Terminating entry */
};
#define USB_REQ_DFU_DNLOAD 1
#define BULK_SIZE 4096
#define FW_HDR_SIZE 20
static int ath3k_load_firmware(struct usb_device *udev,
const struct firmware *firmware)
@ -106,28 +146,265 @@ error:
return err;
}
static int ath3k_get_state(struct usb_device *udev, unsigned char *state)
{
int pipe = 0;
pipe = usb_rcvctrlpipe(udev, 0);
return usb_control_msg(udev, pipe, ATH3K_GETSTATE,
USB_TYPE_VENDOR | USB_DIR_IN, 0, 0,
state, 0x01, USB_CTRL_SET_TIMEOUT);
}
static int ath3k_get_version(struct usb_device *udev,
struct ath3k_version *version)
{
int pipe = 0;
pipe = usb_rcvctrlpipe(udev, 0);
return usb_control_msg(udev, pipe, ATH3K_GETVERSION,
USB_TYPE_VENDOR | USB_DIR_IN, 0, 0, version,
sizeof(struct ath3k_version),
USB_CTRL_SET_TIMEOUT);
}
static int ath3k_load_fwfile(struct usb_device *udev,
const struct firmware *firmware)
{
u8 *send_buf;
int err, pipe, len, size, count, sent = 0;
int ret;
count = firmware->size;
send_buf = kmalloc(BULK_SIZE, GFP_ATOMIC);
if (!send_buf) {
BT_ERR("Can't allocate memory chunk for firmware");
return -ENOMEM;
}
size = min_t(uint, count, FW_HDR_SIZE);
memcpy(send_buf, firmware->data, size);
pipe = usb_sndctrlpipe(udev, 0);
ret = usb_control_msg(udev, pipe, ATH3K_DNLOAD,
USB_TYPE_VENDOR, 0, 0, send_buf,
size, USB_CTRL_SET_TIMEOUT);
if (ret < 0) {
BT_ERR("Can't change to loading configuration err");
kfree(send_buf);
return ret;
}
sent += size;
count -= size;
while (count) {
size = min_t(uint, count, BULK_SIZE);
pipe = usb_sndbulkpipe(udev, 0x02);
memcpy(send_buf, firmware->data + sent, size);
err = usb_bulk_msg(udev, pipe, send_buf, size,
&len, 3000);
if (err || (len != size)) {
BT_ERR("Error in firmware loading err = %d,"
"len = %d, size = %d", err, len, size);
kfree(send_buf);
return err;
}
sent += size;
count -= size;
}
kfree(send_buf);
return 0;
}
static int ath3k_switch_pid(struct usb_device *udev)
{
int pipe = 0;
pipe = usb_sndctrlpipe(udev, 0);
return usb_control_msg(udev, pipe, USB_REG_SWITCH_VID_PID,
USB_TYPE_VENDOR, 0, 0,
NULL, 0, USB_CTRL_SET_TIMEOUT);
}
static int ath3k_set_normal_mode(struct usb_device *udev)
{
unsigned char fw_state;
int pipe = 0, ret;
ret = ath3k_get_state(udev, &fw_state);
if (ret < 0) {
BT_ERR("Can't get state to change to normal mode err");
return ret;
}
if ((fw_state & ATH3K_MODE_MASK) == ATH3K_NORMAL_MODE) {
BT_DBG("firmware was already in normal mode");
return 0;
}
pipe = usb_sndctrlpipe(udev, 0);
return usb_control_msg(udev, pipe, ATH3K_SET_NORMAL_MODE,
USB_TYPE_VENDOR, 0, 0,
NULL, 0, USB_CTRL_SET_TIMEOUT);
}
static int ath3k_load_patch(struct usb_device *udev)
{
unsigned char fw_state;
char filename[ATH3K_NAME_LEN] = {0};
const struct firmware *firmware;
struct ath3k_version fw_version, pt_version;
int ret;
ret = ath3k_get_state(udev, &fw_state);
if (ret < 0) {
BT_ERR("Can't get state to change to load ram patch err");
return ret;
}
if (fw_state & ATH3K_PATCH_UPDATE) {
BT_DBG("Patch was already downloaded");
return 0;
}
ret = ath3k_get_version(udev, &fw_version);
if (ret < 0) {
BT_ERR("Can't get version to change to load ram patch err");
return ret;
}
snprintf(filename, ATH3K_NAME_LEN, "ar3k/AthrBT_0x%08x.dfu",
fw_version.rom_version);
ret = request_firmware(&firmware, filename, &udev->dev);
if (ret < 0) {
BT_ERR("Patch file not found %s", filename);
return ret;
}
pt_version.rom_version = *(int *)(firmware->data + firmware->size - 8);
pt_version.build_version = *(int *)
(firmware->data + firmware->size - 4);
if ((pt_version.rom_version != fw_version.rom_version) ||
(pt_version.build_version <= fw_version.build_version)) {
BT_ERR("Patch file version did not match with firmware");
release_firmware(firmware);
return -EINVAL;
}
ret = ath3k_load_fwfile(udev, firmware);
release_firmware(firmware);
return ret;
}
static int ath3k_load_syscfg(struct usb_device *udev)
{
unsigned char fw_state;
char filename[ATH3K_NAME_LEN] = {0};
const struct firmware *firmware;
struct ath3k_version fw_version;
int clk_value, ret;
ret = ath3k_get_state(udev, &fw_state);
if (ret < 0) {
BT_ERR("Can't get state to change to load configration err");
return -EBUSY;
}
ret = ath3k_get_version(udev, &fw_version);
if (ret < 0) {
BT_ERR("Can't get version to change to load ram patch err");
return ret;
}
switch (fw_version.ref_clock) {
case ATH3K_XTAL_FREQ_26M:
clk_value = 26;
break;
case ATH3K_XTAL_FREQ_40M:
clk_value = 40;
break;
case ATH3K_XTAL_FREQ_19P2:
clk_value = 19;
break;
default:
clk_value = 0;
break;
}
snprintf(filename, ATH3K_NAME_LEN, "ar3k/ramps_0x%08x_%d%s",
fw_version.rom_version, clk_value, ".dfu");
ret = request_firmware(&firmware, filename, &udev->dev);
if (ret < 0) {
BT_ERR("Configuration file not found %s", filename);
return ret;
}
ret = ath3k_load_fwfile(udev, firmware);
release_firmware(firmware);
return ret;
}
static int ath3k_probe(struct usb_interface *intf,
const struct usb_device_id *id)
{
const struct firmware *firmware;
struct usb_device *udev = interface_to_usbdev(intf);
int ret;
BT_DBG("intf %p id %p", intf, id);
if (intf->cur_altsetting->desc.bInterfaceNumber != 0)
return -ENODEV;
if (request_firmware(&firmware, "ath3k-1.fw", &udev->dev) < 0) {
return -EIO;
/* match device ID in ath3k blacklist table */
if (!id->driver_info) {
const struct usb_device_id *match;
match = usb_match_id(intf, ath3k_blist_tbl);
if (match)
id = match;
}
if (ath3k_load_firmware(udev, firmware)) {
release_firmware(firmware);
/* load patch and sysconfig files for AR3012 */
if (id->driver_info & BTUSB_ATH3012) {
ret = ath3k_load_patch(udev);
if (ret < 0) {
BT_ERR("Loading patch file failed");
return ret;
}
ret = ath3k_load_syscfg(udev);
if (ret < 0) {
BT_ERR("Loading sysconfig file failed");
return ret;
}
ret = ath3k_set_normal_mode(udev);
if (ret < 0) {
BT_ERR("Set normal mode failed");
return ret;
}
ath3k_switch_pid(udev);
return 0;
}
if (request_firmware(&firmware, "ath3k-1.fw", &udev->dev) < 0) {
BT_ERR("Error loading firmware");
return -EIO;
}
ret = ath3k_load_firmware(udev, firmware);
release_firmware(firmware);
return 0;
return ret;
}
static void ath3k_disconnect(struct usb_interface *intf)

13
drivers/bluetooth/btusb.c

@ -105,6 +105,9 @@ static struct usb_device_id blacklist_table[] = {
/* Atheros AR9285 Malbec with sflash firmware */
{ USB_DEVICE(0x03f0, 0x311d), .driver_info = BTUSB_IGNORE },
/* Atheros 3012 with sflash firmware */
{ USB_DEVICE(0x0cf3, 0x3004), .driver_info = BTUSB_IGNORE },
/* Atheros AR5BBU12 with sflash firmware */
{ USB_DEVICE(0x0489, 0xe02c), .driver_info = BTUSB_IGNORE },
@ -714,15 +717,11 @@ static int btusb_send_frame(struct sk_buff *skb)
pipe