aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorWolfgang Wiedmeyer <wolfgit@wiedmeyer.de>2015-10-24 02:08:33 +0200
committerWolfgang Wiedmeyer <wolfgit@wiedmeyer.de>2015-10-24 02:08:33 +0200
commitf0b9ad5690ed96f95d91ca19fba2fb2894bae6f0 (patch)
treed1b649e6f97ac0f1fc9864a296021c71cf69cd21
parent272e77de798362c31e6452a46a0e7d5b6aaeb550 (diff)
downloadkernel_samsung_smdk4412-f0b9ad5690ed96f95d91ca19fba2fb2894bae6f0.zip
kernel_samsung_smdk4412-f0b9ad5690ed96f95d91ca19fba2fb2894bae6f0.tar.gz
kernel_samsung_smdk4412-f0b9ad5690ed96f95d91ca19fba2fb2894bae6f0.tar.bz2
update network codemigrate_3.2
-rw-r--r--net/Kconfig6
-rw-r--r--net/Makefile11
-rw-r--r--net/TUNABLE50
-rw-r--r--net/batman-adv/Kconfig1
-rw-r--r--net/batman-adv/Makefile2
-rw-r--r--net/batman-adv/aggregation.c280
-rw-r--r--net/batman-adv/aggregation.h43
-rw-r--r--net/batman-adv/bat_debugfs.c11
-rw-r--r--net/batman-adv/bat_sysfs.c104
-rw-r--r--net/batman-adv/bat_sysfs.h2
-rw-r--r--net/batman-adv/bitarray.c18
-rw-r--r--net/batman-adv/bitarray.h10
-rw-r--r--net/batman-adv/gateway_client.c268
-rw-r--r--net/batman-adv/gateway_client.h3
-rw-r--r--net/batman-adv/gateway_common.c25
-rw-r--r--net/batman-adv/hard-interface.c128
-rw-r--r--net/batman-adv/hard-interface.h21
-rw-r--r--net/batman-adv/hash.c7
-rw-r--r--net/batman-adv/hash.h31
-rw-r--r--net/batman-adv/icmp_socket.c4
-rw-r--r--net/batman-adv/main.c35
-rw-r--r--net/batman-adv/main.h91
-rw-r--r--net/batman-adv/originator.c55
-rw-r--r--net/batman-adv/originator.h18
-rw-r--r--net/batman-adv/packet.h149
-rw-r--r--net/batman-adv/ring_buffer.c4
-rw-r--r--net/batman-adv/ring_buffer.h2
-rw-r--r--net/batman-adv/routing.c843
-rw-r--r--net/batman-adv/routing.h22
-rw-r--r--net/batman-adv/send.c340
-rw-r--r--net/batman-adv/send.h19
-rw-r--r--net/batman-adv/soft-interface.c104
-rw-r--r--net/batman-adv/soft-interface.h5
-rw-r--r--net/batman-adv/translation-table.c1752
-rw-r--r--net/batman-adv/translation-table.h48
-rw-r--r--net/batman-adv/types.h79
-rw-r--r--net/batman-adv/unicast.c39
-rw-r--r--net/batman-adv/unicast.h10
-rw-r--r--net/batman-adv/vis.c114
-rw-r--r--net/bluetooth_tizen/Kconfig49
-rw-r--r--net/bluetooth_tizen/Makefile12
-rw-r--r--net/bluetooth_tizen/af_bluetooth.c616
-rw-r--r--net/bluetooth_tizen/bnep/Kconfig24
-rw-r--r--net/bluetooth_tizen/bnep/Makefile7
-rw-r--r--net/bluetooth_tizen/bnep/bnep.h180
-rw-r--r--net/bluetooth_tizen/bnep/core.c747
-rw-r--r--net/bluetooth_tizen/bnep/netdev.c238
-rw-r--r--net/bluetooth_tizen/bnep/sock.c259
-rw-r--r--net/bluetooth_tizen/cmtp/Kconfig11
-rw-r--r--net/bluetooth_tizen/cmtp/Makefile7
-rw-r--r--net/bluetooth_tizen/cmtp/capi.c624
-rw-r--r--net/bluetooth_tizen/cmtp/cmtp.h129
-rw-r--r--net/bluetooth_tizen/cmtp/core.c500
-rw-r--r--net/bluetooth_tizen/cmtp/sock.c253
-rw-r--r--net/bluetooth_tizen/hci_conn.c984
-rw-r--r--net/bluetooth_tizen/hci_core.c2966
-rw-r--r--net/bluetooth_tizen/hci_event.c3604
-rw-r--r--net/bluetooth_tizen/hci_sock.c1102
-rw-r--r--net/bluetooth_tizen/hci_sysfs.c588
-rw-r--r--net/bluetooth_tizen/hidp/Kconfig12
-rw-r--r--net/bluetooth_tizen/hidp/Makefile7
-rw-r--r--net/bluetooth_tizen/hidp/core.c1242
-rw-r--r--net/bluetooth_tizen/hidp/hidp.h191
-rw-r--r--net/bluetooth_tizen/hidp/sock.c305
-rw-r--r--net/bluetooth_tizen/l2cap_core.c4803
-rw-r--r--net/bluetooth_tizen/l2cap_sock.c1156
-rw-r--r--net/bluetooth_tizen/lib.c192
-rw-r--r--net/bluetooth_tizen/mgmt.c3599
-rw-r--r--net/bluetooth_tizen/rfcomm/Kconfig17
-rw-r--r--net/bluetooth_tizen/rfcomm/Makefile8
-rw-r--r--net/bluetooth_tizen/rfcomm/core.c2245
-rw-r--r--net/bluetooth_tizen/rfcomm/sock.c1078
-rw-r--r--net/bluetooth_tizen/rfcomm/tty.c1188
-rw-r--r--net/bluetooth_tizen/sco.c1061
-rw-r--r--net/bluetooth_tizen/smp.c1003
-rw-r--r--net/bridge/br_device.c15
-rw-r--r--net/bridge/br_fdb.c25
-rw-r--r--net/bridge/br_forward.c1
-rw-r--r--net/bridge/br_if.c51
-rw-r--r--net/bridge/br_input.c34
-rw-r--r--net/bridge/br_ioctl.c2
-rw-r--r--net/bridge/br_multicast.c30
-rw-r--r--net/bridge/br_netfilter.c33
-rw-r--r--net/bridge/br_netlink.c23
-rw-r--r--net/bridge/br_notify.c7
-rw-r--r--net/bridge/br_private.h8
-rw-r--r--net/bridge/br_private_stp.h3
-rw-r--r--net/bridge/br_stp.c77
-rw-r--r--net/bridge/br_stp_bpdu.c15
-rw-r--r--net/bridge/br_stp_if.c20
-rw-r--r--net/bridge/br_stp_timer.c1
-rw-r--r--net/bridge/br_sysfs_br.c34
-rw-r--r--net/bridge/netfilter/Kconfig2
-rw-r--r--net/bridge/netfilter/ebt_ulog.c8
-rw-r--r--net/bridge/netfilter/ebtable_broute.c4
-rw-r--r--net/bridge/netfilter/ebtables.c8
-rw-r--r--net/caif/caif_dev.c8
-rw-r--r--net/caif/caif_socket.c14
-rw-r--r--net/caif/cfcnfg.c38
-rw-r--r--net/caif/cfctrl.c23
-rw-r--r--net/caif/cfdbgl.c7
-rw-r--r--net/caif/cfdgml.c7
-rw-r--r--net/caif/cffrml.c18
-rw-r--r--net/caif/cfmuxl.c6
-rw-r--r--net/caif/cfpkt_skbuff.c1
-rw-r--r--net/caif/cfrfml.c7
-rw-r--r--net/caif/cfserl.c7
-rw-r--r--net/caif/cfsrvl.c8
-rw-r--r--net/caif/cfutill.c7
-rw-r--r--net/caif/cfveil.c7
-rw-r--r--net/caif/cfvidl.c7
-rw-r--r--net/caif/chnl_net.c3
-rw-r--r--net/can/Kconfig11
-rw-r--r--net/can/Makefile3
-rw-r--r--net/can/af_can.c16
-rw-r--r--net/can/af_can.h2
-rw-r--r--net/can/bcm.c3
-rw-r--r--net/can/proc.c2
-rw-r--r--net/can/raw.c5
-rw-r--r--net/ceph/Kconfig14
-rw-r--r--net/ceph/auth_x.c256
-rw-r--r--net/ceph/ceph_common.c48
-rw-r--r--net/ceph/crush/mapper.c35
-rw-r--r--net/ceph/crypto.c171
-rw-r--r--net/ceph/messenger.c196
-rw-r--r--net/ceph/mon_client.c95
-rw-r--r--net/ceph/msgpool.c42
-rw-r--r--net/ceph/osd_client.c93
-rw-r--r--net/ceph/osdmap.c86
-rw-r--r--net/ipx/af_ipx.c3
-rw-r--r--net/ipx/ipx_proc.c1
-rw-r--r--net/irda/af_irda.c8
-rw-r--r--net/irda/discovery.c1
-rw-r--r--net/irda/ircomm/ircomm_tty.c6
-rw-r--r--net/irda/ircomm/ircomm_tty_attach.c2
-rw-r--r--net/irda/irda_device.c3
-rw-r--r--net/irda/iriap.c8
-rw-r--r--net/irda/irlan/irlan_client.c10
-rw-r--r--net/irda/irlan/irlan_common.c10
-rw-r--r--net/irda/irlan/irlan_eth.c4
-rw-r--r--net/irda/irlan/irlan_provider.c10
-rw-r--r--net/irda/irqueue.c4
-rw-r--r--net/irda/irsysctl.c6
-rw-r--r--net/irda/irttp.c19
-rw-r--r--net/irda/qos.c8
-rw-r--r--net/iucv/Kconfig14
-rw-r--r--net/iucv/af_iucv.c871
-rw-r--r--net/iucv/iucv.c32
-rw-r--r--net/key/af_key.c67
-rw-r--r--net/l2tp/l2tp_core.c15
-rw-r--r--net/l2tp/l2tp_ip.c26
-rw-r--r--net/l2tp/l2tp_ppp.c26
-rw-r--r--net/lapb/lapb_iface.c59
-rw-r--r--net/lapb/lapb_in.c881
-rw-r--r--net/llc/af_llc.c7
-rw-r--r--net/llc/llc_input.c1
-rw-r--r--net/llc/llc_output.c1
-rw-r--r--net/llc/llc_proc.c1
-rw-r--r--net/llc/sysctl_net_llc.c8
-rw-r--r--net/netfilter/ipvs/ip_vs_app.c14
-rw-r--r--net/netfilter/ipvs/ip_vs_conn.c7
-rw-r--r--net/netfilter/ipvs/ip_vs_core.c139
-rw-r--r--net/netfilter/ipvs/ip_vs_ctl.c251
-rw-r--r--net/netfilter/ipvs/ip_vs_dh.c5
-rw-r--r--net/netfilter/ipvs/ip_vs_est.c13
-rw-r--r--net/netfilter/ipvs/ip_vs_ftp.c67
-rw-r--r--net/netfilter/ipvs/ip_vs_lblc.c9
-rw-r--r--net/netfilter/ipvs/ip_vs_lblcr.c13
-rw-r--r--net/netfilter/ipvs/ip_vs_nfct.c2
-rw-r--r--net/netfilter/ipvs/ip_vs_proto.c9
-rw-r--r--net/netfilter/ipvs/ip_vs_proto_sctp.c14
-rw-r--r--net/netfilter/ipvs/ip_vs_proto_tcp.c6
-rw-r--r--net/netfilter/ipvs/ip_vs_proto_udp.c5
-rw-r--r--net/netfilter/ipvs/ip_vs_sh.c5
-rw-r--r--net/netfilter/ipvs/ip_vs_sync.c24
-rw-r--r--net/netfilter/ipvs/ip_vs_wrr.c5
-rw-r--r--net/netfilter/ipvs/ip_vs_xmit.c4
-rw-r--r--net/rds/bind.c4
-rw-r--r--net/rds/cong.c1
-rw-r--r--net/rds/connection.c7
-rw-r--r--net/rds/ib.c4
-rw-r--r--net/rds/ib.h1
-rw-r--r--net/rds/ib_cm.c12
-rw-r--r--net/rds/ib_rdma.c116
-rw-r--r--net/rds/ib_send.c9
-rw-r--r--net/rds/info.c3
-rw-r--r--net/rds/iw.c4
-rw-r--r--net/rds/iw.h1
-rw-r--r--net/rds/iw_cm.c9
-rw-r--r--net/rds/iw_rdma.c62
-rw-r--r--net/rds/iw_send.c4
-rw-r--r--net/rds/message.c1
-rw-r--r--net/rds/page.c2
-rw-r--r--net/rds/rdma_transport.c1
-rw-r--r--net/rds/rds.h8
-rw-r--r--net/rds/recv.c3
-rw-r--r--net/rds/send.c9
-rw-r--r--net/rds/stats.c1
-rw-r--r--net/rds/sysctl.c4
-rw-r--r--net/rds/tcp.c1
-rw-r--r--net/rds/tcp_stats.c2
-rw-r--r--net/rds/threads.c1
-rw-r--r--net/rds/xlist.h80
-rw-r--r--net/sunrpc/xprtrdma/rpc_rdma.c8
-rw-r--r--net/sunrpc/xprtrdma/svc_rdma_transport.c2
-rw-r--r--net/sunrpc/xprtrdma/transport.c7
-rw-r--r--net/sunrpc/xprtrdma/verbs.c9
-rw-r--r--net/sunrpc/xprtrdma/xprt_rdma.h4
-rw-r--r--net/tipc/bcast.c117
-rw-r--r--net/tipc/bcast.h1
-rw-r--r--net/tipc/bearer.c9
-rw-r--r--net/tipc/bearer.h6
-rw-r--r--net/tipc/config.h1
-rw-r--r--net/tipc/core.c2
-rw-r--r--net/tipc/core.h8
-rw-r--r--net/tipc/discover.c6
-rw-r--r--net/tipc/eth_media.c34
-rw-r--r--net/tipc/link.c117
-rw-r--r--net/tipc/link.h1
-rw-r--r--net/tipc/msg.c6
-rw-r--r--net/tipc/msg.h34
-rw-r--r--net/tipc/name_distr.c41
-rw-r--r--net/tipc/name_table.c289
-rw-r--r--net/tipc/name_table.h14
-rw-r--r--net/tipc/net.c11
-rw-r--r--net/tipc/node.c45
-rw-r--r--net/tipc/node.h10
-rw-r--r--net/tipc/port.c284
-rw-r--r--net/tipc/socket.c63
-rw-r--r--net/tipc/subscr.c3
-rw-r--r--net/tipc/subscr.h6
-rw-r--r--net/wanrouter/wanproc.c2
-rw-r--r--net/wimax/op-msg.c1
-rw-r--r--net/wimax/op-reset.c1
-rw-r--r--net/wimax/op-rfkill.c1
-rw-r--r--net/wimax/stack.c1
-rwxr-xr-xnet/wireless_ath/Makefile23
-rwxr-xr-xnet/wireless_ath/Makefile.bk18
-rwxr-xr-xnet/wireless_ath/chan.c135
-rwxr-xr-xnet/wireless_ath/core.c1110
-rwxr-xr-xnet/wireless_ath/core.h468
-rwxr-xr-xnet/wireless_ath/db.txt697
-rwxr-xr-xnet/wireless_ath/debugfs.c121
-rwxr-xr-xnet/wireless_ath/debugfs.h11
-rwxr-xr-xnet/wireless_ath/ethtool.c78
-rwxr-xr-xnet/wireless_ath/ethtool.h6
-rwxr-xr-xnet/wireless_ath/genregdb.awk119
-rwxr-xr-xnet/wireless_ath/ibss.c527
-rwxr-xr-xnet/wireless_ath/lib80211.c289
-rwxr-xr-xnet/wireless_ath/lib80211_crypt_ccmp.c491
-rwxr-xr-xnet/wireless_ath/lib80211_crypt_tkip.c780
-rwxr-xr-xnet/wireless_ath/lib80211_crypt_wep.c290
-rwxr-xr-xnet/wireless_ath/mesh.c165
-rwxr-xr-xnet/wireless_ath/mlme.c1140
-rwxr-xr-xnet/wireless_ath/nl80211.c8092
-rwxr-xr-xnet/wireless_ath/nl80211.h125
-rwxr-xr-xnet/wireless_ath/radiotap.c358
-rwxr-xr-xnet/wireless_ath/reg.c2307
-rwxr-xr-xnet/wireless_ath/reg.h87
-rwxr-xr-xnet/wireless_ath/regdb.h7
-rwxr-xr-xnet/wireless_ath/scan.c1381
-rwxr-xr-xnet/wireless_ath/sme.c1041
-rwxr-xr-xnet/wireless_ath/sysfs.c157
-rwxr-xr-xnet/wireless_ath/sysfs.h9
-rwxr-xr-xnet/wireless_ath/util.c1219
-rwxr-xr-xnet/wireless_ath/wext-compat.c1531
-rwxr-xr-xnet/wireless_ath/wext-compat.h57
-rwxr-xr-xnet/wireless_ath/wext-core.c1123
-rwxr-xr-xnet/wireless_ath/wext-priv.c249
-rwxr-xr-xnet/wireless_ath/wext-proc.c159
-rwxr-xr-xnet/wireless_ath/wext-sme.c408
-rwxr-xr-xnet/wireless_ath/wext-spy.c232
272 files changed, 6129 insertions, 60487 deletions
diff --git a/net/Kconfig b/net/Kconfig
index b74076a..c0a7305 100644
--- a/net/Kconfig
+++ b/net/Kconfig
@@ -231,7 +231,7 @@ source "net/dns_resolver/Kconfig"
source "net/batman-adv/Kconfig"
config RPS
- boolean "RPS"
+ boolean
depends on SMP && SYSFS && USE_GENERIC_SMP_HELPERS
default y
@@ -264,7 +264,7 @@ menu "Network testing"
config NET_PKTGEN
tristate "Packet Generator (USE WITH CAUTION)"
- depends on PROC_FS
+ depends on INET && PROC_FS
---help---
This module will inject preconfigured packets, at a configurable
rate, out of a given interface. It is used for network interface
@@ -314,7 +314,6 @@ source "net/can/Kconfig"
source "net/irda/Kconfig"
source "net/bluetooth/Kconfig"
source "net/bluetooth_mgmt/Kconfig"
-source "net/bluetooth_tizen/Kconfig"
source "net/rxrpc/Kconfig"
config FIB_RULES
@@ -338,6 +337,7 @@ source "net/rfkill/Kconfig"
source "net/9p/Kconfig"
source "net/caif/Kconfig"
source "net/ceph/Kconfig"
+source "net/nfc/Kconfig"
endif # if NET
diff --git a/net/Makefile b/net/Makefile
index 11fee99..da0fdf5 100644
--- a/net/Makefile
+++ b/net/Makefile
@@ -9,7 +9,7 @@ obj-y := nonet.o
obj-$(CONFIG_NET) := socket.o core/
-tmp-$(CONFIG_COMPAT) := compat.o
+tmp-$(CONFIG_COMPAT) := compat.o
obj-$(CONFIG_NET) += $(tmp-y)
# LLC has to be linked before the files in net/802/
@@ -37,12 +37,8 @@ obj-$(CONFIG_IRDA) += irda/
ifeq ($(CONFIG_BT_MGMT),y)
obj-$(CONFIG_BT) += bluetooth_mgmt/
else
-ifeq ($(CONFIG_BT_TIZEN),y)
-obj-$(CONFIG_BT) += bluetooth_tizen/
-else
obj-$(CONFIG_BT) += bluetooth/
endif
-endif
obj-$(CONFIG_SUNRPC) += sunrpc/
obj-$(CONFIG_AF_RXRPC) += rxrpc/
obj-$(CONFIG_ATM) += atm/
@@ -56,11 +52,7 @@ endif
obj-$(CONFIG_IP_DCCP) += dccp/
obj-$(CONFIG_IP_SCTP) += sctp/
obj-$(CONFIG_RDS) += rds/
-ifeq ($(CONFIG_MACH_PX),y)
-obj-$(CONFIG_WIRELESS) += wireless_ath/
-else
obj-$(CONFIG_WIRELESS) += wireless/
-endif
obj-$(CONFIG_MAC80211) += mac80211/
obj-$(CONFIG_TIPC) += tipc/
obj-$(CONFIG_NETLABEL) += netlabel/
@@ -81,3 +73,4 @@ obj-$(CONFIG_DNS_RESOLVER) += dns_resolver/
obj-$(CONFIG_CEPH_LIB) += ceph/
obj-$(CONFIG_BATMAN_ADV) += batman-adv/
obj-$(CONFIG_NET_ACTIVITY_STATS) += activity_stats.o
+obj-$(CONFIG_NFC) += nfc/
diff --git a/net/TUNABLE b/net/TUNABLE
deleted file mode 100644
index 9913211..0000000
--- a/net/TUNABLE
+++ /dev/null
@@ -1,50 +0,0 @@
-The following parameters should be tunable at compile time. Some of them
-exist as sysctls too.
-
-This is far from complete
-
-Item Description
-----------------------------------------------------------------------------
-MAX_LINKS Maximum number of netlink minor devices. (1-32)
-RIF_TABLE_SIZE Token ring RIF cache size (tunable)
-AARP_HASH_SIZE Size of Appletalk hash table (tunable)
-AX25_DEF_T1 AX.25 parameters. These are all tunable via
-AX25_DEF_T2 SIOCAX25SETPARMS
-AX25_DEF_T3 T1-T3,N2 have the meanings in the specification
-AX25_DEF_N2
-AX25_DEF_AXDEFMODE 8 = normal 128 is PE1CHL extended
-AX25_DEF_IPDEFMODE 'D' - datagram 'V' - virtual connection
-AX25_DEF_BACKOFF 'E'xponential 'L'inear
-AX25_DEF_NETROM Allow netrom 1=Y
-AX25_DF_TEXT Allow PID=Text 1=Y
-AX25_DEF_WINDOW Window for normal mode
-AX25_DEF_EWINDOW Window for PE1CHL mode
-AX25_DEF_DIGI 1 for inband 2 for cross band 3 for both
-AX25_DEF_CONMODE Allow connected modes 1=Yes
-AX25_ROUTE_MAX AX.25 route cache size - no currently tunable
-Unnamed (16) Number of protocol hash slots (tunable)
-DEV_NUMBUFFS Number of priority levels (not easily tunable)
-Unnamed (300) Maximum packet backlog queue (tunable)
-MAX_IOVEC Maximum number of iovecs in a message (tunable)
-MIN_WINDOW Offered minimum window (tunable)
-MAX_WINDOW Offered maximum window (tunable)
-MAX_HEADER Largest physical header (tunable)
-MAX_ADDR_LEN Largest physical address (tunable)
-SOCK_ARRAY_SIZE IP socket array hash size (tunable)
-IP_MAX_MEMBERSHIPS Largest number of groups per socket (BSD style) (tunable)
-16 Hard coded constant for amount of room allowed for
- cache align and faster forwarding (tunable)
-IP_FRAG_TIME Time we hold a fragment for. (tunable)
-PORT_MASQ_BEGIN First port reserved for masquerade (tunable)
-PORT_MASQ_END Last port used for masquerade (tunable)
-MASQUERADE_EXPIRE_TCP_FIN Time we keep a masquerade for after a FIN
-MASQUERADE_EXPIRE_UDP Time we keep a UDP masquerade for (tunable)
-MAXVIFS Maximum mrouted vifs (1-32)
-MFC_LINES Lines in the multicast router cache (tunable)
-
-NetROM parameters are tunable via an ioctl passing a struct
-
-4000 Size a Unix domain socket malloc falls back to
- (tunable) should be 8K - a bit for 8K machines like
- the ALPHA
-
diff --git a/net/batman-adv/Kconfig b/net/batman-adv/Kconfig
index 6c051ad..2b68d06 100644
--- a/net/batman-adv/Kconfig
+++ b/net/batman-adv/Kconfig
@@ -5,6 +5,7 @@
config BATMAN_ADV
tristate "B.A.T.M.A.N. Advanced Meshing Protocol"
depends on NET
+ select CRC16
default n
---help---
diff --git a/net/batman-adv/Makefile b/net/batman-adv/Makefile
index 2de93d0..ce68611 100644
--- a/net/batman-adv/Makefile
+++ b/net/batman-adv/Makefile
@@ -19,8 +19,8 @@
#
obj-$(CONFIG_BATMAN_ADV) += batman-adv.o
-batman-adv-y += aggregation.o
batman-adv-y += bat_debugfs.o
+batman-adv-y += bat_iv_ogm.o
batman-adv-y += bat_sysfs.o
batman-adv-y += bitarray.o
batman-adv-y += gateway_client.o
diff --git a/net/batman-adv/aggregation.c b/net/batman-adv/aggregation.c
deleted file mode 100644
index a8c3203..0000000
--- a/net/batman-adv/aggregation.c
+++ /dev/null
@@ -1,280 +0,0 @@
-/*
- * Copyright (C) 2007-2011 B.A.T.M.A.N. contributors:
- *
- * Marek Lindner, Simon Wunderlich
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of version 2 of the GNU General Public
- * License as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
- * 02110-1301, USA
- *
- */
-
-#include "main.h"
-#include "aggregation.h"
-#include "send.h"
-#include "routing.h"
-#include "hard-interface.h"
-
-/* calculate the size of the tt information for a given packet */
-static int tt_len(struct batman_packet *batman_packet)
-{
- return batman_packet->num_tt * ETH_ALEN;
-}
-
-/* return true if new_packet can be aggregated with forw_packet */
-static bool can_aggregate_with(struct batman_packet *new_batman_packet,
- int packet_len,
- unsigned long send_time,
- bool directlink,
- struct hard_iface *if_incoming,
- struct forw_packet *forw_packet)
-{
- struct batman_packet *batman_packet =
- (struct batman_packet *)forw_packet->skb->data;
- int aggregated_bytes = forw_packet->packet_len + packet_len;
-
- /**
- * we can aggregate the current packet to this aggregated packet
- * if:
- *
- * - the send time is within our MAX_AGGREGATION_MS time
- * - the resulting packet wont be bigger than
- * MAX_AGGREGATION_BYTES
- */
-
- if (time_before(send_time, forw_packet->send_time) &&
- time_after_eq(send_time + msecs_to_jiffies(MAX_AGGREGATION_MS),
- forw_packet->send_time) &&
- (aggregated_bytes <= MAX_AGGREGATION_BYTES)) {
-
- /**
- * check aggregation compatibility
- * -> direct link packets are broadcasted on
- * their interface only
- * -> aggregate packet if the current packet is
- * a "global" packet as well as the base
- * packet
- */
-
- /* packets without direct link flag and high TTL
- * are flooded through the net */
- if ((!directlink) &&
- (!(batman_packet->flags & DIRECTLINK)) &&
- (batman_packet->ttl != 1) &&
-
- /* own packets originating non-primary
- * interfaces leave only that interface */
- ((!forw_packet->own) ||
- (forw_packet->if_incoming->if_num == 0)))
- return true;
-
- /* if the incoming packet is sent via this one
- * interface only - we still can aggregate */
- if ((directlink) &&
- (new_batman_packet->ttl == 1) &&
- (forw_packet->if_incoming == if_incoming) &&
-
- /* packets from direct neighbors or
- * own secondary interface packets
- * (= secondary interface packets in general) */
- (batman_packet->flags & DIRECTLINK ||
- (forw_packet->own &&
- forw_packet->if_incoming->if_num != 0)))
- return true;
- }
-
- return false;
-}
-
-/* create a new aggregated packet and add this packet to it */
-static void new_aggregated_packet(unsigned char *packet_buff, int packet_len,
- unsigned long send_time, bool direct_link,
- struct hard_iface *if_incoming,
- int own_packet)
-{
- struct bat_priv *bat_priv = netdev_priv(if_incoming->soft_iface);
- struct forw_packet *forw_packet_aggr;
- unsigned char *skb_buff;
-
- if (!atomic_inc_not_zero(&if_incoming->refcount))
- return;
-
- /* own packet should always be scheduled */
- if (!own_packet) {
- if (!atomic_dec_not_zero(&bat_priv->batman_queue_left)) {
- bat_dbg(DBG_BATMAN, bat_priv,
- "batman packet queue full\n");
- goto out;
- }
- }
-
- forw_packet_aggr = kmalloc(sizeof(struct forw_packet), GFP_ATOMIC);
- if (!forw_packet_aggr) {
- if (!own_packet)
- atomic_inc(&bat_priv->batman_queue_left);
- goto out;
- }
-
- if ((atomic_read(&bat_priv->aggregated_ogms)) &&
- (packet_len < MAX_AGGREGATION_BYTES))
- forw_packet_aggr->skb = dev_alloc_skb(MAX_AGGREGATION_BYTES +
- sizeof(struct ethhdr));
- else
- forw_packet_aggr->skb = dev_alloc_skb(packet_len +
- sizeof(struct ethhdr));
-
- if (!forw_packet_aggr->skb) {
- if (!own_packet)
- atomic_inc(&bat_priv->batman_queue_left);
- kfree(forw_packet_aggr);
- goto out;
- }
- skb_reserve(forw_packet_aggr->skb, sizeof(struct ethhdr));
-
- INIT_HLIST_NODE(&forw_packet_aggr->list);
-
- skb_buff = skb_put(forw_packet_aggr->skb, packet_len);
- forw_packet_aggr->packet_len = packet_len;
- memcpy(skb_buff, packet_buff, packet_len);
-
- forw_packet_aggr->own = own_packet;
- forw_packet_aggr->if_incoming = if_incoming;
- forw_packet_aggr->num_packets = 0;
- forw_packet_aggr->direct_link_flags = 0;
- forw_packet_aggr->send_time = send_time;
-
- /* save packet direct link flag status */
- if (direct_link)
- forw_packet_aggr->direct_link_flags |= 1;
-
- /* add new packet to packet list */
- spin_lock_bh(&bat_priv->forw_bat_list_lock);
- hlist_add_head(&forw_packet_aggr->list, &bat_priv->forw_bat_list);
- spin_unlock_bh(&bat_priv->forw_bat_list_lock);
-
- /* start timer for this packet */
- INIT_DELAYED_WORK(&forw_packet_aggr->delayed_work,
- send_outstanding_bat_packet);
- queue_delayed_work(bat_event_workqueue,
- &forw_packet_aggr->delayed_work,
- send_time - jiffies);
-
- return;
-out:
- hardif_free_ref(if_incoming);
-}
-
-/* aggregate a new packet into the existing aggregation */
-static void aggregate(struct forw_packet *forw_packet_aggr,
- unsigned char *packet_buff,
- int packet_len,
- bool direct_link)
-{
- unsigned char *skb_buff;
-
- skb_buff = skb_put(forw_packet_aggr->skb, packet_len);
- memcpy(skb_buff, packet_buff, packet_len);
- forw_packet_aggr->packet_len += packet_len;
- forw_packet_aggr->num_packets++;
-
- /* save packet direct link flag status */
- if (direct_link)
- forw_packet_aggr->direct_link_flags |=
- (1 << forw_packet_aggr->num_packets);
-}
-
-void add_bat_packet_to_list(struct bat_priv *bat_priv,
- unsigned char *packet_buff, int packet_len,
- struct hard_iface *if_incoming, char own_packet,
- unsigned long send_time)
-{
- /**
- * _aggr -> pointer to the packet we want to aggregate with
- * _pos -> pointer to the position in the queue
- */
- struct forw_packet *forw_packet_aggr = NULL, *forw_packet_pos = NULL;
- struct hlist_node *tmp_node;
- struct batman_packet *batman_packet =
- (struct batman_packet *)packet_buff;
- bool direct_link = batman_packet->flags & DIRECTLINK ? 1 : 0;
-
- /* find position for the packet in the forward queue */
- spin_lock_bh(&bat_priv->forw_bat_list_lock);
- /* own packets are not to be aggregated */
- if ((atomic_read(&bat_priv->aggregated_ogms)) && (!own_packet)) {
- hlist_for_each_entry(forw_packet_pos, tmp_node,
- &bat_priv->forw_bat_list, list) {
- if (can_aggregate_with(batman_packet,
- packet_len,
- send_time,
- direct_link,
- if_incoming,
- forw_packet_pos)) {
- forw_packet_aggr = forw_packet_pos;
- break;
- }
- }
- }
-
- /* nothing to aggregate with - either aggregation disabled or no
- * suitable aggregation packet found */
- if (!forw_packet_aggr) {
- /* the following section can run without the lock */
- spin_unlock_bh(&bat_priv->forw_bat_list_lock);
-
- /**
- * if we could not aggregate this packet with one of the others
- * we hold it back for a while, so that it might be aggregated
- * later on
- */
- if ((!own_packet) &&
- (atomic_read(&bat_priv->aggregated_ogms)))
- send_time += msecs_to_jiffies(MAX_AGGREGATION_MS);
-
- new_aggregated_packet(packet_buff, packet_len,
- send_time, direct_link,
- if_incoming, own_packet);
- } else {
- aggregate(forw_packet_aggr,
- packet_buff, packet_len,
- direct_link);
- spin_unlock_bh(&bat_priv->forw_bat_list_lock);
- }
-}
-
-/* unpack the aggregated packets and process them one by one */
-void receive_aggr_bat_packet(struct ethhdr *ethhdr, unsigned char *packet_buff,
- int packet_len, struct hard_iface *if_incoming)
-{
- struct batman_packet *batman_packet;
- int buff_pos = 0;
- unsigned char *tt_buff;
-
- batman_packet = (struct batman_packet *)packet_buff;
-
- do {
- /* network to host order for our 32bit seqno, and the
- orig_interval. */
- batman_packet->seqno = ntohl(batman_packet->seqno);
-
- tt_buff = packet_buff + buff_pos + BAT_PACKET_LEN;
- receive_bat_packet(ethhdr, batman_packet,
- tt_buff, tt_len(batman_packet),
- if_incoming);
-
- buff_pos += BAT_PACKET_LEN + tt_len(batman_packet);
- batman_packet = (struct batman_packet *)
- (packet_buff + buff_pos);
- } while (aggregated_packet(buff_pos, packet_len,
- batman_packet->num_tt));
-}
diff --git a/net/batman-adv/aggregation.h b/net/batman-adv/aggregation.h
deleted file mode 100644
index 7e6d72f..0000000
--- a/net/batman-adv/aggregation.h
+++ /dev/null
@@ -1,43 +0,0 @@
-/*
- * Copyright (C) 2007-2011 B.A.T.M.A.N. contributors:
- *
- * Marek Lindner, Simon Wunderlich
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of version 2 of the GNU General Public
- * License as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
- * 02110-1301, USA
- *
- */
-
-#ifndef _NET_BATMAN_ADV_AGGREGATION_H_
-#define _NET_BATMAN_ADV_AGGREGATION_H_
-
-#include "main.h"
-
-/* is there another aggregated packet here? */
-static inline int aggregated_packet(int buff_pos, int packet_len, int num_tt)
-{
- int next_buff_pos = buff_pos + BAT_PACKET_LEN + (num_tt * ETH_ALEN);
-
- return (next_buff_pos <= packet_len) &&
- (next_buff_pos <= MAX_AGGREGATION_BYTES);
-}
-
-void add_bat_packet_to_list(struct bat_priv *bat_priv,
- unsigned char *packet_buff, int packet_len,
- struct hard_iface *if_incoming, char own_packet,
- unsigned long send_time);
-void receive_aggr_bat_packet(struct ethhdr *ethhdr, unsigned char *packet_buff,
- int packet_len, struct hard_iface *if_incoming);
-
-#endif /* _NET_BATMAN_ADV_AGGREGATION_H_ */
diff --git a/net/batman-adv/bat_debugfs.c b/net/batman-adv/bat_debugfs.c
index abaeec5..d0af9bf 100644
--- a/net/batman-adv/bat_debugfs.c
+++ b/net/batman-adv/bat_debugfs.c
@@ -50,7 +50,8 @@ static void emit_log_char(struct debug_log *debug_log, char c)
debug_log->log_start = debug_log->log_end - log_buff_len;
}
-static int fdebug_log(struct debug_log *debug_log, char *fmt, ...)
+__printf(2, 3)
+static int fdebug_log(struct debug_log *debug_log, const char *fmt, ...)
{
va_list args;
static char debug_log_buf[256];
@@ -74,14 +75,14 @@ static int fdebug_log(struct debug_log *debug_log, char *fmt, ...)
return 0;
}
-int debug_log(struct bat_priv *bat_priv, char *fmt, ...)
+int debug_log(struct bat_priv *bat_priv, const char *fmt, ...)
{
va_list args;
char tmp_log_buf[256];
va_start(args, fmt);
vscnprintf(tmp_log_buf, sizeof(tmp_log_buf), fmt, args);
- fdebug_log(bat_priv->debug_log, "[%10u] %s",
+ fdebug_log(bat_priv->debug_log, "[%10lu] %s",
(jiffies / HZ), tmp_log_buf);
va_end(args);
@@ -114,7 +115,7 @@ static ssize_t log_read(struct file *file, char __user *buf,
!(debug_log->log_end - debug_log->log_start))
return -EAGAIN;
- if ((!buf) || (count < 0))
+ if (!buf)
return -EINVAL;
if (count == 0)
@@ -184,7 +185,7 @@ static int debug_log_setup(struct bat_priv *bat_priv)
if (!bat_priv->debug_dir)
goto err;
- bat_priv->debug_log = kzalloc(sizeof(struct debug_log), GFP_ATOMIC);
+ bat_priv->debug_log = kzalloc(sizeof(*bat_priv->debug_log), GFP_ATOMIC);
if (!bat_priv->debug_log)
goto err;
diff --git a/net/batman-adv/bat_sysfs.c b/net/batman-adv/bat_sysfs.c
index 497a070..b8a7414 100644
--- a/net/batman-adv/bat_sysfs.c
+++ b/net/batman-adv/bat_sysfs.c
@@ -28,9 +28,31 @@
#include "gateway_client.h"
#include "vis.h"
-#define to_dev(obj) container_of(obj, struct device, kobj)
-#define kobj_to_netdev(obj) to_net_dev(to_dev(obj->parent))
-#define kobj_to_batpriv(obj) netdev_priv(kobj_to_netdev(obj))
+static struct net_device *kobj_to_netdev(struct kobject *obj)
+{
+ struct device *dev = container_of(obj->parent, struct device, kobj);
+ return to_net_dev(dev);
+}
+
+static struct bat_priv *kobj_to_batpriv(struct kobject *obj)
+{
+ struct net_device *net_dev = kobj_to_netdev(obj);
+ return netdev_priv(net_dev);
+}
+
+#define UEV_TYPE_VAR "BATTYPE="
+#define UEV_ACTION_VAR "BATACTION="
+#define UEV_DATA_VAR "BATDATA="
+
+static char *uev_action_str[] = {
+ "add",
+ "del",
+ "change"
+};
+
+static char *uev_type_str[] = {
+ "gw"
+};
/* Use this, if you have customized show and store functions */
#define BAT_ATTR(_name, _mode, _show, _store) \
@@ -96,7 +118,7 @@ ssize_t show_##_name(struct kobject *kobj, struct attribute *attr, \
static int store_bool_attr(char *buff, size_t count,
struct net_device *net_dev,
- char *attr_name, atomic_t *attr)
+ const char *attr_name, atomic_t *attr)
{
int enabled = -1;
@@ -138,16 +160,15 @@ static inline ssize_t __store_bool_attr(char *buff, size_t count,
{
int ret;
- ret = store_bool_attr(buff, count, net_dev, (char *)attr->name,
- attr_store);
+ ret = store_bool_attr(buff, count, net_dev, attr->name, attr_store);
if (post_func && ret)
post_func(net_dev);
return ret;
}
-static int store_uint_attr(char *buff, size_t count,
- struct net_device *net_dev, char *attr_name,
+static int store_uint_attr(const char *buff, size_t count,
+ struct net_device *net_dev, const char *attr_name,
unsigned int min, unsigned int max, atomic_t *attr)
{
unsigned long uint_val;
@@ -183,15 +204,15 @@ static int store_uint_attr(char *buff, size_t count,
return count;
}
-static inline ssize_t __store_uint_attr(char *buff, size_t count,
+static inline ssize_t __store_uint_attr(const char *buff, size_t count,
int min, int max,
void (*post_func)(struct net_device *),
- struct attribute *attr,
+ const struct attribute *attr,
atomic_t *attr_store, struct net_device *net_dev)
{
int ret;
- ret = store_uint_attr(buff, count, net_dev, (char *)attr->name,
+ ret = store_uint_attr(buff, count, net_dev, attr->name,
min, max, attr_store);
if (post_func && ret)
post_func(net_dev);
@@ -359,6 +380,7 @@ static ssize_t store_gw_bwidth(struct kobject *kobj, struct attribute *attr,
BAT_ATTR_BOOL(aggregated_ogms, S_IRUGO | S_IWUSR, NULL);
BAT_ATTR_BOOL(bonding, S_IRUGO | S_IWUSR, NULL);
BAT_ATTR_BOOL(fragmentation, S_IRUGO | S_IWUSR, update_min_mtu);
+BAT_ATTR_BOOL(ap_isolation, S_IRUGO | S_IWUSR, NULL);
static BAT_ATTR(vis_mode, S_IRUGO | S_IWUSR, show_vis_mode, store_vis_mode);
static BAT_ATTR(gw_mode, S_IRUGO | S_IWUSR, show_gw_mode, store_gw_mode);
BAT_ATTR_UINT(orig_interval, S_IRUGO | S_IWUSR, 2 * JITTER, INT_MAX, NULL);
@@ -368,13 +390,14 @@ BAT_ATTR_UINT(gw_sel_class, S_IRUGO | S_IWUSR, 1, TQ_MAX_VALUE,
static BAT_ATTR(gw_bandwidth, S_IRUGO | S_IWUSR, show_gw_bwidth,
store_gw_bwidth);
#ifdef CONFIG_BATMAN_ADV_DEBUG
-BAT_ATTR_UINT(log_level, S_IRUGO | S_IWUSR, 0, 3, NULL);
+BAT_ATTR_UINT(log_level, S_IRUGO | S_IWUSR, 0, 7, NULL);
#endif
static struct bat_attribute *mesh_attrs[] = {
&bat_attr_aggregated_ogms,
&bat_attr_bonding,
&bat_attr_fragmentation,
+ &bat_attr_ap_isolation,
&bat_attr_vis_mode,
&bat_attr_gw_mode,
&bat_attr_orig_interval,
@@ -594,3 +617,60 @@ void sysfs_del_hardif(struct kobject **hardif_obj)
kobject_put(*hardif_obj);
*hardif_obj = NULL;
}
+
+int throw_uevent(struct bat_priv *bat_priv, enum uev_type type,
+ enum uev_action action, const char *data)
+{
+ int ret = -1;
+ struct hard_iface *primary_if = NULL;
+ struct kobject *bat_kobj;
+ char *uevent_env[4] = { NULL, NULL, NULL, NULL };
+
+ primary_if = primary_if_get_selected(bat_priv);
+ if (!primary_if)
+ goto out;
+
+ bat_kobj = &primary_if->soft_iface->dev.kobj;
+
+ uevent_env[0] = kmalloc(strlen(UEV_TYPE_VAR) +
+ strlen(uev_type_str[type]) + 1,
+ GFP_ATOMIC);
+ if (!uevent_env[0])
+ goto out;
+
+ sprintf(uevent_env[0], "%s%s", UEV_TYPE_VAR, uev_type_str[type]);
+
+ uevent_env[1] = kmalloc(strlen(UEV_ACTION_VAR) +
+ strlen(uev_action_str[action]) + 1,
+ GFP_ATOMIC);
+ if (!uevent_env[1])
+ goto out;
+
+ sprintf(uevent_env[1], "%s%s", UEV_ACTION_VAR, uev_action_str[action]);
+
+ /* If the event is DEL, ignore the data field */
+ if (action != UEV_DEL) {
+ uevent_env[2] = kmalloc(strlen(UEV_DATA_VAR) +
+ strlen(data) + 1, GFP_ATOMIC);
+ if (!uevent_env[2])
+ goto out;
+
+ sprintf(uevent_env[2], "%s%s", UEV_DATA_VAR, data);
+ }
+
+ ret = kobject_uevent_env(bat_kobj, KOBJ_CHANGE, uevent_env);
+out:
+ kfree(uevent_env[0]);
+ kfree(uevent_env[1]);
+ kfree(uevent_env[2]);
+
+ if (primary_if)
+ hardif_free_ref(primary_if);
+
+ if (ret)
+ bat_dbg(DBG_BATMAN, bat_priv, "Impossible to send "
+ "uevent for (%s,%s,%s) event (err: %d)\n",
+ uev_type_str[type], uev_action_str[action],
+ (action == UEV_DEL ? "NULL" : data), ret);
+ return ret;
+}
diff --git a/net/batman-adv/bat_sysfs.h b/net/batman-adv/bat_sysfs.h
index 02f1fa7..a3f75a7 100644
--- a/net/batman-adv/bat_sysfs.h
+++ b/net/batman-adv/bat_sysfs.h
@@ -38,5 +38,7 @@ int sysfs_add_meshif(struct net_device *dev);
void sysfs_del_meshif(struct net_device *dev);
int sysfs_add_hardif(struct kobject **hardif_obj, struct net_device *dev);
void sysfs_del_hardif(struct kobject **hardif_obj);
+int throw_uevent(struct bat_priv *bat_priv, enum uev_type type,
+ enum uev_action action, const char *data);
#endif /* _NET_BATMAN_ADV_SYSFS_H_ */
diff --git a/net/batman-adv/bitarray.c b/net/batman-adv/bitarray.c
index ad2ca92..0be9ff3 100644
--- a/net/batman-adv/bitarray.c
+++ b/net/batman-adv/bitarray.c
@@ -26,8 +26,8 @@
/* returns true if the corresponding bit in the given seq_bits indicates true
* and curr_seqno is within range of last_seqno */
-uint8_t get_bit_status(unsigned long *seq_bits, uint32_t last_seqno,
- uint32_t curr_seqno)
+int get_bit_status(const unsigned long *seq_bits, uint32_t last_seqno,
+ uint32_t curr_seqno)
{
int32_t diff, word_offset, word_num;
@@ -97,12 +97,12 @@ static void bit_shift(unsigned long *seq_bits, int32_t n)
(seq_bits[i - word_num - 1] >>
(WORD_BIT_SIZE-word_offset));
/* and the upper part of the right half and shift it left to
- * it's position */
+ * its position */
/* for our example that would be: word[0] = 9800 + 0076 =
* 9876 */
}
- /* now for our last word, i==word_num, we only have the it's "left"
- * half. that's the 1000 word in our example.*/
+ /* now for our last word, i==word_num, we only have its "left" half.
+ * that's the 1000 word in our example.*/
seq_bits[i] = (seq_bits[i - word_num] << word_offset);
@@ -127,10 +127,10 @@ static void bit_reset_window(unsigned long *seq_bits)
* 1 if the window was moved (either new or very old)
* 0 if the window was not moved/shifted.
*/
-char bit_get_packet(void *priv, unsigned long *seq_bits,
- int32_t seq_num_diff, int8_t set_mark)
+int bit_get_packet(void *priv, unsigned long *seq_bits,
+ int32_t seq_num_diff, int set_mark)
{
- struct bat_priv *bat_priv = (struct bat_priv *)priv;
+ struct bat_priv *bat_priv = priv;
/* sequence number is slightly older. We already got a sequence number
* higher than this one, so we just mark it. */
@@ -190,7 +190,7 @@ char bit_get_packet(void *priv, unsigned long *seq_bits,
/* count the hamming weight, how many good packets did we receive? just count
* the 1's.
*/
-int bit_packet_count(unsigned long *seq_bits)
+int bit_packet_count(const unsigned long *seq_bits)
{
int i, hamming = 0;
diff --git a/net/batman-adv/bitarray.h b/net/batman-adv/bitarray.h
index 769c246..9c04422 100644
--- a/net/batman-adv/bitarray.h
+++ b/net/batman-adv/bitarray.h
@@ -26,8 +26,8 @@
/* returns true if the corresponding bit in the given seq_bits indicates true
* and curr_seqno is within range of last_seqno */
-uint8_t get_bit_status(unsigned long *seq_bits, uint32_t last_seqno,
- uint32_t curr_seqno);
+int get_bit_status(const unsigned long *seq_bits, uint32_t last_seqno,
+ uint32_t curr_seqno);
/* turn corresponding bit on, so we can remember that we got the packet */
void bit_mark(unsigned long *seq_bits, int32_t n);
@@ -35,10 +35,10 @@ void bit_mark(unsigned long *seq_bits, int32_t n);
/* receive and process one packet, returns 1 if received seq_num is considered
* new, 0 if old */
-char bit_get_packet(void *priv, unsigned long *seq_bits,
- int32_t seq_num_diff, int8_t set_mark);
+int bit_get_packet(void *priv, unsigned long *seq_bits,
+ int32_t seq_num_diff, int set_mark);
/* count the hamming weight, how many good packets did we receive? */
-int bit_packet_count(unsigned long *seq_bits);
+int bit_packet_count(const unsigned long *seq_bits);
#endif /* _NET_BATMAN_ADV_BITARRAY_H_ */
diff --git a/net/batman-adv/gateway_client.c b/net/batman-adv/gateway_client.c
index 61605a0..619fb73 100644
--- a/net/batman-adv/gateway_client.c
+++ b/net/batman-adv/gateway_client.c
@@ -20,15 +20,22 @@
*/
#include "main.h"
+#include "bat_sysfs.h"
#include "gateway_client.h"
#include "gateway_common.h"
#include "hard-interface.h"
#include "originator.h"
+#include "routing.h"
#include <linux/ip.h>
#include <linux/ipv6.h>
#include <linux/udp.h>
#include <linux/if_vlan.h>
+/* This is the offset of the options field in a dhcp packet starting at
+ * the beginning of the dhcp header */
+#define DHCP_OPTIONS_OFFSET 240
+#define DHCP_REQUEST 3
+
static void gw_node_free_ref(struct gw_node *gw_node)
{
if (atomic_dec_and_test(&gw_node->refcount))
@@ -86,7 +93,7 @@ static void gw_select(struct bat_priv *bat_priv, struct gw_node *new_gw_node)
if (new_gw_node && !atomic_inc_not_zero(&new_gw_node->refcount))
new_gw_node = NULL;
- curr_gw_node = bat_priv->curr_gw;
+ curr_gw_node = rcu_dereference_protected(bat_priv->curr_gw, 1);
rcu_assign_pointer(bat_priv->curr_gw, new_gw_node);
if (curr_gw_node)
@@ -97,40 +104,19 @@ static void gw_select(struct bat_priv *bat_priv, struct gw_node *new_gw_node)
void gw_deselect(struct bat_priv *bat_priv)
{
- gw_select(bat_priv, NULL);
+ atomic_set(&bat_priv->gw_reselect, 1);
}
-void gw_election(struct bat_priv *bat_priv)
+static struct gw_node *gw_get_best_gw_node(struct bat_priv *bat_priv)
{
- struct hlist_node *node;
- struct gw_node *gw_node, *curr_gw = NULL, *curr_gw_tmp = NULL;
struct neigh_node *router;
- uint8_t max_tq = 0;
+ struct hlist_node *node;
+ struct gw_node *gw_node, *curr_gw = NULL;
uint32_t max_gw_factor = 0, tmp_gw_factor = 0;
+ uint8_t max_tq = 0;
int down, up;
- /**
- * The batman daemon checks here if we already passed a full originator
- * cycle in order to make sure we don't choose the first gateway we
- * hear about. This check is based on the daemon's uptime which we
- * don't have.
- **/
- if (atomic_read(&bat_priv->gw_mode) != GW_MODE_CLIENT)
- return;
-
- curr_gw = gw_get_selected_gw_node(bat_priv);
- if (curr_gw)
- goto out;
-
rcu_read_lock();
- if (hlist_empty(&bat_priv->gw_list)) {
- bat_dbg(DBG_BATMAN, bat_priv,
- "Removing selected gateway - "
- "no gateway in range\n");
- gw_deselect(bat_priv);
- goto unlock;
- }
-
hlist_for_each_entry_rcu(gw_node, node, &bat_priv->gw_list, list) {
if (gw_node->deleted)
continue;
@@ -139,6 +125,9 @@ void gw_election(struct bat_priv *bat_priv)
if (!router)
continue;
+ if (!atomic_inc_not_zero(&gw_node->refcount))
+ goto next;
+
switch (atomic_read(&bat_priv->gw_sel_class)) {
case 1: /* fast connection */
gw_bandwidth_to_kbit(gw_node->orig_node->gw_flags,
@@ -151,8 +140,12 @@ void gw_election(struct bat_priv *bat_priv)
if ((tmp_gw_factor > max_gw_factor) ||
((tmp_gw_factor == max_gw_factor) &&
- (router->tq_avg > max_tq)))
- curr_gw_tmp = gw_node;
+ (router->tq_avg > max_tq))) {
+ if (curr_gw)
+ gw_node_free_ref(curr_gw);
+ curr_gw = gw_node;
+ atomic_inc(&curr_gw->refcount);
+ }
break;
default: /**
@@ -163,8 +156,12 @@ void gw_election(struct bat_priv *bat_priv)
* soon as a better gateway appears which has
* $routing_class more tq points)
**/
- if (router->tq_avg > max_tq)
- curr_gw_tmp = gw_node;
+ if (router->tq_avg > max_tq) {
+ if (curr_gw)
+ gw_node_free_ref(curr_gw);
+ curr_gw = gw_node;
+ atomic_inc(&curr_gw->refcount);
+ }
break;
}
@@ -174,42 +171,81 @@ void gw_election(struct bat_priv *bat_priv)
if (tmp_gw_factor > max_gw_factor)
max_gw_factor = tmp_gw_factor;
+ gw_node_free_ref(gw_node);
+
+next:
neigh_node_free_ref(router);
}
+ rcu_read_unlock();
- if (curr_gw != curr_gw_tmp) {
- router = orig_node_get_router(curr_gw_tmp->orig_node);
- if (!router)
- goto unlock;
+ return curr_gw;
+}
- if ((curr_gw) && (!curr_gw_tmp))
- bat_dbg(DBG_BATMAN, bat_priv,
- "Removing selected gateway - "
- "no gateway in range\n");
- else if ((!curr_gw) && (curr_gw_tmp))
- bat_dbg(DBG_BATMAN, bat_priv,
- "Adding route to gateway %pM "
- "(gw_flags: %i, tq: %i)\n",
- curr_gw_tmp->orig_node->orig,
- curr_gw_tmp->orig_node->gw_flags,
- router->tq_avg);
- else
- bat_dbg(DBG_BATMAN, bat_priv,
- "Changing route to gateway %pM "
- "(gw_flags: %i, tq: %i)\n",
- curr_gw_tmp->orig_node->orig,
- curr_gw_tmp->orig_node->gw_flags,
- router->tq_avg);
+void gw_election(struct bat_priv *bat_priv)
+{
+ struct gw_node *curr_gw = NULL, *next_gw = NULL;
+ struct neigh_node *router = NULL;
+ char gw_addr[18] = { '\0' };
- neigh_node_free_ref(router);
- gw_select(bat_priv, curr_gw_tmp);
+ /**
+ * The batman daemon checks here if we already passed a full originator
+ * cycle in order to make sure we don't choose the first gateway we
+ * hear about. This check is based on the daemon's uptime which we
+ * don't have.
+ **/
+ if (atomic_read(&bat_priv->gw_mode) != GW_MODE_CLIENT)
+ goto out;
+
+ if (!atomic_dec_not_zero(&bat_priv->gw_reselect))
+ goto out;
+
+ curr_gw = gw_get_selected_gw_node(bat_priv);
+
+ next_gw = gw_get_best_gw_node(bat_priv);
+
+ if (curr_gw == next_gw)
+ goto out;
+
+ if (next_gw) {
+ sprintf(gw_addr, "%pM", next_gw->orig_node->orig);
+
+ router = orig_node_get_router(next_gw->orig_node);
+ if (!router) {
+ gw_deselect(bat_priv);
+ goto out;
+ }
}
-unlock:
- rcu_read_unlock();
+ if ((curr_gw) && (!next_gw)) {
+ bat_dbg(DBG_BATMAN, bat_priv,
+ "Removing selected gateway - no gateway in range\n");
+ throw_uevent(bat_priv, UEV_GW, UEV_DEL, NULL);
+ } else if ((!curr_gw) && (next_gw)) {
+ bat_dbg(DBG_BATMAN, bat_priv,
+ "Adding route to gateway %pM (gw_flags: %i, tq: %i)\n",
+ next_gw->orig_node->orig,
+ next_gw->orig_node->gw_flags,
+ router->tq_avg);
+ throw_uevent(bat_priv, UEV_GW, UEV_ADD, gw_addr);
+ } else {
+ bat_dbg(DBG_BATMAN, bat_priv,
+ "Changing route to gateway %pM "
+ "(gw_flags: %i, tq: %i)\n",
+ next_gw->orig_node->orig,
+ next_gw->orig_node->gw_flags,
+ router->tq_avg);
+ throw_uevent(bat_priv, UEV_GW, UEV_CHANGE, gw_addr);
+ }
+
+ gw_select(bat_priv, next_gw);
+
out:
if (curr_gw)
gw_node_free_ref(curr_gw);
+ if (next_gw)
+ gw_node_free_ref(next_gw);
+ if (router)
+ neigh_node_free_ref(router);
}
void gw_check_election(struct bat_priv *bat_priv, struct orig_node *orig_node)
@@ -273,11 +309,10 @@ static void gw_node_add(struct bat_priv *bat_priv,
struct gw_node *gw_node;
int down, up;
- gw_node = kmalloc(sizeof(struct gw_node), GFP_ATOMIC);
+ gw_node = kzalloc(sizeof(*gw_node), GFP_ATOMIC);
if (!gw_node)
return;
- memset(gw_node, 0, sizeof(struct gw_node));
INIT_HLIST_NODE(&gw_node->list);
gw_node->orig_node = orig_node;
atomic_set(&gw_node->refcount, 1);
@@ -323,7 +358,7 @@ void gw_node_update(struct bat_priv *bat_priv,
gw_node->deleted = 0;
- if (new_gwflags == 0) {
+ if (new_gwflags == NO_FLAGS) {
gw_node->deleted = jiffies;
bat_dbg(DBG_BATMAN, bat_priv,
"Gateway %pM removed from gateway list\n",
@@ -336,7 +371,7 @@ void gw_node_update(struct bat_priv *bat_priv,
goto unlock;
}
- if (new_gwflags == 0)
+ if (new_gwflags == NO_FLAGS)
goto unlock;
gw_node_add(bat_priv, orig_node, new_gwflags);
@@ -353,7 +388,7 @@ unlock:
void gw_node_delete(struct bat_priv *bat_priv, struct orig_node *orig_node)
{
- return gw_node_update(bat_priv, orig_node, 0);
+ gw_node_update(bat_priv, orig_node, 0);
}
void gw_node_purge(struct bat_priv *bat_priv)
@@ -361,7 +396,7 @@ void gw_node_purge(struct bat_priv *bat_priv)
struct gw_node *gw_node, *curr_gw;
struct hlist_node *node, *node_tmp;
unsigned long timeout = 2 * PURGE_TIMEOUT * HZ;
- char do_deselect = 0;
+ int do_deselect = 0;
curr_gw = gw_get_selected_gw_node(bat_priv);
@@ -394,8 +429,8 @@ void gw_node_purge(struct bat_priv *bat_priv)
/**
* fails if orig_node has no router
*/
-static int _write_buffer_text(struct bat_priv *bat_priv,
- struct seq_file *seq, struct gw_node *gw_node)
+static int _write_buffer_text(struct bat_priv *bat_priv, struct seq_file *seq,
+ const struct gw_node *gw_node)
{
struct gw_node *curr_gw;
struct neigh_node *router;
@@ -452,10 +487,9 @@ int gw_client_seq_print_text(struct seq_file *seq, void *offset)
}
seq_printf(seq, " %-12s (%s/%i) %17s [%10s]: gw_class ... "
- "[B.A.T.M.A.N. adv %s%s, MainIF/MAC: %s/%pM (%s)]\n",
+ "[B.A.T.M.A.N. adv %s, MainIF/MAC: %s/%pM (%s)]\n",
"Gateway", "#", TQ_MAX_VALUE, "Nexthop",
- "outgoingIF", SOURCE_VERSION, REVISION_VERSION_STR,
- primary_if->net_dev->name,
+ "outgoingIF", SOURCE_VERSION, primary_if->net_dev->name,
primary_if->net_dev->dev_addr, net_dev->name);
rcu_read_lock();
@@ -480,14 +514,75 @@ out:
return ret;
}
-int gw_is_target(struct bat_priv *bat_priv, struct sk_buff *skb)
+static bool is_type_dhcprequest(struct sk_buff *skb, int header_len)
+{
+ int ret = false;
+ unsigned char *p;
+ int pkt_len;
+
+ if (skb_linearize(skb) < 0)
+ goto out;
+
+ pkt_len = skb_headlen(skb);
+
+ if (pkt_len < header_len + DHCP_OPTIONS_OFFSET + 1)
+ goto out;
+
+ p = skb->data + header_len + DHCP_OPTIONS_OFFSET;
+ pkt_len -= header_len + DHCP_OPTIONS_OFFSET + 1;
+
+ /* Access the dhcp option lists. Each entry is made up by:
+ * - octet 1: option type
+ * - octet 2: option data len (only if type != 255 and 0)
+ * - octet 3: option data */
+ while (*p != 255 && !ret) {
+ /* p now points to the first octet: option type */
+ if (*p == 53) {
+ /* type 53 is the message type option.
+ * Jump the len octet and go to the data octet */
+ if (pkt_len < 2)
+ goto out;
+ p += 2;
+
+ /* check if the message type is what we need */
+ if (*p == DHCP_REQUEST)
+ ret = true;
+ break;
+ } else if (*p == 0) {
+ /* option type 0 (padding), just go forward */
+ if (pkt_len < 1)
+ goto out;
+ pkt_len--;
+ p++;
+ } else {
+ /* This is any other option. So we get the length... */
+ if (pkt_len < 1)
+ goto out;
+ pkt_len--;
+ p++;
+
+ /* ...and then we jump over the data */
+ if (pkt_len < *p)
+ goto out;
+ pkt_len -= *p;
+ p += (*p);
+ }
+ }
+out:
+ return ret;
+}
+
+int gw_is_target(struct bat_priv *bat_priv, struct sk_buff *skb,
+ struct orig_node *old_gw)
{
struct ethhdr *ethhdr;
struct iphdr *iphdr;
struct ipv6hdr *ipv6hdr;
struct udphdr *udphdr;
struct gw_node *curr_gw;
+ struct neigh_node *neigh_curr = NULL, *neigh_old = NULL;
unsigned int header_len = 0;
+ int ret = 1;
if (atomic_read(&bat_priv->gw_mode) == GW_MODE_OFF)
return 0;
@@ -509,7 +604,7 @@ int gw_is_target(struct bat_priv *bat_priv, struct sk_buff *skb)
/* check for ip header */
switch (ntohs(ethhdr->h_proto)) {
case ETH_P_IP:
- if (!pskb_may_pull(skb, header_len + sizeof(struct iphdr)))
+ if (!pskb_may_pull(skb, header_len + sizeof(*iphdr)))
return 0;
iphdr = (struct iphdr *)(skb->data + header_len);
header_len += iphdr->ihl * 4;
@@ -520,10 +615,10 @@ int gw_is_target(struct bat_priv *bat_priv, struct sk_buff *skb)
break;
case ETH_P_IPV6:
- if (!pskb_may_pull(skb, header_len + sizeof(struct ipv6hdr)))
+ if (!pskb_may_pull(skb, header_len + sizeof(*ipv6hdr)))
return 0;
ipv6hdr = (struct ipv6hdr *)(skb->data + header_len);
- header_len += sizeof(struct ipv6hdr);
+ header_len += sizeof(*ipv6hdr);
/* check for udp header */
if (ipv6hdr->nexthdr != IPPROTO_UDP)
@@ -534,10 +629,10 @@ int gw_is_target(struct bat_priv *bat_priv, struct sk_buff *skb)
return 0;
}
- if (!pskb_may_pull(skb, header_len + sizeof(struct udphdr)))
+ if (!pskb_may_pull(skb, header_len + sizeof(*udphdr)))
return 0;
udphdr = (struct udphdr *)(skb->data + header_len);
- header_len += sizeof(struct udphdr);
+ header_len += sizeof(*udphdr);
/* check for bootp port */
if ((ntohs(ethhdr->h_proto) == ETH_P_IP) &&
@@ -555,7 +650,30 @@ int gw_is_target(struct bat_priv *bat_priv, struct sk_buff *skb)
if (!curr_gw)
return 0;
+ /* If old_gw != NULL then this packet is unicast.
+ * So, at this point we have to check the message type: if it is a
+ * DHCPREQUEST we have to decide whether to drop it or not */
+ if (old_gw && curr_gw->orig_node != old_gw) {
+ if (is_type_dhcprequest(skb, header_len)) {
+ /* If the dhcp packet has been sent to a different gw,
+ * we have to evaluate whether the old gw is still
+ * reliable enough */
+ neigh_curr = find_router(bat_priv, curr_gw->orig_node,
+ NULL);
+ neigh_old = find_router(bat_priv, old_gw, NULL);
+ if (!neigh_curr || !neigh_old)
+ goto free_neigh;
+ if (neigh_curr->tq_avg - neigh_old->tq_avg <
+ GW_THRESHOLD)
+ ret = -1;
+ }
+ }
+free_neigh:
+ if (neigh_old)
+ neigh_node_free_ref(neigh_old);
+ if (neigh_curr)
+ neigh_node_free_ref(neigh_curr);
if (curr_gw)
gw_node_free_ref(curr_gw);
- return 1;
+ return ret;
}
diff --git a/net/batman-adv/gateway_client.h b/net/batman-adv/gateway_client.h
index 1ce8c60..b9b983c 100644
--- a/net/batman-adv/gateway_client.h
+++ b/net/batman-adv/gateway_client.h
@@ -31,6 +31,7 @@ void gw_node_update(struct bat_priv *bat_priv,
void gw_node_delete(struct bat_priv *bat_priv, struct orig_node *orig_node);
void gw_node_purge(struct bat_priv *bat_priv);
int gw_client_seq_print_text(struct seq_file *seq, void *offset);
-int gw_is_target(struct bat_priv *bat_priv, struct sk_buff *skb);
+int gw_is_target(struct bat_priv *bat_priv, struct sk_buff *skb,
+ struct orig_node *old_gw);
#endif /* _NET_BATMAN_ADV_GATEWAY_CLIENT_H_ */
diff --git a/net/batman-adv/gateway_common.c b/net/batman-adv/gateway_common.c
index 50d3a59..18661af 100644
--- a/net/batman-adv/gateway_common.c
+++ b/net/batman-adv/gateway_common.c
@@ -61,9 +61,9 @@ static void kbit_to_gw_bandwidth(int down, int up, long *gw_srv_class)
/* returns the up and downspeeds in kbit, calculated from the class */
void gw_bandwidth_to_kbit(uint8_t gw_srv_class, int *down, int *up)
{
- char sbit = (gw_srv_class & 0x80) >> 7;
- char dpart = (gw_srv_class & 0x78) >> 3;
- char upart = (gw_srv_class & 0x07);
+ int sbit = (gw_srv_class & 0x80) >> 7;
+ int dpart = (gw_srv_class & 0x78) >> 3;
+ int upart = (gw_srv_class & 0x07);
if (!gw_srv_class) {
*down = 0;
@@ -76,10 +76,11 @@ void gw_bandwidth_to_kbit(uint8_t gw_srv_class, int *down, int *up)
}
static bool parse_gw_bandwidth(struct net_device *net_dev, char *buff,
- long *up, long *down)
+ int *up, int *down)
{
int ret, multi = 1;
char *slash_ptr, *tmp_ptr;
+ long ldown, lup;
slash_ptr = strchr(buff, '/');
if (slash_ptr)
@@ -96,7 +97,7 @@ static bool parse_gw_bandwidth(struct net_device *net_dev, char *buff,
*tmp_ptr = '\0';
}
- ret = strict_strtoul(buff, 10, down);
+ ret = strict_strtol(buff, 10, &ldown);
if (ret) {
bat_err(net_dev,
"Download speed of gateway mode invalid: %s\n",
@@ -104,7 +105,7 @@ static bool parse_gw_bandwidth(struct net_device *net_dev, char *buff,
return false;
}
- *down *= multi;
+ *down = ldown * multi;
/* we also got some upload info */
if (slash_ptr) {
@@ -121,7 +122,7 @@ static bool parse_gw_bandwidth(struct net_device *net_dev, char *buff,
*tmp_ptr = '\0';
}
- ret = strict_strtoul(slash_ptr + 1, 10, up);
+ ret = strict_strtol(slash_ptr + 1, 10, &lup);
if (ret) {
bat_err(net_dev,
"Upload speed of gateway mode invalid: "
@@ -129,7 +130,7 @@ static bool parse_gw_bandwidth(struct net_device *net_dev, char *buff,
return false;
}
- *up *= multi;
+ *up = lup * multi;
}
return true;
@@ -138,7 +139,8 @@ static bool parse_gw_bandwidth(struct net_device *net_dev, char *buff,
ssize_t gw_bandwidth_set(struct net_device *net_dev, char *buff, size_t count)
{
struct bat_priv *bat_priv = netdev_priv(net_dev);
- long gw_bandwidth_tmp = 0, up = 0, down = 0;
+ long gw_bandwidth_tmp = 0;
+ int up = 0, down = 0;
bool ret;
ret = parse_gw_bandwidth(net_dev, buff, &up, &down);
@@ -158,12 +160,11 @@ ssize_t gw_bandwidth_set(struct net_device *net_dev, char *buff, size_t count)
* speeds, hence we need to calculate it back to show the number
* that is going to be propagated
**/
- gw_bandwidth_to_kbit((uint8_t)gw_bandwidth_tmp,
- (int *)&down, (int *)&up);
+ gw_bandwidth_to_kbit((uint8_t)gw_bandwidth_tmp, &down, &up);
gw_deselect(bat_priv);
bat_info(net_dev, "Changing gateway bandwidth from: '%i' to: '%ld' "
- "(propagating: %ld%s/%ld%s)\n",
+ "(propagating: %d%s/%d%s)\n",
atomic_read(&bat_priv->gw_bandwidth), gw_bandwidth_tmp,
(down > 2048 ? down / 1024 : down),
(down > 2048 ? "MBit" : "KBit"),
diff --git a/net/batman-adv/hard-interface.c b/net/batman-adv/hard-interface.c
index dfbfccc..7704df4 100644
--- a/net/batman-adv/hard-interface.c
+++ b/net/batman-adv/hard-interface.c
@@ -28,6 +28,7 @@
#include "bat_sysfs.h"
#include "originator.h"
#include "hash.h"
+#include "bat_ogm.h"
#include <linux/if_arp.h>
@@ -46,7 +47,7 @@ void hardif_free_rcu(struct rcu_head *rcu)
kfree(hard_iface);
}
-struct hard_iface *hardif_get_by_netdev(struct net_device *net_dev)
+struct hard_iface *hardif_get_by_netdev(const struct net_device *net_dev)
{
struct hard_iface *hard_iface;
@@ -64,7 +65,7 @@ out:
return hard_iface;
}
-static int is_valid_iface(struct net_device *net_dev)
+static int is_valid_iface(const struct net_device *net_dev)
{
if (net_dev->flags & IFF_LOOPBACK)
return 0;
@@ -86,7 +87,7 @@ static int is_valid_iface(struct net_device *net_dev)
return 1;
}
-static struct hard_iface *hardif_get_active(struct net_device *soft_iface)
+static struct hard_iface *hardif_get_active(const struct net_device *soft_iface)
{
struct hard_iface *hard_iface;
@@ -131,14 +132,13 @@ static void primary_if_select(struct bat_priv *bat_priv,
struct hard_iface *new_hard_iface)
{
struct hard_iface *curr_hard_iface;
- struct batman_packet *batman_packet;
ASSERT_RTNL();
if (new_hard_iface && !atomic_inc_not_zero(&new_hard_iface->refcount))
new_hard_iface = NULL;
- curr_hard_iface = bat_priv->primary_if;
+ curr_hard_iface = rcu_dereference_protected(bat_priv->primary_if, 1);
rcu_assign_pointer(bat_priv->primary_if, new_hard_iface);
if (curr_hard_iface)
@@ -147,20 +147,11 @@ static void primary_if_select(struct bat_priv *bat_priv,
if (!new_hard_iface)
return;
- batman_packet = (struct batman_packet *)(new_hard_iface->packet_buff);
- batman_packet->flags = PRIMARIES_FIRST_HOP;
- batman_packet->ttl = TTL;
-
+ bat_ogm_init_primary(new_hard_iface);
primary_if_update_addr(bat_priv);
-
- /***
- * hacky trick to make sure that we send the TT information via
- * our new primary interface
- */
- atomic_set(&bat_priv->tt_local_changed, 1);
}
-static bool hardif_is_iface_up(struct hard_iface *hard_iface)
+static bool hardif_is_iface_up(const struct hard_iface *hard_iface)
{
if (hard_iface->net_dev->flags & IFF_UP)
return true;
@@ -168,17 +159,9 @@ static bool hardif_is_iface_up(struct hard_iface *hard_iface)
return false;
}
-static void update_mac_addresses(struct hard_iface *hard_iface)
+static void check_known_mac_addr(const struct net_device *net_dev)
{
- memcpy(((struct batman_packet *)(hard_iface->packet_buff))->orig,
- hard_iface->net_dev->dev_addr, ETH_ALEN);
- memcpy(((struct batman_packet *)(hard_iface->packet_buff))->prev_sender,
- hard_iface->net_dev->dev_addr, ETH_ALEN);
-}
-
-static void check_known_mac_addr(struct net_device *net_dev)
-{
- struct hard_iface *hard_iface;
+ const struct hard_iface *hard_iface;
rcu_read_lock();
list_for_each_entry_rcu(hard_iface, &hardif_list, list) {
@@ -204,8 +187,8 @@ static void check_known_mac_addr(struct net_device *net_dev)
int hardif_min_mtu(struct net_device *soft_iface)
{
- struct bat_priv *bat_priv = netdev_priv(soft_iface);
- struct hard_iface *hard_iface;
+ const struct bat_priv *bat_priv = netdev_priv(soft_iface);
+ const struct hard_iface *hard_iface;
/* allow big frames if all devices are capable to do so
* (have MTU > 1500 + BAT_HEADER_LEN) */
int min_mtu = ETH_DATA_LEN;
@@ -250,12 +233,12 @@ static void hardif_activate_interface(struct hard_iface *hard_iface)
bat_priv = netdev_priv(hard_iface->soft_iface);
- update_mac_addresses(hard_iface);
+ bat_ogm_update_mac(hard_iface);
hard_iface->if_status = IF_TO_BE_ACTIVATED;
/**
* the first active interface becomes our primary interface or
- * the next active interface after the old primay interface was removed
+ * the next active interface after the old primary interface was removed
*/
primary_if = primary_if_get_selected(bat_priv);
if (!primary_if)
@@ -285,10 +268,10 @@ static void hardif_deactivate_interface(struct hard_iface *hard_iface)
update_min_mtu(hard_iface->soft_iface);
}
-int hardif_enable_interface(struct hard_iface *hard_iface, char *iface_name)
+int hardif_enable_interface(struct hard_iface *hard_iface,
+ const char *iface_name)
{
struct bat_priv *bat_priv;
- struct batman_packet *batman_packet;
struct net_device *soft_iface;
int ret;
@@ -323,8 +306,8 @@ int hardif_enable_interface(struct hard_iface *hard_iface, char *iface_name)
hard_iface->soft_iface = soft_iface;
bat_priv = netdev_priv(hard_iface->soft_iface);
- hard_iface->packet_len = BAT_PACKET_LEN;
- hard_iface->packet_buff = kmalloc(hard_iface->packet_len, GFP_ATOMIC);
+
+ bat_ogm_init(hard_iface);
if (!hard_iface->packet_buff) {
bat_err(hard_iface->soft_iface, "Can't add interface packet "
@@ -333,14 +316,6 @@ int hardif_enable_interface(struct hard_iface *hard_iface, char *iface_name)
goto err;
}
- batman_packet = (struct batman_packet *)(hard_iface->packet_buff);
- batman_packet->packet_type = BAT_PACKET;
- batman_packet->version = COMPAT_VERSION;
- batman_packet->flags = 0;
- batman_packet->ttl = 2;
- batman_packet->tq = TQ_MAX_VALUE;
- batman_packet->num_tt = 0;
-
hard_iface->if_num = bat_priv->num_ifaces;
bat_priv->num_ifaces++;
hard_iface->if_status = IF_INACTIVE;
@@ -385,7 +360,7 @@ int hardif_enable_interface(struct hard_iface *hard_iface, char *iface_name)
hard_iface->net_dev->name);
/* begin scheduling originator messages on that interface */
- schedule_own_packet(hard_iface);
+ schedule_bat_ogm(hard_iface);
out:
return 0;
@@ -458,12 +433,9 @@ static struct hard_iface *hardif_add_interface(struct net_device *net_dev)
dev_hold(net_dev);
- hard_iface = kmalloc(sizeof(struct hard_iface), GFP_ATOMIC);
- if (!hard_iface) {
- pr_err("Can't add interface (%s): out of memory\n",
- net_dev->name);
+ hard_iface = kmalloc(sizeof(*hard_iface), GFP_ATOMIC);
+ if (!hard_iface)
goto release_dev;
- }
ret = sysfs_add_hardif(&hard_iface->hardif_obj, net_dev);
if (ret)
@@ -522,7 +494,7 @@ void hardif_remove_interfaces(void)
static int hard_if_event(struct notifier_block *this,
unsigned long event, void *ptr)
{
- struct net_device *net_dev = (struct net_device *)ptr;
+ struct net_device *net_dev = ptr;
struct hard_iface *hard_iface = hardif_get_by_netdev(net_dev);
struct hard_iface *primary_if = NULL;
struct bat_priv *bat_priv;
@@ -555,7 +527,7 @@ static int hard_if_event(struct notifier_block *this,
goto hardif_put;
check_known_mac_addr(hard_iface->net_dev);
- update_mac_addresses(hard_iface);
+ bat_ogm_update_mac(hard_iface);
bat_priv = netdev_priv(hard_iface->soft_iface);
primary_if = primary_if_get_selected(bat_priv);
@@ -567,7 +539,7 @@ static int hard_if_event(struct notifier_block *this,
break;
default:
break;
- };
+ }
hardif_put:
hardif_free_ref(hard_iface);
@@ -577,14 +549,14 @@ out:
return NOTIFY_DONE;
}
-/* receive a packet with the batman ethertype coming on a hard
+/* incoming packets with the batman ethertype received on any active hard
* interface */
static int batman_skb_recv(struct sk_buff *skb, struct net_device *dev,
struct packet_type *ptype,
struct net_device *orig_dev)
{
struct bat_priv *bat_priv;
- struct batman_packet *batman_packet;
+ struct batman_ogm_packet *batman_ogm_packet;
struct hard_iface *hard_iface;
int ret;
@@ -616,22 +588,22 @@ static int batman_skb_recv(struct sk_buff *skb, struct net_device *dev,
if (hard_iface->if_status != IF_ACTIVE)
goto err_free;
- batman_packet = (struct batman_packet *)skb->data;
+ batman_ogm_packet = (struct batman_ogm_packet *)skb->data;
- if (batman_packet->version != COMPAT_VERSION) {
+ if (batman_ogm_packet->version != COMPAT_VERSION) {
bat_dbg(DBG_BATMAN, bat_priv,
"Drop packet: incompatible batman version (%i)\n",
- batman_packet->version);
+ batman_ogm_packet->version);
goto err_free;
}
/* all receive handlers return whether they received or reused
* the supplied skb. if not, we have to free the skb. */
- switch (batman_packet->packet_type) {
+ switch (batman_ogm_packet->packet_type) {
/* batman originator packet */
- case BAT_PACKET:
- ret = recv_bat_packet(skb, hard_iface);
+ case BAT_OGM:
+ ret = recv_bat_ogm_packet(skb, hard_iface);
break;
/* batman icmp packet */
@@ -658,6 +630,14 @@ static int batman_skb_recv(struct sk_buff *skb, struct net_device *dev,
case BAT_VIS:
ret = recv_vis_packet(skb, hard_iface);
break;
+ /* Translation table query (request or response) */
+ case BAT_TT_QUERY:
+ ret = recv_tt_query(skb, hard_iface);
+ break;
+ /* Roaming advertisement */
+ case BAT_ROAM_ADV:
+ ret = recv_roam_adv(skb, hard_iface);
+ break;
default:
ret = NET_RX_DROP;
}
@@ -677,6 +657,36 @@ err_out:
return NET_RX_DROP;
}
+/* This function returns true if the interface represented by ifindex is a
+ * 802.11 wireless device */
+bool is_wifi_iface(int ifindex)
+{
+ struct net_device *net_device = NULL;
+ bool ret = false;
+
+ if (ifindex == NULL_IFINDEX)
+ goto out;
+
+ net_device = dev_get_by_index(&init_net, ifindex);
+ if (!net_device)
+ goto out;
+
+#ifdef CONFIG_WIRELESS_EXT
+ /* pre-cfg80211 drivers have to implement WEXT, so it is possible to
+ * check for wireless_handlers != NULL */
+ if (net_device->wireless_handlers)
+ ret = true;
+ else
+#endif
+ /* cfg80211 drivers have to set ieee80211_ptr */
+ if (net_device->ieee80211_ptr)
+ ret = true;
+out:
+ if (net_device)
+ dev_put(net_device);
+ return ret;
+}
+
struct notifier_block hard_if_notifier = {
.notifier_call = hard_if_event,
};
diff --git a/net/batman-adv/hard-interface.h b/net/batman-adv/hard-interface.h
index 6426599..67f78d1 100644
--- a/net/batman-adv/hard-interface.h
+++ b/net/batman-adv/hard-interface.h
@@ -22,22 +22,27 @@
#ifndef _NET_BATMAN_ADV_HARD_INTERFACE_H_
#define _NET_BATMAN_ADV_HARD_INTERFACE_H_
-#define IF_NOT_IN_USE 0
-#define IF_TO_BE_REMOVED 1
-#define IF_INACTIVE 2
-#define IF_ACTIVE 3
-#define IF_TO_BE_ACTIVATED 4
-#define IF_I_WANT_YOU 5
+enum hard_if_state {
+ IF_NOT_IN_USE,
+ IF_TO_BE_REMOVED,
+ IF_INACTIVE,
+ IF_ACTIVE,
+ IF_TO_BE_ACTIVATED,
+ IF_I_WANT_YOU
+};
extern struct notifier_block hard_if_notifier;
-struct hard_iface *hardif_get_by_netdev(struct net_device *net_dev);
-int hardif_enable_interface(struct hard_iface *hard_iface, char *iface_name);
+struct hard_iface*
+hardif_get_by_netdev(const struct net_device *net_dev);
+int hardif_enable_interface(struct hard_iface *hard_iface,
+ const char *iface_name);
void hardif_disable_interface(struct hard_iface *hard_iface);
void hardif_remove_interfaces(void);
int hardif_min_mtu(struct net_device *soft_iface);
void update_min_mtu(struct net_device *soft_iface);
void hardif_free_rcu(struct rcu_head *rcu);
+bool is_wifi_iface(int ifindex);
static inline void hardif_free_ref(struct hard_iface *hard_iface)
{
diff --git a/net/batman-adv/hash.c b/net/batman-adv/hash.c
index c5213d8..2a17250 100644
--- a/net/batman-adv/hash.c
+++ b/net/batman-adv/hash.c
@@ -46,15 +46,16 @@ struct hashtable_t *hash_new(int size)
{
struct hashtable_t *hash;
- hash = kmalloc(sizeof(struct hashtable_t), GFP_ATOMIC);
+ hash = kmalloc(sizeof(*hash), GFP_ATOMIC);
if (!hash)
return NULL;
- hash->table = kmalloc(sizeof(struct element_t *) * size, GFP_ATOMIC);
+ hash->table = kmalloc(sizeof(*hash->table) * size, GFP_ATOMIC);
if (!hash->table)
goto free_hash;
- hash->list_locks = kmalloc(sizeof(spinlock_t) * size, GFP_ATOMIC);
+ hash->list_locks = kmalloc(sizeof(*hash->list_locks) * size,
+ GFP_ATOMIC);
if (!hash->list_locks)
goto free_table;
diff --git a/net/batman-adv/hash.h b/net/batman-adv/hash.h
index 434822b..d20aa71 100644
--- a/net/batman-adv/hash.h
+++ b/net/batman-adv/hash.h
@@ -28,12 +28,12 @@
* compare 2 element datas for their keys,
* return 0 if same and not 0 if not
* same */
-typedef int (*hashdata_compare_cb)(struct hlist_node *, void *);
+typedef int (*hashdata_compare_cb)(const struct hlist_node *, const void *);
/* the hashfunction, should return an index
* based on the key in the data of the first
* argument and the size the second */
-typedef int (*hashdata_choose_cb)(void *, int);
+typedef int (*hashdata_choose_cb)(const void *, int);
typedef void (*hashdata_free_cb)(struct hlist_node *, void *);
struct hashtable_t {
@@ -76,19 +76,30 @@ static inline void hash_delete(struct hashtable_t *hash,
hash_destroy(hash);
}
-/* adds data to the hashtable. returns 0 on success, -1 on error */
+/**
+ * hash_add - adds data to the hashtable
+ * @hash: storage hash table
+ * @compare: callback to determine if 2 hash elements are identical
+ * @choose: callback calculating the hash index
+ * @data: data passed to the aforementioned callbacks as argument
+ * @data_node: to be added element
+ *
+ * Returns 0 on success, 1 if the element already is in the hash
+ * and -1 on error.
+ */
+
static inline int hash_add(struct hashtable_t *hash,
hashdata_compare_cb compare,
hashdata_choose_cb choose,
- void *data, struct hlist_node *data_node)
+ const void *data, struct hlist_node *data_node)
{
- int index;
+ int index, ret = -1;
struct hlist_head *head;
struct hlist_node *node;
spinlock_t *list_lock; /* spinlock to protect write access */
if (!hash)
- goto err;
+ goto out;
index = choose(data, hash->size);
head = &hash->table[index];
@@ -99,6 +110,7 @@ static inline int hash_add(struct hashtable_t *hash,
if (!compare(node, data))
continue;
+ ret = 1;
goto err_unlock;
}
rcu_read_unlock();
@@ -108,12 +120,13 @@ static inline int hash_add(struct hashtable_t *hash,
hlist_add_head_rcu(data_node, head);
spin_unlock_bh(list_lock);
- return 0;
+ ret = 0;
+ goto out;
err_unlock:
rcu_read_unlock();
-err:
- return -1;
+out:
+ return ret;
}
/* removes data from hash, if found. returns pointer do data on success, so you
diff --git a/net/batman-adv/icmp_socket.c b/net/batman-adv/icmp_socket.c
index ad7d8b2..0c82ce3 100644
--- a/net/batman-adv/icmp_socket.c
+++ b/net/batman-adv/icmp_socket.c
@@ -46,7 +46,7 @@ static int bat_socket_open(struct inode *inode, struct file *file)
nonseekable_open(inode, file);
- socket_client = kmalloc(sizeof(struct socket_client), GFP_KERNEL);
+ socket_client = kmalloc(sizeof(*socket_client), GFP_KERNEL);
if (!socket_client)
return -ENOMEM;
@@ -309,7 +309,7 @@ static void bat_socket_add_packet(struct socket_client *socket_client,
{
struct socket_packet *socket_packet;
- socket_packet = kmalloc(sizeof(struct socket_packet), GFP_ATOMIC);
+ socket_packet = kmalloc(sizeof(*socket_packet), GFP_ATOMIC);
if (!socket_packet)
return;
diff --git a/net/batman-adv/main.c b/net/batman-adv/main.c
index 0a7cee0..fb87bdc 100644
--- a/net/batman-adv/main.c
+++ b/net/batman-adv/main.c
@@ -58,9 +58,8 @@ static int __init batman_init(void)
register_netdevice_notifier(&hard_if_notifier);
- pr_info("B.A.T.M.A.N. advanced %s%s (compatibility version %i) "
- "loaded\n", SOURCE_VERSION, REVISION_VERSION_STR,
- COMPAT_VERSION);
+ pr_info("B.A.T.M.A.N. advanced %s (compatibility version %i) "
+ "loaded\n", SOURCE_VERSION, COMPAT_VERSION);
return 0;
}
@@ -84,8 +83,10 @@ int mesh_init(struct net_device *soft_iface)
spin_lock_init(&bat_priv->forw_bat_list_lock);
spin_lock_init(&bat_priv->forw_bcast_list_lock);
- spin_lock_init(&bat_priv->tt_lhash_lock);
- spin_lock_init(&bat_priv->tt_ghash_lock);
+ spin_lock_init(&bat_priv->tt_changes_list_lock);
+ spin_lock_init(&bat_priv->tt_req_list_lock);
+ spin_lock_init(&bat_priv->tt_roam_list_lock);
+ spin_lock_init(&bat_priv->tt_buff_lock);
spin_lock_init(&bat_priv->gw_list_lock);
spin_lock_init(&bat_priv->vis_hash_lock);
spin_lock_init(&bat_priv->vis_list_lock);
@@ -96,27 +97,26 @@ int mesh_init(struct net_device *soft_iface)
INIT_HLIST_HEAD(&bat_priv->forw_bcast_list);
INIT_HLIST_HEAD(&bat_priv->gw_list);
INIT_HLIST_HEAD(&bat_priv->softif_neigh_vids);
+ INIT_LIST_HEAD(&bat_priv->tt_changes_list);
+ INIT_LIST_HEAD(&bat_priv->tt_req_list);
+ INIT_LIST_HEAD(&bat_priv->tt_roam_list);
if (originator_init(bat_priv) < 1)
goto err;
- if (tt_local_init(bat_priv) < 1)
+ if (tt_init(bat_priv) < 1)
goto err;
- if (tt_global_init(bat_priv) < 1)
- goto err;
-
- tt_local_add(soft_iface, soft_iface->dev_addr);
+ tt_local_add(soft_iface, soft_iface->dev_addr, NULL_IFINDEX);
if (vis_init(bat_priv) < 1)
goto err;
+ atomic_set(&bat_priv->gw_reselect, 0);
atomic_set(&bat_priv->mesh_state, MESH_ACTIVE);
goto end;
err:
- pr_err("Unable to allocate memory for mesh information structures: "
- "out of mem ?\n");
mesh_free(soft_iface);
return -1;
@@ -137,8 +137,7 @@ void mesh_free(struct net_device *soft_iface)
gw_node_purge(bat_priv);
originator_free(bat_priv);
- tt_local_free(bat_priv);
- tt_global_free(bat_priv);
+ tt_free(bat_priv);
softif_neigh_purge(bat_priv);
@@ -155,9 +154,9 @@ void dec_module_count(void)
module_put(THIS_MODULE);
}
-int is_my_mac(uint8_t *addr)
+int is_my_mac(const uint8_t *addr)
{
- struct hard_iface *hard_iface;
+ const struct hard_iface *hard_iface;
rcu_read_lock();
list_for_each_entry_rcu(hard_iface, &hardif_list, list) {
@@ -182,8 +181,4 @@ MODULE_LICENSE("GPL");
MODULE_AUTHOR(DRIVER_AUTHOR);
MODULE_DESCRIPTION(DRIVER_DESC);
MODULE_SUPPORTED_DEVICE(DRIVER_DEVICE);
-#ifdef REVISION_VERSION
-MODULE_VERSION(SOURCE_VERSION "-" REVISION_VERSION);
-#else
MODULE_VERSION(SOURCE_VERSION);
-#endif
diff --git a/net/batman-adv/main.h b/net/batman-adv/main.h
index 148b49e..964ad4d 100644
--- a/net/batman-adv/main.h
+++ b/net/batman-adv/main.h
@@ -27,8 +27,9 @@
#define DRIVER_DESC "B.A.T.M.A.N. advanced"
#define DRIVER_DEVICE "batman-adv"
-#define SOURCE_VERSION "next"
-
+#ifndef SOURCE_VERSION
+#define SOURCE_VERSION "2011.4.0"
+#endif
/* B.A.T.M.A.N. parameters */
@@ -42,15 +43,27 @@
* -> TODO: check influence on TQ_LOCAL_WINDOW_SIZE */
#define PURGE_TIMEOUT 200
#define TT_LOCAL_TIMEOUT 3600 /* in seconds */
-
-/* sliding packet range of received originator messages in squence numbers
+#define TT_CLIENT_ROAM_TIMEOUT 600
+/* sliding packet range of received originator messages in sequence numbers
* (should be a multiple of our word size) */
#define TQ_LOCAL_WINDOW_SIZE 64
+#define TT_REQUEST_TIMEOUT 3 /* seconds we have to keep pending tt_req */
+
#define TQ_GLOBAL_WINDOW_SIZE 5
#define TQ_LOCAL_BIDRECT_SEND_MINIMUM 1
#define TQ_LOCAL_BIDRECT_RECV_MINIMUM 1
#define TQ_TOTAL_BIDRECT_LIMIT 1
+#define TT_OGM_APPEND_MAX 3 /* number of OGMs sent with the last tt diff */
+
+#define ROAMING_MAX_TIME 20 /* Time in which a client can roam at most
+ * ROAMING_MAX_COUNT times */
+#define ROAMING_MAX_COUNT 5
+
+#define NO_FLAGS 0
+
+#define NULL_IFINDEX 0 /* dummy ifindex used to avoid iface checks */
+
#define NUM_WORDS (TQ_LOCAL_WINDOW_SIZE / WORD_BIT_SIZE)
#define LOG_BUF_LEN 8192 /* has to be a power of 2 */
@@ -72,13 +85,27 @@
#define RESET_PROTECTION_MS 30000
#define EXPECTED_SEQNO_RANGE 65536
-#define MESH_INACTIVE 0
-#define MESH_ACTIVE 1
-#define MESH_DEACTIVATING 2
+enum mesh_state {
+ MESH_INACTIVE,
+ MESH_ACTIVE,
+ MESH_DEACTIVATING
+};
#define BCAST_QUEUE_LEN 256
#define BATMAN_QUEUE_LEN 256
+enum uev_action {
+ UEV_ADD = 0,
+ UEV_DEL,
+ UEV_CHANGE
+};
+
+enum uev_type {
+ UEV_GW = 0
+};
+
+#define GW_THRESHOLD 50
+
/*
* Debug Messages
*/
@@ -89,10 +116,12 @@
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
/* all messages related to routing / flooding / broadcasting / etc */
-#define DBG_BATMAN 1
-/* route or tt entry added / changed / deleted */
-#define DBG_ROUTES 2
-#define DBG_ALL 3
+enum dbg_level {
+ DBG_BATMAN = 1 << 0,
+ DBG_ROUTES = 1 << 1, /* route added / changed / deleted */
+ DBG_TT = 1 << 2, /* translation table operations */
+ DBG_ALL = 7
+};
/*
@@ -106,7 +135,7 @@
#include <linux/mutex.h> /* mutex */
#include <linux/module.h> /* needed by all modules */
#include <linux/netdevice.h> /* netdevice */
-#include <linux/etherdevice.h> /* ethernet address classifaction */
+#include <linux/etherdevice.h> /* ethernet address classification */
#include <linux/if_ether.h> /* ethernet header */
#include <linux/poll.h> /* poll_table */
#include <linux/kthread.h> /* kernel threads */
@@ -118,12 +147,6 @@
#include <linux/seq_file.h>
#include "types.h"
-#ifndef REVISION_VERSION
-#define REVISION_VERSION_STR ""
-#else
-#define REVISION_VERSION_STR " "REVISION_VERSION
-#endif
-
extern struct list_head hardif_list;
extern unsigned char broadcast_addr[];
@@ -133,10 +156,10 @@ int mesh_init(struct net_device *soft_iface);
void mesh_free(struct net_device *soft_iface);
void inc_module_count(void);
void dec_module_count(void);
-int is_my_mac(uint8_t *addr);
+int is_my_mac(const uint8_t *addr);
#ifdef CONFIG_BATMAN_ADV_DEBUG
-int debug_log(struct bat_priv *bat_priv, char *fmt, ...);
+int debug_log(struct bat_priv *bat_priv, const char *fmt, ...) __printf(2, 3);
#define bat_dbg(type, bat_priv, fmt, arg...) \
do { \
@@ -145,9 +168,10 @@ int debug_log(struct bat_priv *bat_priv, char *fmt, ...);
} \
while (0)
#else /* !CONFIG_BATMAN_ADV_DEBUG */
-static inline void bat_dbg(char type __always_unused,
+__printf(3, 4)
+static inline void bat_dbg(int type __always_unused,
struct bat_priv *bat_priv __always_unused,
- char *fmt __always_unused, ...)
+ const char *fmt __always_unused, ...)
{
}
#endif
@@ -172,11 +196,32 @@ static inline void bat_dbg(char type __always_unused,
*
* note: can't use compare_ether_addr() as it requires aligned memory
*/
-static inline int compare_eth(void *data1, void *data2)
+
+static inline int compare_eth(const void *data1, const void *data2)
{
return (memcmp(data1, data2, ETH_ALEN) == 0 ? 1 : 0);
}
+
#define atomic_dec_not_zero(v) atomic_add_unless((v), -1, 0)
+/* Returns the smallest signed integer in two's complement with the sizeof x */
+#define smallest_signed_int(x) (1u << (7u + 8u * (sizeof(x) - 1u)))
+
+/* Checks if a sequence number x is a predecessor/successor of y.
+ * they handle overflows/underflows and can correctly check for a
+ * predecessor/successor unless the variable sequence number has grown by
+ * more then 2**(bitwidth(x)-1)-1.
+ * This means that for a uint8_t with the maximum value 255, it would think:
+ * - when adding nothing - it is neither a predecessor nor a successor
+ * - before adding more than 127 to the starting value - it is a predecessor,
+ * - when adding 128 - it is neither a predecessor nor a successor,
+ * - after adding more than 127 to the starting value - it is a successor */
+#define seq_before(x, y) ({typeof(x) _d1 = (x); \
+ typeof(y) _d2 = (y); \
+ typeof(x) _dummy = (_d1 - _d2); \
+ (void) (&_d1 == &_d2); \
+ _dummy > smallest_signed_int(_dummy); })
+#define seq_after(x, y) seq_before(y, x)
+
#endif /* _NET_BATMAN_ADV_MAIN_H_ */
diff --git a/net/batman-adv/originator.c b/net/batman-adv/originator.c
index 40a30bb..0e5b772 100644
--- a/net/batman-adv/originator.c
+++ b/net/batman-adv/originator.c
@@ -37,6 +37,14 @@ static void start_purge_timer(struct bat_priv *bat_priv)
queue_delayed_work(bat_event_workqueue, &bat_priv->orig_work, 1 * HZ);
}
+/* returns 1 if they are the same originator */
+static int compare_orig(const struct hlist_node *node, const void *data2)
+{
+ const void *data1 = container_of(node, struct orig_node, hash_entry);
+
+ return (memcmp(data1, data2, ETH_ALEN) == 0 ? 1 : 0);
+}
+
int originator_init(struct bat_priv *bat_priv)
{
if (bat_priv->orig_hash)
@@ -77,7 +85,7 @@ struct neigh_node *orig_node_get_router(struct orig_node *orig_node)
struct neigh_node *create_neighbor(struct orig_node *orig_node,
struct orig_node *orig_neigh_node,
- uint8_t *neigh,
+ const uint8_t *neigh,
struct hard_iface *if_incoming)
{
struct bat_priv *bat_priv = netdev_priv(if_incoming->soft_iface);
@@ -86,7 +94,7 @@ struct neigh_node *create_neighbor(struct orig_node *orig_node,
bat_dbg(DBG_BATMAN, bat_priv,
"Creating new last-hop neighbor of originator\n");
- neigh_node = kzalloc(sizeof(struct neigh_node), GFP_ATOMIC);
+ neigh_node = kzalloc(sizeof(*neigh_node), GFP_ATOMIC);
if (!neigh_node)
return NULL;
@@ -137,6 +145,7 @@ static void orig_node_free_rcu(struct rcu_head *rcu)
tt_global_del_orig(orig_node->bat_priv, orig_node,
"originator timed out");
+ kfree(orig_node->tt_buff);
kfree(orig_node->bcast_own);
kfree(orig_node->bcast_own_sum);
kfree(orig_node);
@@ -183,7 +192,7 @@ void originator_free(struct bat_priv *bat_priv)
/* this function finds or creates an originator entry for the given
* address if it does not exits */
-struct orig_node *get_orig_node(struct bat_priv *bat_priv, uint8_t *addr)
+struct orig_node *get_orig_node(struct bat_priv *bat_priv, const uint8_t *addr)
{
struct orig_node *orig_node;
int size;
@@ -196,7 +205,7 @@ struct orig_node *get_orig_node(struct bat_priv *bat_priv, uint8_t *addr)
bat_dbg(DBG_BATMAN, bat_priv,
"Creating new originator: %pM\n", addr);
- orig_node = kzalloc(sizeof(struct orig_node), GFP_ATOMIC);
+ orig_node = kzalloc(sizeof(*orig_node), GFP_ATOMIC);
if (!orig_node)
return NULL;
@@ -205,14 +214,20 @@ struct orig_node *get_orig_node(struct bat_priv *bat_priv, uint8_t *addr)
spin_lock_init(&orig_node->ogm_cnt_lock);
spin_lock_init(&orig_node->bcast_seqno_lock);
spin_lock_init(&orig_node->neigh_list_lock);
+ spin_lock_init(&orig_node->tt_buff_lock);
/* extra reference for return */
atomic_set(&orig_node->refcount, 2);
+ orig_node->tt_poss_change = false;
orig_node->bat_priv = bat_priv;
memcpy(orig_node->orig, addr, ETH_ALEN);
orig_node->router = NULL;
+ orig_node->tt_crc = 0;
+ atomic_set(&orig_node->last_ttvn, 0);
orig_node->tt_buff = NULL;
+ orig_node->tt_buff_len = 0;
+ atomic_set(&orig_node->tt_size, 0);
orig_node->bcast_seqno_reset = jiffies - 1
- msecs_to_jiffies(RESET_PROTECTION_MS);
orig_node->batman_seqno_reset = jiffies - 1
@@ -237,7 +252,7 @@ struct orig_node *get_orig_node(struct bat_priv *bat_priv, uint8_t *addr)
hash_added = hash_add(bat_priv->orig_hash, compare_orig,
choose_orig, orig_node, &orig_node->hash_entry);
- if (hash_added < 0)
+ if (hash_added != 0)
goto free_bcast_own_sum;
return orig_node;
@@ -321,10 +336,7 @@ static bool purge_orig_node(struct bat_priv *bat_priv,
} else {
if (purge_orig_neighbors(bat_priv, orig_node,
&best_neigh_node)) {
- update_routes(bat_priv, orig_node,
- best_neigh_node,
- orig_node->tt_buff,
- orig_node->tt_buff_len);
+ update_route(bat_priv, orig_node, best_neigh_node);
}
}
@@ -419,9 +431,8 @@ int orig_seq_print_text(struct seq_file *seq, void *offset)
goto out;
}
- seq_printf(seq, "[B.A.T.M.A.N. adv %s%s, MainIF/MAC: %s/%pM (%s)]\n",
- SOURCE_VERSION, REVISION_VERSION_STR,
- primary_if->net_dev->name,
+ seq_printf(seq, "[B.A.T.M.A.N. adv %s, MainIF/MAC: %s/%pM (%s)]\n",
+ SOURCE_VERSION, primary_if->net_dev->name,
primary_if->net_dev->dev_addr, net_dev->name);
seq_printf(seq, " %-15s %s (%s/%i) %17s [%10s]: %20s ...\n",
"Originator", "last-seen", "#", TQ_MAX_VALUE, "Nexthop",
@@ -481,10 +492,8 @@ static int orig_node_add_if(struct orig_node *orig_node, int max_if_num)
data_ptr = kmalloc(max_if_num * sizeof(unsigned long) * NUM_WORDS,
GFP_ATOMIC);
- if (!data_ptr) {
- pr_err("Can't resize orig: out of memory\n");
+ if (!data_ptr)
return -1;
- }
memcpy(data_ptr, orig_node->bcast_own,
(max_if_num - 1) * sizeof(unsigned long) * NUM_WORDS);
@@ -492,10 +501,8 @@ static int orig_node_add_if(struct orig_node *orig_node, int max_if_num)
orig_node->bcast_own = data_ptr;
data_ptr = kmalloc(max_if_num * sizeof(uint8_t), GFP_ATOMIC);
- if (!data_ptr) {
- pr_err("Can't resize orig: out of memory\n");
+ if (!data_ptr)
return -1;
- }
memcpy(data_ptr, orig_node->bcast_own_sum,
(max_if_num - 1) * sizeof(uint8_t));
@@ -550,16 +557,14 @@ static int orig_node_del_if(struct orig_node *orig_node,
chunk_size = sizeof(unsigned long) * NUM_WORDS;
data_ptr = kmalloc(max_if_num * chunk_size, GFP_ATOMIC);
- if (!data_ptr) {
- pr_err("Can't resize orig: out of memory\n");
+ if (!data_ptr)
return -1;
- }
/* copy first part */
memcpy(data_ptr, orig_node->bcast_own, del_if_num * chunk_size);
/* copy second part */
- memcpy(data_ptr + del_if_num * chunk_size,
+ memcpy((char *)data_ptr + del_if_num * chunk_size,
orig_node->bcast_own + ((del_if_num + 1) * chunk_size),
(max_if_num - del_if_num) * chunk_size);
@@ -571,15 +576,13 @@ free_bcast_own:
goto free_own_sum;
data_ptr = kmalloc(max_if_num * sizeof(uint8_t), GFP_ATOMIC);
- if (!data_ptr) {
- pr_err("Can't resize orig: out of memory\n");
+ if (!data_ptr)
return -1;
- }
memcpy(data_ptr, orig_node->bcast_own_sum,
del_if_num * sizeof(uint8_t));
- memcpy(data_ptr + del_if_num * sizeof(uint8_t),
+ memcpy((char *)data_ptr + del_if_num * sizeof(uint8_t),
orig_node->bcast_own_sum + ((del_if_num + 1) * sizeof(uint8_t)),
(max_if_num - del_if_num) * sizeof(uint8_t));
diff --git a/net/batman-adv/originator.h b/net/batman-adv/originator.h
index e1d641f..cfc1f60 100644
--- a/net/batman-adv/originator.h
+++ b/net/batman-adv/originator.h
@@ -28,10 +28,10 @@ int originator_init(struct bat_priv *bat_priv);
void originator_free(struct bat_priv *bat_priv);
void purge_orig_ref(struct bat_priv *bat_priv);
void orig_node_free_ref(struct orig_node *orig_node);
-struct orig_node *get_orig_node(struct bat_priv *bat_priv, uint8_t *addr);
+struct orig_node *get_orig_node(struct bat_priv *bat_priv, const uint8_t *addr);
struct neigh_node *create_neighbor(struct orig_node *orig_node,
struct orig_node *orig_neigh_node,
- uint8_t *neigh,
+ const uint8_t *neigh,
struct hard_iface *if_incoming);
void neigh_node_free_ref(struct neigh_node *neigh_node);
struct neigh_node *orig_node_get_router(struct orig_node *orig_node);
@@ -40,19 +40,11 @@ int orig_hash_add_if(struct hard_iface *hard_iface, int max_if_num);
int orig_hash_del_if(struct hard_iface *hard_iface, int max_if_num);
-/* returns 1 if they are the same originator */
-static inline int compare_orig(struct hlist_node *node, void *data2)
-{
- void *data1 = container_of(node, struct orig_node, hash_entry);
-
- return (memcmp(data1, data2, ETH_ALEN) == 0 ? 1 : 0);
-}
-
/* hashfunction to choose an entry in a hash table of given size */
/* hash algorithm from http://en.wikipedia.org/wiki/Hash_table */
-static inline int choose_orig(void *data, int32_t size)
+static inline int choose_orig(const void *data, int32_t size)
{
- unsigned char *key = data;
+ const unsigned char *key = data;
uint32_t hash = 0;
size_t i;
@@ -70,7 +62,7 @@ static inline int choose_orig(void *data, int32_t size)
}
static inline struct orig_node *orig_hash_find(struct bat_priv *bat_priv,
- void *data)
+ const void *data)
{
struct hashtable_t *hash = bat_priv->orig_hash;
struct hlist_head *head;
diff --git a/net/batman-adv/packet.h b/net/batman-adv/packet.h
index eda9965..4d9e54c 100644
--- a/net/batman-adv/packet.h
+++ b/net/batman-adv/packet.h
@@ -24,59 +24,99 @@
#define ETH_P_BATMAN 0x4305 /* unofficial/not registered Ethertype */
-#define BAT_PACKET 0x01
-#define BAT_ICMP 0x02
-#define BAT_UNICAST 0x03
-#define BAT_BCAST 0x04
-#define BAT_VIS 0x05
-#define BAT_UNICAST_FRAG 0x06
+enum bat_packettype {
+ BAT_OGM = 0x01,
+ BAT_ICMP = 0x02,
+ BAT_UNICAST = 0x03,
+ BAT_BCAST = 0x04,
+ BAT_VIS = 0x05,
+ BAT_UNICAST_FRAG = 0x06,
+ BAT_TT_QUERY = 0x07,
+ BAT_ROAM_ADV = 0x08
+};
/* this file is included by batctl which needs these defines */
-#define COMPAT_VERSION 12
-#define DIRECTLINK 0x40
-#define VIS_SERVER 0x20
-#define PRIMARIES_FIRST_HOP 0x10
+#define COMPAT_VERSION 14
+
+enum batman_flags {
+ PRIMARIES_FIRST_HOP = 1 << 4,
+ VIS_SERVER = 1 << 5,
+ DIRECTLINK = 1 << 6
+};
/* ICMP message types */
-#define ECHO_REPLY 0
-#define DESTINATION_UNREACHABLE 3
-#define ECHO_REQUEST 8
-#define TTL_EXCEEDED 11
-#define PARAMETER_PROBLEM 12
+enum icmp_packettype {
+ ECHO_REPLY = 0,
+ DESTINATION_UNREACHABLE = 3,
+ ECHO_REQUEST = 8,
+ TTL_EXCEEDED = 11,
+ PARAMETER_PROBLEM = 12
+};
/* vis defines */
-#define VIS_TYPE_SERVER_SYNC 0
-#define VIS_TYPE_CLIENT_UPDATE 1
+enum vis_packettype {
+ VIS_TYPE_SERVER_SYNC = 0,
+ VIS_TYPE_CLIENT_UPDATE = 1
+};
/* fragmentation defines */
-#define UNI_FRAG_HEAD 0x01
-#define UNI_FRAG_LARGETAIL 0x02
-
-struct batman_packet {
+enum unicast_frag_flags {
+ UNI_FRAG_HEAD = 1 << 0,
+ UNI_FRAG_LARGETAIL = 1 << 1
+};
+
+/* TT_QUERY subtypes */
+#define TT_QUERY_TYPE_MASK 0x3
+
+enum tt_query_packettype {
+ TT_REQUEST = 0,
+ TT_RESPONSE = 1
+};
+
+/* TT_QUERY flags */
+enum tt_query_flags {
+ TT_FULL_TABLE = 1 << 2
+};
+
+/* TT_CLIENT flags.
+ * Flags from 1 to 1 << 7 are sent on the wire, while flags from 1 << 8 to
+ * 1 << 15 are used for local computation only */
+enum tt_client_flags {
+ TT_CLIENT_DEL = 1 << 0,
+ TT_CLIENT_ROAM = 1 << 1,
+ TT_CLIENT_WIFI = 1 << 2,
+ TT_CLIENT_NOPURGE = 1 << 8,
+ TT_CLIENT_NEW = 1 << 9,
+ TT_CLIENT_PENDING = 1 << 10
+};
+
+struct batman_ogm_packet {
uint8_t packet_type;
uint8_t version; /* batman version field */
+ uint8_t ttl;
uint8_t flags; /* 0x40: DIRECTLINK flag, 0x20 VIS_SERVER flag... */
- uint8_t tq;
uint32_t seqno;
uint8_t orig[6];
uint8_t prev_sender[6];
- uint8_t ttl;
- uint8_t num_tt;
uint8_t gw_flags; /* flags related to gateway class */
- uint8_t align;
+ uint8_t tq;
+ uint8_t tt_num_changes;
+ uint8_t ttvn; /* translation table version number */
+ uint16_t tt_crc;
} __packed;
-#define BAT_PACKET_LEN sizeof(struct batman_packet)
+#define BATMAN_OGM_LEN sizeof(struct batman_ogm_packet)
struct icmp_packet {
uint8_t packet_type;
uint8_t version; /* batman version field */
- uint8_t msg_type; /* see ICMP message types above */
uint8_t ttl;
+ uint8_t msg_type; /* see ICMP message types above */
uint8_t dst[6];
uint8_t orig[6];
uint16_t seqno;
uint8_t uid;
+ uint8_t reserved;
} __packed;
#define BAT_RR_LEN 16
@@ -86,8 +126,8 @@ struct icmp_packet {
struct icmp_packet_rr {
uint8_t packet_type;
uint8_t version; /* batman version field */
- uint8_t msg_type; /* see ICMP message types above */
uint8_t ttl;
+ uint8_t msg_type; /* see ICMP message types above */
uint8_t dst[6];
uint8_t orig[6];
uint16_t seqno;
@@ -99,16 +139,19 @@ struct icmp_packet_rr {
struct unicast_packet {
uint8_t packet_type;
uint8_t version; /* batman version field */
- uint8_t dest[6];
uint8_t ttl;
+ uint8_t ttvn; /* destination translation table version number */
+ uint8_t dest[6];
} __packed;
struct unicast_frag_packet {
uint8_t packet_type;
uint8_t version; /* batman version field */
- uint8_t dest[6];
uint8_t ttl;
+ uint8_t ttvn; /* destination translation table version number */
+ uint8_t dest[6];
uint8_t flags;
+ uint8_t align;
uint8_t orig[6];
uint16_t seqno;
} __packed;
@@ -116,21 +159,61 @@ struct unicast_frag_packet {
struct bcast_packet {
uint8_t packet_type;
uint8_t version; /* batman version field */
- uint8_t orig[6];
uint8_t ttl;
+ uint8_t reserved;
uint32_t seqno;
+ uint8_t orig[6];
} __packed;
struct vis_packet {
uint8_t packet_type;
uint8_t version; /* batman version field */
+ uint8_t ttl; /* TTL */
uint8_t vis_type; /* which type of vis-participant sent this? */
- uint8_t entries; /* number of entries behind this struct */
uint32_t seqno; /* sequence number */
- uint8_t ttl; /* TTL */
+ uint8_t entries; /* number of entries behind this struct */
+ uint8_t reserved;
uint8_t vis_orig[6]; /* originator that announces its neighbors */
uint8_t target_orig[6]; /* who should receive this packet */
uint8_t sender_orig[6]; /* who sent or rebroadcasted this packet */
} __packed;
+struct tt_query_packet {
+ uint8_t packet_type;
+ uint8_t version; /* batman version field */
+ uint8_t ttl;
+ /* the flag field is a combination of:
+ * - TT_REQUEST or TT_RESPONSE
+ * - TT_FULL_TABLE */
+ uint8_t flags;
+ uint8_t dst[ETH_ALEN];
+ uint8_t src[ETH_ALEN];
+ /* the ttvn field is:
+ * if TT_REQUEST: ttvn that triggered the
+ * request
+ * if TT_RESPONSE: new ttvn for the src
+ * orig_node */
+ uint8_t ttvn;
+ /* tt_data field is:
+ * if TT_REQUEST: crc associated with the
+ * ttvn
+ * if TT_RESPONSE: table_size */
+ uint16_t tt_data;
+} __packed;
+
+struct roam_adv_packet {
+ uint8_t packet_type;
+ uint8_t version;
+ uint8_t ttl;
+ uint8_t reserved;
+ uint8_t dst[ETH_ALEN];
+ uint8_t src[ETH_ALEN];
+ uint8_t client[ETH_ALEN];
+} __packed;
+
+struct tt_change {
+ uint8_t flags;
+ uint8_t addr[ETH_ALEN];
+} __packed;
+
#endif /* _NET_BATMAN_ADV_PACKET_H_ */
diff --git a/net/batman-adv/ring_buffer.c b/net/batman-adv/ring_buffer.c
index 5bb6a61..f1ccfa7 100644
--- a/net/batman-adv/ring_buffer.c
+++ b/net/batman-adv/ring_buffer.c
@@ -28,9 +28,9 @@ void ring_buffer_set(uint8_t lq_recv[], uint8_t *lq_index, uint8_t value)
*lq_index = (*lq_index + 1) % TQ_GLOBAL_WINDOW_SIZE;
}
-uint8_t ring_buffer_avg(uint8_t lq_recv[])
+uint8_t ring_buffer_avg(const uint8_t lq_recv[])
{
- uint8_t *ptr;
+ const uint8_t *ptr;
uint16_t count = 0, i = 0, sum = 0;
ptr = lq_recv;
diff --git a/net/batman-adv/ring_buffer.h b/net/batman-adv/ring_buffer.h
index 0395b27..7cdfe62 100644
--- a/net/batman-adv/ring_buffer.h
+++ b/net/batman-adv/ring_buffer.h
@@ -23,6 +23,6 @@
#define _NET_BATMAN_ADV_RING_BUFFER_H_
void ring_buffer_set(uint8_t lq_recv[], uint8_t *lq_index, uint8_t value);
-uint8_t ring_buffer_avg(uint8_t lq_recv[]);
+uint8_t ring_buffer_avg(const uint8_t lq_recv[]);
#endif /* _NET_BATMAN_ADV_RING_BUFFER_H_ */
diff --git a/net/batman-adv/routing.c b/net/batman-adv/routing.c
index bb1c3ec..da587ad 100644
--- a/net/batman-adv/routing.c
+++ b/net/batman-adv/routing.c
@@ -22,18 +22,14 @@
#include "main.h"
#include "routing.h"
#include "send.h"
-#include "hash.h"
#include "soft-interface.h"
#include "hard-interface.h"
#include "icmp_socket.h"
#include "translation-table.h"
#include "originator.h"
-#include "ring_buffer.h"
#include "vis.h"
-#include "aggregation.h"
-#include "gateway_common.h"
-#include "gateway_client.h"
#include "unicast.h"
+#include "bat_ogm.h"
void slide_own_bcast_window(struct hard_iface *hard_iface)
{
@@ -64,28 +60,9 @@ void slide_own_bcast_window(struct hard_iface *hard_iface)
}
}
-static void update_TT(struct bat_priv *bat_priv, struct orig_node *orig_node,
- unsigned char *tt_buff, int tt_buff_len)
-{
- if ((tt_buff_len != orig_node->tt_buff_len) ||
- ((tt_buff_len > 0) &&
- (orig_node->tt_buff_len > 0) &&
- (memcmp(orig_node->tt_buff, tt_buff, tt_buff_len) != 0))) {
-
- if (orig_node->tt_buff_len > 0)
- tt_global_del_orig(bat_priv, orig_node,
- "originator changed tt");
-
- if ((tt_buff_len > 0) && (tt_buff))
- tt_global_add_orig(bat_priv, orig_node,
- tt_buff, tt_buff_len);
- }
-}
-
-static void update_route(struct bat_priv *bat_priv,
- struct orig_node *orig_node,
- struct neigh_node *neigh_node,
- unsigned char *tt_buff, int tt_buff_len)
+static void _update_route(struct bat_priv *bat_priv,
+ struct orig_node *orig_node,
+ struct neigh_node *neigh_node)
{
struct neigh_node *curr_router;
@@ -93,11 +70,10 @@ static void update_route(struct bat_priv *bat_priv,
/* route deleted */
if ((curr_router) && (!neigh_node)) {
-
bat_dbg(DBG_ROUTES, bat_priv, "Deleting route towards: %pM\n",
orig_node->orig);
tt_global_del_orig(bat_priv, orig_node,
- "originator timed out");
+ "Deleted route towards originator");
/* route added */
} else if ((!curr_router) && (neigh_node)) {
@@ -105,11 +81,8 @@ static void update_route(struct bat_priv *bat_priv,
bat_dbg(DBG_ROUTES, bat_priv,
"Adding route towards: %pM (via %pM)\n",
orig_node->orig, neigh_node->addr);
- tt_global_add_orig(bat_priv, orig_node,
- tt_buff, tt_buff_len);
-
/* route changed */
- } else {
+ } else if (neigh_node && curr_router) {
bat_dbg(DBG_ROUTES, bat_priv,
"Changing route towards: %pM "
"(now via %pM - was via %pM)\n",
@@ -133,10 +106,8 @@ static void update_route(struct bat_priv *bat_priv,
neigh_node_free_ref(curr_router);
}
-
-void update_routes(struct bat_priv *bat_priv, struct orig_node *orig_node,
- struct neigh_node *neigh_node, unsigned char *tt_buff,
- int tt_buff_len)
+void update_route(struct bat_priv *bat_priv, struct orig_node *orig_node,
+ struct neigh_node *neigh_node)
{
struct neigh_node *router = NULL;
@@ -146,120 +117,13 @@ void update_routes(struct bat_priv *bat_priv, struct orig_node *orig_node,
router = orig_node_get_router(orig_node);
if (router != neigh_node)
- update_route(bat_priv, orig_node, neigh_node,
- tt_buff, tt_buff_len);
- /* may be just TT changed */
- else
- update_TT(bat_priv, orig_node, tt_buff, tt_buff_len);
+ _update_route(bat_priv, orig_node, neigh_node);
out:
if (router)
neigh_node_free_ref(router);
}
-static int is_bidirectional_neigh(struct orig_node *orig_node,
- struct orig_node *orig_neigh_node,
- struct batman_packet *batman_packet,
- struct hard_iface *if_incoming)
-{
- struct bat_priv *bat_priv = netdev_priv(if_incoming->soft_iface);
- struct neigh_node *neigh_node = NULL, *tmp_neigh_node;
- struct hlist_node *node;
- unsigned char total_count;
- uint8_t orig_eq_count, neigh_rq_count, tq_own;
- int tq_asym_penalty, ret = 0;
-
- /* find corresponding one hop neighbor */
- rcu_read_lock();
- hlist_for_each_entry_rcu(tmp_neigh_node, node,
- &orig_neigh_node->neigh_list, list) {
-
- if (!compare_eth(tmp_neigh_node->addr, orig_neigh_node->orig))
- continue;
-
- if (tmp_neigh_node->if_incoming != if_incoming)
- continue;
-
- if (!atomic_inc_not_zero(&tmp_neigh_node->refcount))
- continue;
-
- neigh_node = tmp_neigh_node;
- break;
- }
- rcu_read_unlock();
-
- if (!neigh_node)
- neigh_node = create_neighbor(orig_neigh_node,
- orig_neigh_node,
- orig_neigh_node->orig,
- if_incoming);
-
- if (!neigh_node)
- goto out;
-
- /* if orig_node is direct neighbour update neigh_node last_valid */
- if (orig_node == orig_neigh_node)
- neigh_node->last_valid = jiffies;
-
- orig_node->last_valid = jiffies;
-
- /* find packet count of corresponding one hop neighbor */
- spin_lock_bh(&orig_node->ogm_cnt_lock);
- orig_eq_count = orig_neigh_node->bcast_own_sum[if_incoming->if_num];
- neigh_rq_count = neigh_node->real_packet_count;
- spin_unlock_bh(&orig_node->ogm_cnt_lock);
-
- /* pay attention to not get a value bigger than 100 % */
- total_count = (orig_eq_count > neigh_rq_count ?
- neigh_rq_count : orig_eq_count);
-
- /* if we have too few packets (too less data) we set tq_own to zero */
- /* if we receive too few packets it is not considered bidirectional */
- if ((total_count < TQ_LOCAL_BIDRECT_SEND_MINIMUM) ||
- (neigh_rq_count < TQ_LOCAL_BIDRECT_RECV_MINIMUM))
- tq_own = 0;
- else
- /* neigh_node->real_packet_count is never zero as we
- * only purge old information when getting new
- * information */
- tq_own = (TQ_MAX_VALUE * total_count) / neigh_rq_count;
-
- /*
- * 1 - ((1-x) ** 3), normalized to TQ_MAX_VALUE this does
- * affect the nearly-symmetric links only a little, but
- * punishes asymmetric links more. This will give a value
- * between 0 and TQ_MAX_VALUE
- */
- tq_asym_penalty = TQ_MAX_VALUE - (TQ_MAX_VALUE *
- (TQ_LOCAL_WINDOW_SIZE - neigh_rq_count) *
- (TQ_LOCAL_WINDOW_SIZE - neigh_rq_count) *
- (TQ_LOCAL_WINDOW_SIZE - neigh_rq_count)) /
- (TQ_LOCAL_WINDOW_SIZE *
- TQ_LOCAL_WINDOW_SIZE *
- TQ_LOCAL_WINDOW_SIZE);
-
- batman_packet->tq = ((batman_packet->tq * tq_own * tq_asym_penalty) /
- (TQ_MAX_VALUE * TQ_MAX_VALUE));
-
- bat_dbg(DBG_BATMAN, bat_priv,
- "bidirectional: "
- "orig = %-15pM neigh = %-15pM => own_bcast = %2i, "
- "real recv = %2i, local tq: %3i, asym_penalty: %3i, "
- "total tq: %3i\n",
- orig_node->orig, orig_neigh_node->orig, total_count,
- neigh_rq_count, tq_own, tq_asym_penalty, batman_packet->tq);
-
- /* if link has the minimum required transmission quality
- * consider it bidirectional */
- if (batman_packet->tq >= TQ_TOTAL_BIDRECT_LIMIT)
- ret = 1;
-
-out:
- if (neigh_node)
- neigh_node_free_ref(neigh_node);
- return ret;
-}
-
/* caller must hold the neigh_list_lock */
void bonding_candidate_del(struct orig_node *orig_node,
struct neigh_node *neigh_node)
@@ -277,8 +141,8 @@ out:
return;
}
-static void bonding_candidate_add(struct orig_node *orig_node,
- struct neigh_node *neigh_node)
+void bonding_candidate_add(struct orig_node *orig_node,
+ struct neigh_node *neigh_node)
{
struct hlist_node *node;
struct neigh_node *tmp_neigh_node, *router = NULL;
@@ -348,164 +212,23 @@ out:
}
/* copy primary address for bonding */
-static void bonding_save_primary(struct orig_node *orig_node,
- struct orig_node *orig_neigh_node,
- struct batman_packet *batman_packet)
+void bonding_save_primary(const struct orig_node *orig_node,
+ struct orig_node *orig_neigh_node,
+ const struct batman_ogm_packet *batman_ogm_packet)
{
- if (!(batman_packet->flags & PRIMARIES_FIRST_HOP))
+ if (!(batman_ogm_packet->flags & PRIMARIES_FIRST_HOP))
return;
memcpy(orig_neigh_node->primary_addr, orig_node->orig, ETH_ALEN);
}
-static void update_orig(struct bat_priv *bat_priv,
- struct orig_node *orig_node,
- struct ethhdr *ethhdr,
- struct batman_packet *batman_packet,
- struct hard_iface *if_incoming,
- unsigned char *tt_buff, int tt_buff_len,
- char is_duplicate)
-{
- struct neigh_node *neigh_node = NULL, *tmp_neigh_node = NULL;
- struct neigh_node *router = NULL;
- struct orig_node *orig_node_tmp;
- struct hlist_node *node;
- int tmp_tt_buff_len;
- uint8_t bcast_own_sum_orig, bcast_own_sum_neigh;
-
- bat_dbg(DBG_BATMAN, bat_priv, "update_originator(): "
- "Searching and updating originator entry of received packet\n");
-
- rcu_read_lock();
- hlist_for_each_entry_rcu(tmp_neigh_node, node,
- &orig_node->neigh_list, list) {
- if (compare_eth(tmp_neigh_node->addr, ethhdr->h_source) &&
- (tmp_neigh_node->if_incoming == if_incoming) &&
- atomic_inc_not_zero(&tmp_neigh_node->refcount)) {
- if (neigh_node)
- neigh_node_free_ref(neigh_node);
- neigh_node = tmp_neigh_node;
- continue;
- }
-
- if (is_duplicate)
- continue;
-
- spin_lock_bh(&tmp_neigh_node->tq_lock);
- ring_buffer_set(tmp_neigh_node->tq_recv,
- &tmp_neigh_node->tq_index, 0);
- tmp_neigh_node->tq_avg =
- ring_buffer_avg(tmp_neigh_node->tq_recv);
- spin_unlock_bh(&tmp_neigh_node->tq_lock);
- }
-
- if (!neigh_node) {
- struct orig_node *orig_tmp;
-
- orig_tmp = get_orig_node(bat_priv, ethhdr->h_source);
- if (!orig_tmp)
- goto unlock;
-
- neigh_node = create_neighbor(orig_node, orig_tmp,
- ethhdr->h_source, if_incoming);
-
- orig_node_free_ref(orig_tmp);
- if (!neigh_node)
- goto unlock;
- } else
- bat_dbg(DBG_BATMAN, bat_priv,
- "Updating existing last-hop neighbor of originator\n");
-
- rcu_read_unlock();
-
- orig_node->flags = batman_packet->flags;
- neigh_node->last_valid = jiffies;
-
- spin_lock_bh(&neigh_node->tq_lock);
- ring_buffer_set(neigh_node->tq_recv,
- &neigh_node->tq_index,
- batman_packet->tq);
- neigh_node->tq_avg = ring_buffer_avg(neigh_node->tq_recv);
- spin_unlock_bh(&neigh_node->tq_lock);
-
- if (!is_duplicate) {
- orig_node->last_ttl = batman_packet->ttl;
- neigh_node->last_ttl = batman_packet->ttl;
- }
-
- bonding_candidate_add(orig_node, neigh_node);
-
- tmp_tt_buff_len = (tt_buff_len > batman_packet->num_tt * ETH_ALEN ?
- batman_packet->num_tt * ETH_ALEN : tt_buff_len);
-
- /* if this neighbor already is our next hop there is nothing
- * to change */
- router = orig_node_get_router(orig_node);
- if (router == neigh_node)
- goto update_tt;
-
- /* if this neighbor does not offer a better TQ we won't consider it */
- if (router && (router->tq_avg > neigh_node->tq_avg))
- goto update_tt;
-
- /* if the TQ is the same and the link not more symetric we
- * won't consider it either */
- if (router && (neigh_node->tq_avg == router->tq_avg)) {
- orig_node_tmp = router->orig_node;
- spin_lock_bh(&orig_node_tmp->ogm_cnt_lock);
- bcast_own_sum_orig =
- orig_node_tmp->bcast_own_sum[if_incoming->if_num];
- spin_unlock_bh(&orig_node_tmp->ogm_cnt_lock);
-
- orig_node_tmp = neigh_node->orig_node;
- spin_lock_bh(&orig_node_tmp->ogm_cnt_lock);
- bcast_own_sum_neigh =
- orig_node_tmp->bcast_own_sum[if_incoming->if_num];
- spin_unlock_bh(&orig_node_tmp->ogm_cnt_lock);
-
- if (bcast_own_sum_orig >= bcast_own_sum_neigh)
- goto update_tt;
- }
-
- update_routes(bat_priv, orig_node, neigh_node,
- tt_buff, tmp_tt_buff_len);
- goto update_gw;
-
-update_tt:
- update_routes(bat_priv, orig_node, router,
- tt_buff, tmp_tt_buff_len);
-
-update_gw:
- if (orig_node->gw_flags != batman_packet->gw_flags)
- gw_node_update(bat_priv, orig_node, batman_packet->gw_flags);
-
- orig_node->gw_flags = batman_packet->gw_flags;
-
- /* restart gateway selection if fast or late switching was enabled */
- if ((orig_node->gw_flags) &&
- (atomic_read(&bat_priv->gw_mode) == GW_MODE_CLIENT) &&
- (atomic_read(&bat_priv->gw_sel_class) > 2))
- gw_check_election(bat_priv, orig_node);
-
- goto out;
-
-unlock:
- rcu_read_unlock();
-out:
- if (neigh_node)
- neigh_node_free_ref(neigh_node);
- if (router)
- neigh_node_free_ref(router);
-}
-
/* checks whether the host restarted and is in the protection time.
* returns:
* 0 if the packet is to be accepted
* 1 if the packet is to be ignored.
*/
-static int window_protected(struct bat_priv *bat_priv,
- int32_t seq_num_diff,
- unsigned long *last_reset)
+int window_protected(struct bat_priv *bat_priv, int32_t seq_num_diff,
+ unsigned long *last_reset)
{
if ((seq_num_diff <= -TQ_LOCAL_WINDOW_SIZE)
|| (seq_num_diff >= EXPECTED_SEQNO_RANGE)) {
@@ -523,329 +246,12 @@ static int window_protected(struct bat_priv *bat_priv,
return 0;
}
-/* processes a batman packet for all interfaces, adjusts the sequence number and
- * finds out whether it is a duplicate.
- * returns:
- * 1 the packet is a duplicate
- * 0 the packet has not yet been received
- * -1 the packet is old and has been received while the seqno window
- * was protected. Caller should drop it.
- */
-static char count_real_packets(struct ethhdr *ethhdr,
- struct batman_packet *batman_packet,
- struct hard_iface *if_incoming)
-{
- struct bat_priv *bat_priv = netdev_priv(if_incoming->soft_iface);
- struct orig_node *orig_node;
- struct neigh_node *tmp_neigh_node;
- struct hlist_node *node;
- char is_duplicate = 0;
- int32_t seq_diff;
- int need_update = 0;
- int set_mark, ret = -1;
-
- orig_node = get_orig_node(bat_priv, batman_packet->orig);
- if (!orig_node)
- return 0;
-
- spin_lock_bh(&orig_node->ogm_cnt_lock);
- seq_diff = batman_packet->seqno - orig_node->last_real_seqno;
-
- /* signalize caller that the packet is to be dropped. */
- if (window_protected(bat_priv, seq_diff,
- &orig_node->batman_seqno_reset))
- goto out;
-
- rcu_read_lock();
- hlist_for_each_entry_rcu(tmp_neigh_node, node,
- &orig_node->neigh_list, list) {
-
- is_duplicate |= get_bit_status(tmp_neigh_node->real_bits,
- orig_node->last_real_seqno,
- batman_packet->seqno);
-
- if (compare_eth(tmp_neigh_node->addr, ethhdr->h_source) &&
- (tmp_neigh_node->if_incoming == if_incoming))
- set_mark = 1;
- else
- set_mark = 0;
-
- /* if the window moved, set the update flag. */
- need_update |= bit_get_packet(bat_priv,
- tmp_neigh_node->real_bits,
- seq_diff, set_mark);
-
- tmp_neigh_node->real_packet_count =
- bit_packet_count(tmp_neigh_node->real_bits);
- }
- rcu_read_unlock();
-
- if (need_update) {
- bat_dbg(DBG_BATMAN, bat_priv,
- "updating last_seqno: old %d, new %d\n",
- orig_node->last_real_seqno, batman_packet->seqno);
- orig_node->last_real_seqno = batman_packet->seqno;
- }
-
- ret = is_duplicate;
-
-out:
- spin_unlock_bh(&orig_node->ogm_cnt_lock);
- orig_node_free_ref(orig_node);
- return ret;
-}
-
-void receive_bat_packet(struct ethhdr *ethhdr,
- struct batman_packet *batman_packet,
- unsigned char *tt_buff, int tt_buff_len,
- struct hard_iface *if_incoming)
-{
- struct bat_priv *bat_priv = netdev_priv(if_incoming->soft_iface);
- struct hard_iface *hard_iface;
- struct orig_node *orig_neigh_node, *orig_node;
- struct neigh_node *router = NULL, *router_router = NULL;
- struct neigh_node *orig_neigh_router = NULL;
- char has_directlink_flag;
- char is_my_addr = 0, is_my_orig = 0, is_my_oldorig = 0;
- char is_broadcast = 0, is_bidirectional, is_single_hop_neigh;
- char is_duplicate;
- uint32_t if_incoming_seqno;
-
- /* Silently drop when the batman packet is actually not a
- * correct packet.
- *
- * This might happen if a packet is padded (e.g. Ethernet has a
- * minimum frame length of 64 byte) and the aggregation interprets
- * it as an additional length.
- *
- * TODO: A more sane solution would be to have a bit in the
- * batman_packet to detect whether the packet is the last
- * packet in an aggregation. Here we expect that the padding
- * is always zero (or not 0x01)
- */
- if (batman_packet->packet_type != BAT_PACKET)
- return;
-
- /* could be changed by schedule_own_packet() */
- if_incoming_seqno = atomic_read(&if_incoming->seqno);
-
- has_directlink_flag = (batman_packet->flags & DIRECTLINK ? 1 : 0);
-
- is_single_hop_neigh = (compare_eth(ethhdr->h_source,
- batman_packet->orig) ? 1 : 0);
-
- bat_dbg(DBG_BATMAN, bat_priv,
- "Received BATMAN packet via NB: %pM, IF: %s [%pM] "
- "(from OG: %pM, via prev OG: %pM, seqno %d, tq %d, "
- "TTL %d, V %d, IDF %d)\n",
- ethhdr->h_source, if_incoming->net_dev->name,
- if_incoming->net_dev->dev_addr, batman_packet->orig,
- batman_packet->prev_sender, batman_packet->seqno,
- batman_packet->tq, batman_packet->ttl, batman_packet->version,
- has_directlink_flag);
-
- rcu_read_lock();
- list_for_each_entry_rcu(hard_iface, &hardif_list, list) {
- if (hard_iface->if_status != IF_ACTIVE)
- continue;
-
- if (hard_iface->soft_iface != if_incoming->soft_iface)
- continue;
-
- if (compare_eth(ethhdr->h_source,
- hard_iface->net_dev->dev_addr))
- is_my_addr = 1;
-
- if (compare_eth(batman_packet->orig,
- hard_iface->net_dev->dev_addr))
- is_my_orig = 1;
-
- if (compare_eth(batman_packet->prev_sender,
- hard_iface->net_dev->dev_addr))
- is_my_oldorig = 1;
-
- if (compare_eth(ethhdr->h_source, broadcast_addr))
- is_broadcast = 1;
- }
- rcu_read_unlock();
-
- if (batman_packet->version != COMPAT_VERSION) {
- bat_dbg(DBG_BATMAN, bat_priv,
- "Drop packet: incompatible batman version (%i)\n",
- batman_packet->version);
- return;
- }
-
- if (is_my_addr) {
- bat_dbg(DBG_BATMAN, bat_priv,
- "Drop packet: received my own broadcast (sender: %pM"
- ")\n",
- ethhdr->h_source);
- return;
- }
-
- if (is_broadcast) {
- bat_dbg(DBG_BATMAN, bat_priv, "Drop packet: "
- "ignoring all packets with broadcast source addr (sender: %pM"
- ")\n", ethhdr->h_source);
- return;
- }
-
- if (is_my_orig) {
- unsigned long *word;
- int offset;
-
- orig_neigh_node = get_orig_node(bat_priv, ethhdr->h_source);
- if (!orig_neigh_node)
- return;
-
- /* neighbor has to indicate direct link and it has to
- * come via the corresponding interface */
- /* if received seqno equals last send seqno save new
- * seqno for bidirectional check */
- if (has_directlink_flag &&
- compare_eth(if_incoming->net_dev->dev_addr,
- batman_packet->orig) &&
- (batman_packet->seqno - if_incoming_seqno + 2 == 0)) {
- offset = if_incoming->if_num * NUM_WORDS;
-
- spin_lock_bh(&orig_neigh_node->ogm_cnt_lock);
- word = &(orig_neigh_node->bcast_own[offset]);
- bit_mark(word, 0);
- orig_neigh_node->bcast_own_sum[if_incoming->if_num] =
- bit_packet_count(word);
- spin_unlock_bh(&orig_neigh_node->ogm_cnt_lock);
- }
-
- bat_dbg(DBG_BATMAN, bat_priv, "Drop packet: "
- "originator packet from myself (via neighbor)\n");
- orig_node_free_ref(orig_neigh_node);
- return;
- }
-
- if (is_my_oldorig) {
- bat_dbg(DBG_BATMAN, bat_priv,
- "Drop packet: ignoring all rebroadcast echos (sender: "
- "%pM)\n", ethhdr->h_source);
- return;
- }
-
- orig_node = get_orig_node(bat_priv, batman_packet->orig);
- if (!orig_node)
- return;
-
- is_duplicate = count_real_packets(ethhdr, batman_packet, if_incoming);
-
- if (is_duplicate == -1) {
- bat_dbg(DBG_BATMAN, bat_priv,
- "Drop packet: packet within seqno protection time "
- "(sender: %pM)\n", ethhdr->h_source);
- goto out;
- }
-
- if (batman_packet->tq == 0) {
- bat_dbg(DBG_BATMAN, bat_priv,
- "Drop packet: originator packet with tq equal 0\n");
- goto out;
- }
-
- router = orig_node_get_router(orig_node);
- if (router)
- router_router = orig_node_get_router(router->orig_node);
-
- /* avoid temporary routing loops */
- if (router && router_router &&
- (compare_eth(router->addr, batman_packet->prev_sender)) &&
- !(compare_eth(batman_packet->orig, batman_packet->prev_sender)) &&
- (compare_eth(router->addr, router_router->addr))) {
- bat_dbg(DBG_BATMAN, bat_priv,
- "Drop packet: ignoring all rebroadcast packets that "
- "may make me loop (sender: %pM)\n", ethhdr->h_source);
- goto out;
- }
-
- /* if sender is a direct neighbor the sender mac equals
- * originator mac */
- orig_neigh_node = (is_single_hop_neigh ?
- orig_node :
- get_orig_node(bat_priv, ethhdr->h_source));
- if (!orig_neigh_node)
- goto out;
-
- orig_neigh_router = orig_node_get_router(orig_neigh_node);
-
- /* drop packet if sender is not a direct neighbor and if we
- * don't route towards it */
- if (!is_single_hop_neigh && (!orig_neigh_router)) {
- bat_dbg(DBG_BATMAN, bat_priv,
- "Drop packet: OGM via unknown neighbor!\n");
- goto out_neigh;
- }
-
- is_bidirectional = is_bidirectional_neigh(orig_node, orig_neigh_node,
- batman_packet, if_incoming);
-
- bonding_save_primary(orig_node, orig_neigh_node, batman_packet);
-
- /* update ranking if it is not a duplicate or has the same
- * seqno and similar ttl as the non-duplicate */
- if (is_bidirectional &&
- (!is_duplicate ||
- ((orig_node->last_real_seqno == batman_packet->seqno) &&
- (orig_node->last_ttl - 3 <= batman_packet->ttl))))
- update_orig(bat_priv, orig_node, ethhdr, batman_packet,
- if_incoming, tt_buff, tt_buff_len, is_duplicate);
-
- /* is single hop (direct) neighbor */
- if (is_single_hop_neigh) {
-
- /* mark direct link on incoming interface */
- schedule_forward_packet(orig_node, ethhdr, batman_packet,
- 1, tt_buff_len, if_incoming);
-
- bat_dbg(DBG_BATMAN, bat_priv, "Forwarding packet: "
- "rebroadcast neighbor packet with direct link flag\n");
- goto out_neigh;
- }
-
- /* multihop originator */
- if (!is_bidirectional) {
- bat_dbg(DBG_BATMAN, bat_priv,
- "Drop packet: not received via bidirectional link\n");
- goto out_neigh;
- }
-
- if (is_duplicate) {
- bat_dbg(DBG_BATMAN, bat_priv,
- "Drop packet: duplicate packet received\n");
- goto out_neigh;
- }
-
- bat_dbg(DBG_BATMAN, bat_priv,
- "Forwarding packet: rebroadcast originator packet\n");
- schedule_forward_packet(orig_node, ethhdr, batman_packet,
- 0, tt_buff_len, if_incoming);
-
-out_neigh:
- if ((orig_neigh_node) && (!is_single_hop_neigh))
- orig_node_free_ref(orig_neigh_node);
-out:
- if (router)
- neigh_node_free_ref(router);
- if (router_router)
- neigh_node_free_ref(router_router);
- if (orig_neigh_router)
- neigh_node_free_ref(orig_neigh_router);
-
- orig_node_free_ref(orig_node);
-}
-
-int recv_bat_packet(struct sk_buff *skb, struct hard_iface *hard_iface)
+int recv_bat_ogm_packet(struct sk_buff *skb, struct hard_iface *hard_iface)
{
struct ethhdr *ethhdr;
/* drop packet if it has not necessary minimum size */
- if (unlikely(!pskb_may_pull(skb, sizeof(struct batman_packet))))
+ if (unlikely(!pskb_may_pull(skb, BATMAN_OGM_LEN)))
return NET_RX_DROP;
ethhdr = (struct ethhdr *)skb_mac_header(skb);
@@ -868,10 +274,7 @@ int recv_bat_packet(struct sk_buff *skb, struct hard_iface *hard_iface)
ethhdr = (struct ethhdr *)skb_mac_header(skb);
- receive_aggr_bat_packet(ethhdr,
- skb->data,
- skb_headlen(skb),
- hard_iface);
+ bat_ogm_receive(ethhdr, skb->data, skb_headlen(skb), hard_iface);
kfree_skb(skb);
return NET_RX_SUCCESS;
@@ -1077,7 +480,7 @@ out:
* This method rotates the bonding list and increases the
* returned router's refcount. */
static struct neigh_node *find_bond_router(struct orig_node *primary_orig,
- struct hard_iface *recv_if)
+ const struct hard_iface *recv_if)
{
struct neigh_node *tmp_neigh_node;
struct neigh_node *router = NULL, *first_candidate = NULL;
@@ -1128,7 +531,7 @@ out:
*
* Increases the returned router's refcount */
static struct neigh_node *find_ifalter_router(struct orig_node *primary_orig,
- struct hard_iface *recv_if)
+ const struct hard_iface *recv_if)
{
struct neigh_node *tmp_neigh_node;
struct neigh_node *router = NULL, *first_candidate = NULL;
@@ -1171,12 +574,126 @@ static struct neigh_node *find_ifalter_router(struct orig_node *primary_orig,
return router;
}
+int recv_tt_query(struct sk_buff *skb, struct hard_iface *recv_if)
+{
+ struct bat_priv *bat_priv = netdev_priv(recv_if->soft_iface);
+ struct tt_query_packet *tt_query;
+ struct ethhdr *ethhdr;
+
+ /* drop packet if it has not necessary minimum size */
+ if (unlikely(!pskb_may_pull(skb, sizeof(struct tt_query_packet))))
+ goto out;
+
+ /* I could need to modify it */
+ if (skb_cow(skb, sizeof(struct tt_query_packet)) < 0)
+ goto out;
+
+ ethhdr = (struct ethhdr *)skb_mac_header(skb);
+
+ /* packet with unicast indication but broadcast recipient */
+ if (is_broadcast_ether_addr(ethhdr->h_dest))
+ goto out;
+
+ /* packet with broadcast sender address */
+ if (is_broadcast_ether_addr(ethhdr->h_source))
+ goto out;
+
+ tt_query = (struct tt_query_packet *)skb->data;
+
+ tt_query->tt_data = ntohs(tt_query->tt_data);
+
+ switch (tt_query->flags & TT_QUERY_TYPE_MASK) {
+ case TT_REQUEST:
+ /* If we cannot provide an answer the tt_request is
+ * forwarded */
+ if (!send_tt_response(bat_priv, tt_query)) {
+ bat_dbg(DBG_TT, bat_priv,
+ "Routing TT_REQUEST to %pM [%c]\n",
+ tt_query->dst,
+ (tt_query->flags & TT_FULL_TABLE ? 'F' : '.'));
+ tt_query->tt_data = htons(tt_query->tt_data);
+ return route_unicast_packet(skb, recv_if);
+ }
+ break;
+ case TT_RESPONSE:
+ /* packet needs to be linearized to access the TT changes */
+ if (skb_linearize(skb) < 0)
+ goto out;
+ /* skb_linearize() possibly changed skb->data */
+ tt_query = (struct tt_query_packet *)skb->data;
+
+ if (is_my_mac(tt_query->dst))
+ handle_tt_response(bat_priv, tt_query);
+ else {
+ bat_dbg(DBG_TT, bat_priv,
+ "Routing TT_RESPONSE to %pM [%c]\n",
+ tt_query->dst,
+ (tt_query->flags & TT_FULL_TABLE ? 'F' : '.'));
+ tt_query->tt_data = htons(tt_query->tt_data);
+ return route_unicast_packet(skb, recv_if);
+ }
+ break;
+ }
+
+out:
+ /* returning NET_RX_DROP will make the caller function kfree the skb */
+ return NET_RX_DROP;
+}
+
+int recv_roam_adv(struct sk_buff *skb, struct hard_iface *recv_if)
+{
+ struct bat_priv *bat_priv = netdev_priv(recv_if->soft_iface);
+ struct roam_adv_packet *roam_adv_packet;
+ struct orig_node *orig_node;
+ struct ethhdr *ethhdr;
+
+ /* drop packet if it has not necessary minimum size */
+ if (unlikely(!pskb_may_pull(skb, sizeof(struct roam_adv_packet))))
+ goto out;
+
+ ethhdr = (struct ethhdr *)skb_mac_header(skb);
+
+ /* packet with unicast indication but broadcast recipient */
+ if (is_broadcast_ether_addr(ethhdr->h_dest))
+ goto out;
+
+ /* packet with broadcast sender address */
+ if (is_broadcast_ether_addr(ethhdr->h_source))
+ goto out;
+
+ roam_adv_packet = (struct roam_adv_packet *)skb->data;
+
+ if (!is_my_mac(roam_adv_packet->dst))
+ return route_unicast_packet(skb, recv_if);
+
+ orig_node = orig_hash_find(bat_priv, roam_adv_packet->src);
+ if (!orig_node)
+ goto out;
+
+ bat_dbg(DBG_TT, bat_priv, "Received ROAMING_ADV from %pM "
+ "(client %pM)\n", roam_adv_packet->src,
+ roam_adv_packet->client);
+
+ tt_global_add(bat_priv, orig_node, roam_adv_packet->client,
+ atomic_read(&orig_node->last_ttvn) + 1, true, false);
+
+ /* Roaming phase starts: I have new information but the ttvn has not
+ * been incremented yet. This flag will make me check all the incoming
+ * packets for the correct destination. */
+ bat_priv->tt_poss_change = true;
+
+ orig_node_free_ref(orig_node);
+out:
+ /* returning NET_RX_DROP will make the caller function kfree the skb */
+ return NET_RX_DROP;
+}
+
/* find a suitable router for this originator, and use
* bonding if possible. increases the found neighbors
* refcount.*/
struct neigh_node *find_router(struct bat_priv *bat_priv,
struct orig_node *orig_node,
- struct hard_iface *recv_if)
+ const struct hard_iface *recv_if)
{
struct orig_node *primary_orig_node;
struct orig_node *router_orig;
@@ -1240,6 +757,9 @@ struct neigh_node *find_router(struct bat_priv *bat_priv,
router = find_ifalter_router(primary_orig_node, recv_if);
return_router:
+ if (router && router->if_incoming->if_status != IF_ACTIVE)
+ goto err_unlock;
+
rcu_read_unlock();
return router;
err_unlock:
@@ -1354,14 +874,84 @@ out:
return ret;
}
+static int check_unicast_ttvn(struct bat_priv *bat_priv,
+ struct sk_buff *skb) {
+ uint8_t curr_ttvn;
+ struct orig_node *orig_node;
+ struct ethhdr *ethhdr;
+ struct hard_iface *primary_if;
+ struct unicast_packet *unicast_packet;
+ bool tt_poss_change;
+
+ /* I could need to modify it */
+ if (skb_cow(skb, sizeof(struct unicast_packet)) < 0)
+ return 0;
+
+ unicast_packet = (struct unicast_packet *)skb->data;
+
+ if (is_my_mac(unicast_packet->dest)) {
+ tt_poss_change = bat_priv->tt_poss_change;
+ curr_ttvn = (uint8_t)atomic_read(&bat_priv->ttvn);
+ } else {
+ orig_node = orig_hash_find(bat_priv, unicast_packet->dest);
+
+ if (!orig_node)
+ return 0;
+
+ curr_ttvn = (uint8_t)atomic_read(&orig_node->last_ttvn);
+ tt_poss_change = orig_node->tt_poss_change;
+ orig_node_free_ref(orig_node);
+ }
+
+ /* Check whether I have to reroute the packet */
+ if (seq_before(unicast_packet->ttvn, curr_ttvn) || tt_poss_change) {
+ /* Linearize the skb before accessing it */
+ if (skb_linearize(skb) < 0)
+ return 0;
+
+ ethhdr = (struct ethhdr *)(skb->data +
+ sizeof(struct unicast_packet));
+ orig_node = transtable_search(bat_priv, NULL, ethhdr->h_dest);
+
+ if (!orig_node) {
+ if (!is_my_client(bat_priv, ethhdr->h_dest))
+ return 0;
+ primary_if = primary_if_get_selected(bat_priv);
+ if (!primary_if)
+ return 0;
+ memcpy(unicast_packet->dest,
+ primary_if->net_dev->dev_addr, ETH_ALEN);
+ hardif_free_ref(primary_if);
+ } else {
+ memcpy(unicast_packet->dest, orig_node->orig,
+ ETH_ALEN);
+ curr_ttvn = (uint8_t)
+ atomic_read(&orig_node->last_ttvn);
+ orig_node_free_ref(orig_node);
+ }
+
+ bat_dbg(DBG_ROUTES, bat_priv, "TTVN mismatch (old_ttvn %u "
+ "new_ttvn %u)! Rerouting unicast packet (for %pM) to "
+ "%pM\n", unicast_packet->ttvn, curr_ttvn,
+ ethhdr->h_dest, unicast_packet->dest);
+
+ unicast_packet->ttvn = curr_ttvn;
+ }
+ return 1;
+}
+
int recv_unicast_packet(struct sk_buff *skb, struct hard_iface *recv_if)
{
+ struct bat_priv *bat_priv = netdev_priv(recv_if->soft_iface);
struct unicast_packet *unicast_packet;
- int hdr_size = sizeof(struct unicast_packet);
+ int hdr_size = sizeof(*unicast_packet);
if (check_unicast_packet(skb, hdr_size) < 0)
return NET_RX_DROP;
+ if (!check_unicast_ttvn(bat_priv, skb))
+ return NET_RX_DROP;
+
unicast_packet = (struct unicast_packet *)skb->data;
/* packet for me */
@@ -1377,13 +967,16 @@ int recv_ucast_frag_packet(struct sk_buff *skb, struct hard_iface *recv_if)
{
struct bat_priv *bat_priv = netdev_priv(recv_if->soft_iface);
struct unicast_frag_packet *unicast_packet;
- int hdr_size = sizeof(struct unicast_frag_packet);
+ int hdr_size = sizeof(*unicast_packet);
struct sk_buff *new_skb = NULL;
int ret;
if (check_unicast_packet(skb, hdr_size) < 0)
return NET_RX_DROP;
+ if (!check_unicast_ttvn(bat_priv, skb))
+ return NET_RX_DROP;
+
unicast_packet = (struct unicast_frag_packet *)skb->data;
/* packet for me */
@@ -1413,7 +1006,7 @@ int recv_bcast_packet(struct sk_buff *skb, struct hard_iface *recv_if)
struct orig_node *orig_node = NULL;
struct bcast_packet *bcast_packet;
struct ethhdr *ethhdr;
- int hdr_size = sizeof(struct bcast_packet);
+ int hdr_size = sizeof(*bcast_packet);
int ret = NET_RX_DROP;
int32_t seq_diff;
@@ -1471,7 +1064,7 @@ int recv_bcast_packet(struct sk_buff *skb, struct hard_iface *recv_if)
spin_unlock_bh(&orig_node->bcast_seqno_lock);
/* rebroadcast packet */
- add_bcast_packet_to_list(bat_priv, skb);
+ add_bcast_packet_to_list(bat_priv, skb, 1);
/* broadcast for me */
interface_rx(recv_if->soft_iface, skb, recv_if, hdr_size);
@@ -1491,7 +1084,7 @@ int recv_vis_packet(struct sk_buff *skb, struct hard_iface *recv_if)
struct vis_packet *vis_packet;
struct ethhdr *ethhdr;
struct bat_priv *bat_priv = netdev_priv(recv_if->soft_iface);
- int hdr_size = sizeof(struct vis_packet);
+ int hdr_size = sizeof(*vis_packet);
/* keep skb linear */
if (skb_linearize(skb) < 0)
diff --git a/net/batman-adv/routing.h b/net/batman-adv/routing.h
index 870f298..7aaee0f 100644
--- a/net/batman-adv/routing.h
+++ b/net/batman-adv/routing.h
@@ -23,24 +23,28 @@
#define _NET_BATMAN_ADV_ROUTING_H_
void slide_own_bcast_window(struct hard_iface *hard_iface);
-void receive_bat_packet(struct ethhdr *ethhdr,
- struct batman_packet *batman_packet,
- unsigned char *tt_buff, int tt_buff_len,
- struct hard_iface *if_incoming);
-void update_routes(struct bat_priv *bat_priv, struct orig_node *orig_node,
- struct neigh_node *neigh_node, unsigned char *tt_buff,
- int tt_buff_len);
+void update_route(struct bat_priv *bat_priv, struct orig_node *orig_node,
+ struct neigh_node *neigh_node);
int route_unicast_packet(struct sk_buff *skb, struct hard_iface *recv_if);
int recv_icmp_packet(struct sk_buff *skb, struct hard_iface *recv_if);
int recv_unicast_packet(struct sk_buff *skb, struct hard_iface *recv_if);
int recv_ucast_frag_packet(struct sk_buff *skb, struct hard_iface *recv_if);
int recv_bcast_packet(struct sk_buff *skb, struct hard_iface *recv_if);
int recv_vis_packet(struct sk_buff *skb, struct hard_iface *recv_if);
-int recv_bat_packet(struct sk_buff *skb, struct hard_iface *recv_if);
+int recv_bat_ogm_packet(struct sk_buff *skb, struct hard_iface *recv_if);
+int recv_tt_query(struct sk_buff *skb, struct hard_iface *recv_if);
+int recv_roam_adv(struct sk_buff *skb, struct hard_iface *recv_if);
struct neigh_node *find_router(struct bat_priv *bat_priv,
struct orig_node *orig_node,
- struct hard_iface *recv_if);
+ const struct hard_iface *recv_if);
void bonding_candidate_del(struct orig_node *orig_node,
struct neigh_node *neigh_node);
+void bonding_candidate_add(struct orig_node *orig_node,
+ struct neigh_node *neigh_node);
+void bonding_save_primary(const struct orig_node *orig_node,
+ struct orig_node *orig_neigh_node,
+ const struct batman_ogm_packet *batman_ogm_packet);
+int window_protected(struct bat_priv *bat_priv, int32_t seq_num_diff,
+ unsigned long *last_reset);
#endif /* _NET_BATMAN_ADV_ROUTING_H_ */
diff --git a/net/batman-adv/send.c b/net/batman-adv/send.c
index 3377927..8a684eb 100644
--- a/net/batman-adv/send.c
+++ b/net/batman-adv/send.c
@@ -26,38 +26,16 @@
#include "soft-interface.h"
#include "hard-interface.h"
#include "vis.h"
-#include "aggregation.h"
#include "gateway_common.h"
#include "originator.h"
+#include "bat_ogm.h"
static void send_outstanding_bcast_packet(struct work_struct *work);
-/* apply hop penalty for a normal link */
-static uint8_t hop_penalty(const uint8_t tq, struct bat_priv *bat_priv)
-{
- int hop_penalty = atomic_read(&bat_priv->hop_penalty);
- return (tq * (TQ_MAX_VALUE - hop_penalty)) / (TQ_MAX_VALUE);
-}
-
-/* when do we schedule our own packet to be sent */
-static unsigned long own_send_time(struct bat_priv *bat_priv)
-{
- return jiffies + msecs_to_jiffies(
- atomic_read(&bat_priv->orig_interval) -
- JITTER + (random32() % 2*JITTER));
-}
-
-/* when do we schedule a forwarded packet to be sent */
-static unsigned long forward_send_time(void)
-{
- return jiffies + msecs_to_jiffies(random32() % (JITTER/2));
-}
-
/* send out an already prepared packet to the given address via the
* specified batman interface */
-int send_skb_packet(struct sk_buff *skb,
- struct hard_iface *hard_iface,
- uint8_t *dst_addr)
+int send_skb_packet(struct sk_buff *skb, struct hard_iface *hard_iface,
+ const uint8_t *dst_addr)
{
struct ethhdr *ethhdr;
@@ -74,7 +52,7 @@ int send_skb_packet(struct sk_buff *skb,
}
/* push to the ethernet header. */
- if (my_skb_head_push(skb, sizeof(struct ethhdr)) < 0)
+ if (my_skb_head_push(skb, sizeof(*ethhdr)) < 0)
goto send_skb_err;
skb_reset_mac_header(skb);
@@ -100,162 +78,67 @@ send_skb_err:
return NET_XMIT_DROP;
}
-/* Send a packet to a given interface */
-static void send_packet_to_if(struct forw_packet *forw_packet,
- struct hard_iface *hard_iface)
+static void realloc_packet_buffer(struct hard_iface *hard_iface,
+ int new_len)
{
- struct bat_priv *bat_priv = netdev_priv(hard_iface->soft_iface);
- char *fwd_str;
- uint8_t packet_num;
- int16_t buff_pos;
- struct batman_packet *batman_packet;
- struct sk_buff *skb;
+ unsigned char *new_buff;
- if (hard_iface->if_status != IF_ACTIVE)
- return;
+ new_buff = kmalloc(new_len, GFP_ATOMIC);
- packet_num = 0;
- buff_pos = 0;
- batman_packet = (struct batman_packet *)forw_packet->skb->data;
-
- /* adjust all flags and log packets */
- while (aggregated_packet(buff_pos,
- forw_packet->packet_len,
- batman_packet->num_tt)) {
-
- /* we might have aggregated direct link packets with an
- * ordinary base packet */
- if ((forw_packet->direct_link_flags & (1 << packet_num)) &&
- (forw_packet->if_incoming == hard_iface))
- batman_packet->flags |= DIRECTLINK;
- else
- batman_packet->flags &= ~DIRECTLINK;
-
- fwd_str = (packet_num > 0 ? "Forwarding" : (forw_packet->own ?
- "Sending own" :
- "Forwarding"));
- bat_dbg(DBG_BATMAN, bat_priv,
- "%s %spacket (originator %pM, seqno %d, TQ %d, TTL %d,"
- " IDF %s) on interface %s [%pM]\n",
- fwd_str, (packet_num > 0 ? "aggregated " : ""),
- batman_packet->orig, ntohl(batman_packet->seqno),
- batman_packet->tq, batman_packet->ttl,
- (batman_packet->flags & DIRECTLINK ?
- "on" : "off"),
- hard_iface->net_dev->name,
- hard_iface->net_dev->dev_addr);
-
- buff_pos += sizeof(struct batman_packet) +
- (batman_packet->num_tt * ETH_ALEN);
- packet_num++;
- batman_packet = (struct batman_packet *)
- (forw_packet->skb->data + buff_pos);
- }
+ /* keep old buffer if kmalloc should fail */
+ if (new_buff) {
+ memcpy(new_buff, hard_iface->packet_buff,
+ BATMAN_OGM_LEN);
- /* create clone because function is called more than once */
- skb = skb_clone(forw_packet->skb, GFP_ATOMIC);
- if (skb)
- send_skb_packet(skb, hard_iface, broadcast_addr);
+ kfree(hard_iface->packet_buff);
+ hard_iface->packet_buff = new_buff;
+ hard_iface->packet_len = new_len;
+ }
}
-/* send a batman packet */
-static void send_packet(struct forw_packet *forw_packet)
+/* when calling this function (hard_iface == primary_if) has to be true */
+static int prepare_packet_buffer(struct bat_priv *bat_priv,
+ struct hard_iface *hard_iface)
{
- struct hard_iface *hard_iface;
- struct net_device *soft_iface;
- struct bat_priv *bat_priv;
- struct batman_packet *batman_packet =
- (struct batman_packet *)(forw_packet->skb->data);
- unsigned char directlink = (batman_packet->flags & DIRECTLINK ? 1 : 0);
-
- if (!forw_packet->if_incoming) {
- pr_err("Error - can't forward packet: incoming iface not "
- "specified\n");
- return;
- }
+ int new_len;
- soft_iface = forw_packet->if_incoming->soft_iface;
- bat_priv = netdev_priv(soft_iface);
+ new_len = BATMAN_OGM_LEN +
+ tt_len((uint8_t)atomic_read(&bat_priv->tt_local_changes));
- if (forw_packet->if_incoming->if_status != IF_ACTIVE)
- return;
+ /* if we have too many changes for one packet don't send any
+ * and wait for the tt table request which will be fragmented */
+ if (new_len > hard_iface->soft_iface->mtu)
+ new_len = BATMAN_OGM_LEN;
- /* multihomed peer assumed */
- /* non-primary OGMs are only broadcasted on their interface */
- if ((directlink && (batman_packet->ttl == 1)) ||
- (forw_packet->own && (forw_packet->if_incoming->if_num > 0))) {
+ realloc_packet_buffer(hard_iface, new_len);
- /* FIXME: what about aggregated packets ? */
- bat_dbg(DBG_BATMAN, bat_priv,
- "%s packet (originator %pM, seqno %d, TTL %d) "
- "on interface %s [%pM]\n",
- (forw_packet->own ? "Sending own" : "Forwarding"),
- batman_packet->orig, ntohl(batman_packet->seqno),
- batman_packet->ttl,
- forw_packet->if_incoming->net_dev->name,
- forw_packet->if_incoming->net_dev->dev_addr);
-
- /* skb is only used once and than forw_packet is free'd */
- send_skb_packet(forw_packet->skb, forw_packet->if_incoming,
- broadcast_addr);
- forw_packet->skb = NULL;
+ atomic_set(&bat_priv->tt_crc, tt_local_crc(bat_priv));
- return;
- }
+ /* reset the sending counter */
+ atomic_set(&bat_priv->tt_ogm_append_cnt, TT_OGM_APPEND_MAX);
- /* broadcast on every interface */
- rcu_read_lock();
- list_for_each_entry_rcu(hard_iface, &hardif_list, list) {
- if (hard_iface->soft_iface != soft_iface)
- continue;
-
- send_packet_to_if(forw_packet, hard_iface);
- }
- rcu_read_unlock();
+ return tt_changes_fill_buffer(bat_priv,
+ hard_iface->packet_buff + BATMAN_OGM_LEN,
+ hard_iface->packet_len - BATMAN_OGM_LEN);
}
-static void rebuild_batman_packet(struct bat_priv *bat_priv,
- struct hard_iface *hard_iface)
+static int reset_packet_buffer(struct bat_priv *bat_priv,
+ struct hard_iface *hard_iface)
{
- int new_len;
- unsigned char *new_buff;
- struct batman_packet *batman_packet;
-
- new_len = sizeof(struct batman_packet) +
- (bat_priv->num_local_tt * ETH_ALEN);
- new_buff = kmalloc(new_len, GFP_ATOMIC);
-
- /* keep old buffer if kmalloc should fail */
- if (new_buff) {
- memcpy(new_buff, hard_iface->packet_buff,
- sizeof(struct batman_packet));
- batman_packet = (struct batman_packet *)new_buff;
-
- batman_packet->num_tt = tt_local_fill_buffer(bat_priv,
- new_buff + sizeof(struct batman_packet),
- new_len - sizeof(struct batman_packet));
-
- kfree(hard_iface->packet_buff);
- hard_iface->packet_buff = new_buff;
- hard_iface->packet_len = new_len;
- }
+ realloc_packet_buffer(hard_iface, BATMAN_OGM_LEN);
+ return 0;
}
-void schedule_own_packet(struct hard_iface *hard_iface)
+void schedule_bat_ogm(struct hard_iface *hard_iface)
{
struct bat_priv *bat_priv = netdev_priv(hard_iface->soft_iface);
struct hard_iface *primary_if;
- unsigned long send_time;
- struct batman_packet *batman_packet;
- int vis_server;
+ int tt_num_changes = -1;
if ((hard_iface->if_status == IF_NOT_IN_USE) ||
(hard_iface->if_status == IF_TO_BE_REMOVED))
return;
- vis_server = atomic_read(&bat_priv->vis_mode);
- primary_if = primary_if_get_selected(bat_priv);
-
/**
* the interface gets activated here to avoid race conditions between
* the moment of activating the interface in
@@ -266,111 +149,26 @@ void schedule_own_packet(struct hard_iface *hard_iface)
if (hard_iface->if_status == IF_TO_BE_ACTIVATED)
hard_iface->if_status = IF_ACTIVE;
- /* if local tt has changed and interface is a primary interface */
- if ((atomic_read(&bat_priv->tt_local_changed)) &&
- (hard_iface == primary_if))
- rebuild_batman_packet(bat_priv, hard_iface);
-
- /**
- * NOTE: packet_buff might just have been re-allocated in
- * rebuild_batman_packet()
- */
- batman_packet = (struct batman_packet *)hard_iface->packet_buff;
-
- /* change sequence number to network order */
- batman_packet->seqno =
- htonl((uint32_t)atomic_read(&hard_iface->seqno));
-
- if (vis_server == VIS_TYPE_SERVER_SYNC)
- batman_packet->flags |= VIS_SERVER;
- else
- batman_packet->flags &= ~VIS_SERVER;
-
- if ((hard_iface == primary_if) &&
- (atomic_read(&bat_priv->gw_mode) == GW_MODE_SERVER))
- batman_packet->gw_flags =
- (uint8_t)atomic_read(&bat_priv->gw_bandwidth);
- else
- batman_packet->gw_flags = 0;
-
- atomic_inc(&hard_iface->seqno);
-
- slide_own_bcast_window(hard_iface);
- send_time = own_send_time(bat_priv);
- add_bat_packet_to_list(bat_priv,
- hard_iface->packet_buff,
- hard_iface->packet_len,
- hard_iface, 1, send_time);
-
- if (primary_if)
- hardif_free_ref(primary_if);
-}
-
-void schedule_forward_packet(struct orig_node *orig_node,
- struct ethhdr *ethhdr,
- struct batman_packet *batman_packet,
- uint8_t directlink, int tt_buff_len,
- struct hard_iface *if_incoming)
-{
- struct bat_priv *bat_priv = netdev_priv(if_incoming->soft_iface);
- struct neigh_node *router;
- unsigned char in_tq, in_ttl, tq_avg = 0;
- unsigned long send_time;
-
- if (batman_packet->ttl <= 1) {
- bat_dbg(DBG_BATMAN, bat_priv, "ttl exceeded\n");
- return;
- }
-
- router = orig_node_get_router(orig_node);
-
- in_tq = batman_packet->tq;
- in_ttl = batman_packet->ttl;
-
- batman_packet->ttl--;
- memcpy(batman_packet->prev_sender, ethhdr->h_source, ETH_ALEN);
-
- /* rebroadcast tq of our best ranking neighbor to ensure the rebroadcast
- * of our best tq value */
- if (router && router->tq_avg != 0) {
-
- /* rebroadcast ogm of best ranking neighbor as is */
- if (!compare_eth(router->addr, ethhdr->h_source)) {
- batman_packet->tq = router->tq_avg;
+ primary_if = primary_if_get_selected(bat_priv);
- if (router->last_ttl)
- batman_packet->ttl = router->last_ttl - 1;
+ if (hard_iface == primary_if) {
+ /* if at least one change happened */
+ if (atomic_read(&bat_priv->tt_local_changes) > 0) {
+ tt_commit_changes(bat_priv);
+ tt_num_changes = prepare_packet_buffer(bat_priv,
+ hard_iface);
}
- tq_avg = router->tq_avg;
+ /* if the changes have been sent often enough */
+ if (!atomic_dec_not_zero(&bat_priv->tt_ogm_append_cnt))
+ tt_num_changes = reset_packet_buffer(bat_priv,
+ hard_iface);
}
- if (router)
- neigh_node_free_ref(router);
-
- /* apply hop penalty */
- batman_packet->tq = hop_penalty(batman_packet->tq, bat_priv);
-
- bat_dbg(DBG_BATMAN, bat_priv,
- "Forwarding packet: tq_orig: %i, tq_avg: %i, "
- "tq_forw: %i, ttl_orig: %i, ttl_forw: %i\n",
- in_tq, tq_avg, batman_packet->tq, in_ttl - 1,
- batman_packet->ttl);
-
- batman_packet->seqno = htonl(batman_packet->seqno);
-
- /* switch of primaries first hop flag when forwarding */
- batman_packet->flags &= ~PRIMARIES_FIRST_HOP;
- if (directlink)
- batman_packet->flags |= DIRECTLINK;
- else
- batman_packet->flags &= ~DIRECTLINK;
+ if (primary_if)
+ hardif_free_ref(primary_if);
- send_time = forward_send_time();
- add_bat_packet_to_list(bat_priv,
- (unsigned char *)batman_packet,
- sizeof(struct batman_packet) + tt_buff_len,
- if_incoming, 0, send_time);
+ bat_ogm_schedule(hard_iface, tt_num_changes);
}
static void forw_packet_free(struct forw_packet *forw_packet)
@@ -401,18 +199,20 @@ static void _add_bcast_packet_to_list(struct bat_priv *bat_priv,
}
/* add a broadcast packet to the queue and setup timers. broadcast packets
- * are sent multiple times to increase probability for beeing received.
+ * are sent multiple times to increase probability for being received.
*
* This function returns NETDEV_TX_OK on success and NETDEV_TX_BUSY on
* errors.
*
* The skb is not consumed, so the caller should make sure that the
* skb is freed. */
-int add_bcast_packet_to_list(struct bat_priv *bat_priv, struct sk_buff *skb)
+int add_bcast_packet_to_list(struct bat_priv *bat_priv,
+ const struct sk_buff *skb, unsigned long delay)
{
struct hard_iface *primary_if = NULL;
struct forw_packet *forw_packet;
struct bcast_packet *bcast_packet;
+ struct sk_buff *newskb;
if (!atomic_dec_not_zero(&bat_priv->bcast_queue_left)) {
bat_dbg(DBG_BATMAN, bat_priv, "bcast packet queue full\n");
@@ -423,28 +223,28 @@ int add_bcast_packet_to_list(struct bat_priv *bat_priv, struct sk_buff *skb)
if (!primary_if)
goto out_and_inc;
- forw_packet = kmalloc(sizeof(struct forw_packet), GFP_ATOMIC);
+ forw_packet = kmalloc(sizeof(*forw_packet), GFP_ATOMIC);
if (!forw_packet)
goto out_and_inc;
- skb = skb_copy(skb, GFP_ATOMIC);
- if (!skb)
+ newskb = skb_copy(skb, GFP_ATOMIC);
+ if (!newskb)
goto packet_free;
/* as we have a copy now, it is safe to decrease the TTL */
- bcast_packet = (struct bcast_packet *)skb->data;
+ bcast_packet = (struct bcast_packet *)newskb->data;
bcast_packet->ttl--;
- skb_reset_mac_header(skb);
+ skb_reset_mac_header(newskb);
- forw_packet->skb = skb;
+ forw_packet->skb = newskb;
forw_packet->if_incoming = primary_if;
/* how often did we send the bcast packet ? */
forw_packet->num_packets = 0;
- _add_bcast_packet_to_list(bat_priv, forw_packet, 1);
+ _add_bcast_packet_to_list(bat_priv, forw_packet, delay);
return NETDEV_TX_OK;
packet_free:
@@ -502,7 +302,7 @@ out:
atomic_inc(&bat_priv->bcast_queue_left);
}
-void send_outstanding_bat_packet(struct work_struct *work)
+void send_outstanding_bat_ogm_packet(struct work_struct *work)
{
struct delayed_work *delayed_work =
container_of(work, struct delayed_work, work);
@@ -518,7 +318,7 @@ void send_outstanding_bat_packet(struct work_struct *work)
if (atomic_read(&bat_priv->mesh_state) == MESH_DEACTIVATING)
goto out;
- send_packet(forw_packet);
+ bat_ogm_emit(forw_packet);
/**
* we have to have at least one packet in the queue
@@ -526,7 +326,7 @@ void send_outstanding_bat_packet(struct work_struct *work)
* shutting down
*/
if (forw_packet->own)
- schedule_own_packet(forw_packet->if_incoming);
+ schedule_bat_ogm(forw_packet->if_incoming);
out:
/* don't count own packet */
@@ -537,7 +337,7 @@ out:
}
void purge_outstanding_packets(struct bat_priv *bat_priv,
- struct hard_iface *hard_iface)
+ const struct hard_iface *hard_iface)
{
struct forw_packet *forw_packet;
struct hlist_node *tmp_node, *safe_tmp_node;
@@ -557,7 +357,7 @@ void purge_outstanding_packets(struct bat_priv *bat_priv,
&bat_priv->forw_bcast_list, list) {
/**
- * if purge_outstanding_packets() was called with an argmument
+ * if purge_outstanding_packets() was called with an argument
* we delete only packets belonging to the given interface
*/
if ((hard_iface) &&
@@ -586,7 +386,7 @@ void purge_outstanding_packets(struct bat_priv *bat_priv,
&bat_priv->forw_bat_list, list) {
/**
- * if purge_outstanding_packets() was called with an argmument
+ * if purge_outstanding_packets() was called with an argument
* we delete only packets belonging to the given interface
*/
if ((hard_iface) &&
diff --git a/net/batman-adv/send.h b/net/batman-adv/send.h
index 247172d..c8ca3ef 100644
--- a/net/batman-adv/send.h
+++ b/net/batman-adv/send.h
@@ -22,18 +22,13 @@
#ifndef _NET_BATMAN_ADV_SEND_H_
#define _NET_BATMAN_ADV_SEND_H_
-int send_skb_packet(struct sk_buff *skb,
- struct hard_iface *hard_iface,
- uint8_t *dst_addr);
-void schedule_own_packet(struct hard_iface *hard_iface);
-void schedule_forward_packet(struct orig_node *orig_node,
- struct ethhdr *ethhdr,
- struct batman_packet *batman_packet,
- uint8_t directlink, int tt_buff_len,
- struct hard_iface *if_outgoing);
-int add_bcast_packet_to_list(struct bat_priv *bat_priv, struct sk_buff *skb);
-void send_outstanding_bat_packet(struct work_struct *work);
+int send_skb_packet(struct sk_buff *skb, struct hard_iface *hard_iface,
+ const uint8_t *dst_addr);
+void schedule_bat_ogm(struct hard_iface *hard_iface);
+int add_bcast_packet_to_list(struct bat_priv *bat_priv,
+ const struct sk_buff *skb, unsigned long delay);
+void send_outstanding_bat_ogm_packet(struct work_struct *work);
void purge_outstanding_packets(struct bat_priv *bat_priv,
- struct hard_iface *hard_iface);
+ const struct hard_iface *hard_iface);
#endif /* _NET_BATMAN_ADV_SEND_H_ */
diff --git a/net/batman-adv/soft-interface.c b/net/batman-adv/soft-interface.c
index d5aa609..f9cc957 100644
--- a/net/batman-adv/soft-interface.c
+++ b/net/batman-adv/soft-interface.c
@@ -30,6 +30,7 @@
#include "gateway_common.h"
#include "gateway_client.h"
#include "bat_sysfs.h"
+#include "originator.h"
#include <linux/slab.h>
#include <linux/ethtool.h>
#include <linux/etherdevice.h>
@@ -123,8 +124,7 @@ static struct softif_neigh_vid *softif_neigh_vid_get(struct bat_priv *bat_priv,
goto out;
}
- softif_neigh_vid = kzalloc(sizeof(struct softif_neigh_vid),
- GFP_ATOMIC);
+ softif_neigh_vid = kzalloc(sizeof(*softif_neigh_vid), GFP_ATOMIC);
if (!softif_neigh_vid)
goto out;
@@ -146,7 +146,7 @@ out:
}
static struct softif_neigh *softif_neigh_get(struct bat_priv *bat_priv,
- uint8_t *addr, short vid)
+ const uint8_t *addr, short vid)
{
struct softif_neigh_vid *softif_neigh_vid;
struct softif_neigh *softif_neigh = NULL;
@@ -170,7 +170,7 @@ static struct softif_neigh *softif_neigh_get(struct bat_priv *bat_priv,
goto unlock;
}
- softif_neigh = kzalloc(sizeof(struct softif_neigh), GFP_ATOMIC);
+ softif_neigh = kzalloc(sizeof(*softif_neigh), GFP_ATOMIC);
if (!softif_neigh)
goto unlock;
@@ -242,7 +242,8 @@ static void softif_neigh_vid_select(struct bat_priv *bat_priv,
if (new_neigh && !atomic_inc_not_zero(&new_neigh->refcount))
new_neigh = NULL;
- curr_neigh = softif_neigh_vid->softif_neigh;
+ curr_neigh = rcu_dereference_protected(softif_neigh_vid->softif_neigh,
+ 1);
rcu_assign_pointer(softif_neigh_vid->softif_neigh, new_neigh);
if ((curr_neigh) && (!new_neigh))
@@ -380,7 +381,7 @@ void softif_neigh_purge(struct bat_priv *bat_priv)
struct softif_neigh *softif_neigh, *curr_softif_neigh;
struct softif_neigh_vid *softif_neigh_vid;
struct hlist_node *node, *node_tmp, *node_tmp2;
- char do_deselect;
+ int do_deselect;
rcu_read_lock();
hlist_for_each_entry_rcu(softif_neigh_vid, node,
@@ -444,30 +445,31 @@ static void softif_batman_recv(struct sk_buff *skb, struct net_device *dev,
{
struct bat_priv *bat_priv = netdev_priv(dev);
struct ethhdr *ethhdr = (struct ethhdr *)skb->data;
- struct batman_packet *batman_packet;
+ struct batman_ogm_packet *batman_ogm_packet;
struct softif_neigh *softif_neigh = NULL;
struct hard_iface *primary_if = NULL;
struct softif_neigh *curr_softif_neigh = NULL;
if (ntohs(ethhdr->h_proto) == ETH_P_8021Q)
- batman_packet = (struct batman_packet *)
+ batman_ogm_packet = (struct batman_ogm_packet *)
(skb->data + ETH_HLEN + VLAN_HLEN);
else
- batman_packet = (struct batman_packet *)(skb->data + ETH_HLEN);
+ batman_ogm_packet = (struct batman_ogm_packet *)
+ (skb->data + ETH_HLEN);
- if (batman_packet->version != COMPAT_VERSION)
+ if (batman_ogm_packet->version != COMPAT_VERSION)
goto out;
- if (batman_packet->packet_type != BAT_PACKET)
+ if (batman_ogm_packet->packet_type != BAT_OGM)
goto out;
- if (!(batman_packet->flags & PRIMARIES_FIRST_HOP))
+ if (!(batman_ogm_packet->flags & PRIMARIES_FIRST_HOP))
goto out;
- if (is_my_mac(batman_packet->orig))
+ if (is_my_mac(batman_ogm_packet->orig))
goto out;
- softif_neigh = softif_neigh_get(bat_priv, batman_packet->orig, vid);
+ softif_neigh = softif_neigh_get(bat_priv, batman_ogm_packet->orig, vid);
if (!softif_neigh)
goto out;
@@ -531,11 +533,11 @@ static int interface_set_mac_addr(struct net_device *dev, void *p)
if (!is_valid_ether_addr(addr->sa_data))
return -EADDRNOTAVAIL;
- /* only modify transtable if it has been initialised before */
+ /* only modify transtable if it has been initialized before */
if (atomic_read(&bat_priv->mesh_state) == MESH_ACTIVE) {
tt_local_remove(bat_priv, dev->dev_addr,
- "mac address changed");
- tt_local_add(dev, addr->sa_data);
+ "mac address changed", false);
+ tt_local_add(dev, addr->sa_data, NULL_IFINDEX);
}
memcpy(dev->dev_addr, addr->sa_data, ETH_ALEN);
@@ -553,7 +555,7 @@ static int interface_change_mtu(struct net_device *dev, int new_mtu)
return 0;
}
-int interface_tx(struct sk_buff *skb, struct net_device *soft_iface)
+static int interface_tx(struct sk_buff *skb, struct net_device *soft_iface)
{
struct ethhdr *ethhdr = (struct ethhdr *)skb->data;
struct bat_priv *bat_priv = netdev_priv(soft_iface);
@@ -561,9 +563,10 @@ int interface_tx(struct sk_buff *skb, struct net_device *soft_iface)
struct bcast_packet *bcast_packet;
struct vlan_ethhdr *vhdr;
struct softif_neigh *curr_softif_neigh = NULL;
+ struct orig_node *orig_node = NULL;
int data_len = skb->len, ret;
short vid = -1;
- bool do_bcast = false;
+ bool do_bcast;
if (atomic_read(&bat_priv->mesh_state) != MESH_ACTIVE)
goto dropped;
@@ -592,17 +595,20 @@ int interface_tx(struct sk_buff *skb, struct net_device *soft_iface)
if (curr_softif_neigh)
goto dropped;
- /* TODO: check this for locks */
- tt_local_add(soft_iface, ethhdr->h_source);
+ /* Register the client MAC in the transtable */
+ tt_local_add(soft_iface, ethhdr->h_source, skb->skb_iif);
- if (is_multicast_ether_addr(ethhdr->h_dest)) {
- ret = gw_is_target(bat_priv, skb);
+ orig_node = transtable_search(bat_priv, ethhdr->h_source,
+ ethhdr->h_dest);
+ do_bcast = is_multicast_ether_addr(ethhdr->h_dest);
+ if (do_bcast || (orig_node && orig_node->gw_flags)) {
+ ret = gw_is_target(bat_priv, skb, orig_node);
if (ret < 0)
goto dropped;
- if (ret == 0)
- do_bcast = true;
+ if (ret)
+ do_bcast = false;
}
/* ethernet packet should be broadcasted */
@@ -611,7 +617,7 @@ int interface_tx(struct sk_buff *skb, struct net_device *soft_iface)
if (!primary_if)
goto dropped;
- if (my_skb_head_push(skb, sizeof(struct bcast_packet)) < 0)
+ if (my_skb_head_push(skb, sizeof(*bcast_packet)) < 0)
goto dropped;
bcast_packet = (struct bcast_packet *)skb->data;
@@ -630,7 +636,7 @@ int interface_tx(struct sk_buff *skb, struct net_device *soft_iface)
bcast_packet->seqno =
htonl(atomic_inc_return(&bat_priv->bcast_seqno));
- add_bcast_packet_to_list(bat_priv, skb);
+ add_bcast_packet_to_list(bat_priv, skb, 1);
/* a copy is stored in the bcast list, therefore removing
* the original skb. */
@@ -656,6 +662,8 @@ end:
softif_neigh_free_ref(curr_softif_neigh);
if (primary_if)
hardif_free_ref(primary_if);
+ if (orig_node)
+ orig_node_free_ref(orig_node);
return NETDEV_TX_OK;
}
@@ -733,6 +741,9 @@ void interface_rx(struct net_device *soft_iface,
soft_iface->last_rx = jiffies;
+ if (is_ap_isolated(bat_priv, ethhdr->h_source, ethhdr->h_dest))
+ goto dropped;
+
netif_rx(skb);
goto out;
@@ -744,7 +755,6 @@ out:
return;
}
-#ifdef HAVE_NET_DEVICE_OPS
static const struct net_device_ops bat_netdev_ops = {
.ndo_open = interface_open,
.ndo_stop = interface_release,
@@ -754,7 +764,6 @@ static const struct net_device_ops bat_netdev_ops = {
.ndo_start_xmit = interface_tx,
.ndo_validate_addr = eth_validate_addr
};
-#endif
static void interface_setup(struct net_device *dev)
{
@@ -763,16 +772,7 @@ static void interface_setup(struct net_device *dev)
ether_setup(dev);
-#ifdef HAVE_NET_DEVICE_OPS
dev->netdev_ops = &bat_netdev_ops;
-#else
- dev->open = interface_open;
- dev->stop = interface_release;
- dev->get_stats = interface_stats;
- dev->set_mac_address = interface_set_mac_addr;
- dev->change_mtu = interface_change_mtu;
- dev->hard_start_xmit = interface_tx;
-#endif
dev->destructor = free_netdev;
dev->tx_queue_len = 0;
@@ -790,22 +790,19 @@ static void interface_setup(struct net_device *dev)
SET_ETHTOOL_OPS(dev, &bat_ethtool_ops);
- memset(priv, 0, sizeof(struct bat_priv));
+ memset(priv, 0, sizeof(*priv));
}
-struct net_device *softif_create(char *name)
+struct net_device *softif_create(const char *name)
{
struct net_device *soft_iface;
struct bat_priv *bat_priv;
int ret;
- soft_iface = alloc_netdev(sizeof(struct bat_priv) , name,
- interface_setup);
+ soft_iface = alloc_netdev(sizeof(*bat_priv), name, interface_setup);
- if (!soft_iface) {
- pr_err("Unable to allocate the batman interface: %s\n", name);
+ if (!soft_iface)
goto out;
- }
ret = register_netdevice(soft_iface);
if (ret < 0) {
@@ -818,6 +815,7 @@ struct net_device *softif_create(char *name)
atomic_set(&bat_priv->aggregated_ogms, 1);
atomic_set(&bat_priv->bonding, 0);
+ atomic_set(&bat_priv->ap_isolation, 0);
atomic_set(&bat_priv->vis_mode, VIS_TYPE_CLIENT_UPDATE);
atomic_set(&bat_priv->gw_mode, GW_MODE_OFF);
atomic_set(&bat_priv->gw_sel_class, 20);
@@ -831,7 +829,13 @@ struct net_device *softif_create(char *name)
atomic_set(&bat_priv->mesh_state, MESH_INACTIVE);
atomic_set(&bat_priv->bcast_seqno, 1);
- atomic_set(&bat_priv->tt_local_changed, 0);
+ atomic_set(&bat_priv->ttvn, 0);
+ atomic_set(&bat_priv->tt_local_changes, 0);
+ atomic_set(&bat_priv->tt_ogm_append_cnt, 0);
+
+ bat_priv->tt_buff = NULL;
+ bat_priv->tt_buff_len = 0;
+ bat_priv->tt_poss_change = false;
bat_priv->primary_if = NULL;
bat_priv->num_ifaces = 0;
@@ -872,15 +876,10 @@ void softif_destroy(struct net_device *soft_iface)
unregister_netdevice(soft_iface);
}
-int softif_is_valid(struct net_device *net_dev)
+int softif_is_valid(const struct net_device *net_dev)
{
-#ifdef HAVE_NET_DEVICE_OPS
if (net_dev->netdev_ops->ndo_start_xmit == interface_tx)
return 1;
-#else
- if (net_dev->hard_start_xmit == interface_tx)
- return 1;
-#endif
return 0;
}
@@ -924,4 +923,3 @@ static u32 bat_get_link(struct net_device *dev)
{
return 1;
}
-
diff --git a/net/batman-adv/soft-interface.h b/net/batman-adv/soft-interface.h
index 4789b6f..001546f 100644
--- a/net/batman-adv/soft-interface.h
+++ b/net/batman-adv/soft-interface.h
@@ -25,12 +25,11 @@
int my_skb_head_push(struct sk_buff *skb, unsigned int len);
int softif_neigh_seq_print_text(struct seq_file *seq, void *offset);
void softif_neigh_purge(struct bat_priv *bat_priv);
-int interface_tx(struct sk_buff *skb, struct net_device *soft_iface);
void interface_rx(struct net_device *soft_iface,
struct sk_buff *skb, struct hard_iface *recv_if,
int hdr_size);
-struct net_device *softif_create(char *name);
+struct net_device *softif_create(const char *name);
void softif_destroy(struct net_device *soft_iface);
-int softif_is_valid(struct net_device *net_dev);
+int softif_is_valid(const struct net_device *net_dev);
#endif /* _NET_BATMAN_ADV_SOFT_INTERFACE_H_ */
diff --git a/net/batman-adv/translation-table.c b/net/batman-adv/translation-table.c
index 7b72966..088af45 100644
--- a/net/batman-adv/translation-table.c
+++ b/net/batman-adv/translation-table.c
@@ -23,38 +23,45 @@
#include "translation-table.h"
#include "soft-interface.h"
#include "hard-interface.h"
+#include "send.h"
#include "hash.h"
#include "originator.h"
+#include "routing.h"
-static void tt_local_purge(struct work_struct *work);
-static void _tt_global_del_orig(struct bat_priv *bat_priv,
- struct tt_global_entry *tt_global_entry,
- char *message);
+#include <linux/crc16.h>
+
+static void _tt_global_del(struct bat_priv *bat_priv,
+ struct tt_global_entry *tt_global_entry,
+ const char *message);
+static void tt_purge(struct work_struct *work);
/* returns 1 if they are the same mac addr */
-static int compare_ltt(struct hlist_node *node, void *data2)
+static int compare_ltt(const struct hlist_node *node, const void *data2)
{
- void *data1 = container_of(node, struct tt_local_entry, hash_entry);
+ const void *data1 = container_of(node, struct tt_local_entry,
+ hash_entry);
return (memcmp(data1, data2, ETH_ALEN) == 0 ? 1 : 0);
}
/* returns 1 if they are the same mac addr */
-static int compare_gtt(struct hlist_node *node, void *data2)
+static int compare_gtt(const struct hlist_node *node, const void *data2)
{
- void *data1 = container_of(node, struct tt_global_entry, hash_entry);
+ const void *data1 = container_of(node, struct tt_global_entry,
+ hash_entry);
return (memcmp(data1, data2, ETH_ALEN) == 0 ? 1 : 0);
}
-static void tt_local_start_timer(struct bat_priv *bat_priv)
+static void tt_start_timer(struct bat_priv *bat_priv)
{
- INIT_DELAYED_WORK(&bat_priv->tt_work, tt_local_purge);
- queue_delayed_work(bat_event_workqueue, &bat_priv->tt_work, 10 * HZ);
+ INIT_DELAYED_WORK(&bat_priv->tt_work, tt_purge);
+ queue_delayed_work(bat_event_workqueue, &bat_priv->tt_work,
+ msecs_to_jiffies(5000));
}
static struct tt_local_entry *tt_local_hash_find(struct bat_priv *bat_priv,
- void *data)
+ const void *data)
{
struct hashtable_t *hash = bat_priv->tt_local_hash;
struct hlist_head *head;
@@ -73,6 +80,9 @@ static struct tt_local_entry *tt_local_hash_find(struct bat_priv *bat_priv,
if (!compare_eth(tt_local_entry, data))
continue;
+ if (!atomic_inc_not_zero(&tt_local_entry->refcount))
+ continue;
+
tt_local_entry_tmp = tt_local_entry;
break;
}
@@ -82,7 +92,7 @@ static struct tt_local_entry *tt_local_hash_find(struct bat_priv *bat_priv,
}
static struct tt_global_entry *tt_global_hash_find(struct bat_priv *bat_priv,
- void *data)
+ const void *data)
{
struct hashtable_t *hash = bat_priv->tt_global_hash;
struct hlist_head *head;
@@ -102,6 +112,9 @@ static struct tt_global_entry *tt_global_hash_find(struct bat_priv *bat_priv,
if (!compare_eth(tt_global_entry, data))
continue;
+ if (!atomic_inc_not_zero(&tt_global_entry->refcount))
+ continue;
+
tt_global_entry_tmp = tt_global_entry;
break;
}
@@ -110,7 +123,66 @@ static struct tt_global_entry *tt_global_hash_find(struct bat_priv *bat_priv,
return tt_global_entry_tmp;
}
-int tt_local_init(struct bat_priv *bat_priv)
+static bool is_out_of_time(unsigned long starting_time, unsigned long timeout)
+{
+ unsigned long deadline;
+ deadline = starting_time + msecs_to_jiffies(timeout);
+
+ return time_after(jiffies, deadline);
+}
+
+static void tt_local_entry_free_ref(struct tt_local_entry *tt_local_entry)
+{
+ if (atomic_dec_and_test(&tt_local_entry->refcount))
+ kfree_rcu(tt_local_entry, rcu);
+}
+
+static void tt_global_entry_free_rcu(struct rcu_head *rcu)
+{
+ struct tt_global_entry *tt_global_entry;
+
+ tt_global_entry = container_of(rcu, struct tt_global_entry, rcu);
+
+ if (tt_global_entry->orig_node)
+ orig_node_free_ref(tt_global_entry->orig_node);
+
+ kfree(tt_global_entry);
+}
+
+static void tt_global_entry_free_ref(struct tt_global_entry *tt_global_entry)
+{
+ if (atomic_dec_and_test(&tt_global_entry->refcount))
+ call_rcu(&tt_global_entry->rcu, tt_global_entry_free_rcu);
+}
+
+static void tt_local_event(struct bat_priv *bat_priv, const uint8_t *addr,
+ uint8_t flags)
+{
+ struct tt_change_node *tt_change_node;
+
+ tt_change_node = kmalloc(sizeof(*tt_change_node), GFP_ATOMIC);
+
+ if (!tt_change_node)
+ return;
+
+ tt_change_node->change.flags = flags;
+ memcpy(tt_change_node->change.addr, addr, ETH_ALEN);
+
+ spin_lock_bh(&bat_priv->tt_changes_list_lock);
+ /* track the change in the OGMinterval list */
+ list_add_tail(&tt_change_node->list, &bat_priv->tt_changes_list);
+ atomic_inc(&bat_priv->tt_local_changes);
+ spin_unlock_bh(&bat_priv->tt_changes_list_lock);
+
+ atomic_set(&bat_priv->tt_ogm_append_cnt, 0);
+}
+
+int tt_len(int changes_num)
+{
+ return changes_num * sizeof(struct tt_change);
+}
+
+static int tt_local_init(struct bat_priv *bat_priv)
{
if (bat_priv->tt_local_hash)
return 1;
@@ -120,116 +192,119 @@ int tt_local_init(struct bat_priv *bat_priv)
if (!bat_priv->tt_local_hash)
return 0;
- atomic_set(&bat_priv->tt_local_changed, 0);
- tt_local_start_timer(bat_priv);
-
return 1;
}
-void tt_local_add(struct net_device *soft_iface, uint8_t *addr)
+void tt_local_add(struct net_device *soft_iface, const uint8_t *addr,
+ int ifindex)
{
struct bat_priv *bat_priv = netdev_priv(soft_iface);
- struct tt_local_entry *tt_local_entry;
- struct tt_global_entry *tt_global_entry;
- int required_bytes;
+ struct tt_local_entry *tt_local_entry = NULL;
+ struct tt_global_entry *tt_global_entry = NULL;
- spin_lock_bh(&bat_priv->tt_lhash_lock);
tt_local_entry = tt_local_hash_find(bat_priv, addr);
- spin_unlock_bh(&bat_priv->tt_lhash_lock);
if (tt_local_entry) {
tt_local_entry->last_seen = jiffies;
- return;
- }
-
- /* only announce as many hosts as possible in the batman-packet and
- space in batman_packet->num_tt That also should give a limit to
- MAC-flooding. */
- required_bytes = (bat_priv->num_local_tt + 1) * ETH_ALEN;
- required_bytes += BAT_PACKET_LEN;
-
- if ((required_bytes > ETH_DATA_LEN) ||
- (atomic_read(&bat_priv->aggregated_ogms) &&
- required_bytes > MAX_AGGREGATION_BYTES) ||
- (bat_priv->num_local_tt + 1 > 255)) {
- bat_dbg(DBG_ROUTES, bat_priv,
- "Can't add new local tt entry (%pM): "
- "number of local tt entries exceeds packet size\n",
- addr);
- return;
+ goto out;
}
- bat_dbg(DBG_ROUTES, bat_priv,
- "Creating new local tt entry: %pM\n", addr);
-
- tt_local_entry = kmalloc(sizeof(struct tt_local_entry), GFP_ATOMIC);
+ tt_local_entry = kmalloc(sizeof(*tt_local_entry), GFP_ATOMIC);
if (!tt_local_entry)
- return;
+ goto out;
+
+ bat_dbg(DBG_TT, bat_priv,
+ "Creating new local tt entry: %pM (ttvn: %d)\n", addr,
+ (uint8_t)atomic_read(&bat_priv->ttvn));
memcpy(tt_local_entry->addr, addr, ETH_ALEN);
tt_local_entry->last_seen = jiffies;
+ tt_local_entry->flags = NO_FLAGS;
+ if (is_wifi_iface(ifindex))
+ tt_local_entry->flags |= TT_CLIENT_WIFI;
+ atomic_set(&tt_local_entry->refcount, 2);
/* the batman interface mac address should never be purged */
if (compare_eth(addr, soft_iface->dev_addr))
- tt_local_entry->never_purge = 1;
- else
- tt_local_entry->never_purge = 0;
+ tt_local_entry->flags |= TT_CLIENT_NOPURGE;
+
+ tt_local_event(bat_priv, addr, tt_local_entry->flags);
- spin_lock_bh(&bat_priv->tt_lhash_lock);
+ /* The local entry has to be marked as NEW to avoid to send it in
+ * a full table response going out before the next ttvn increment
+ * (consistency check) */
+ tt_local_entry->flags |= TT_CLIENT_NEW;
hash_add(bat_priv->tt_local_hash, compare_ltt, choose_orig,
tt_local_entry, &tt_local_entry->hash_entry);
- bat_priv->num_local_tt++;
- atomic_set(&bat_priv->tt_local_changed, 1);
-
- spin_unlock_bh(&bat_priv->tt_lhash_lock);
/* remove address from global hash if present */
- spin_lock_bh(&bat_priv->tt_ghash_lock);
-
tt_global_entry = tt_global_hash_find(bat_priv, addr);
+ /* Check whether it is a roaming! */
+ if (tt_global_entry) {
+ /* This node is probably going to update its tt table */
+ tt_global_entry->orig_node->tt_poss_change = true;
+ /* The global entry has to be marked as ROAMING and has to be
+ * kept for consistency purpose */
+ tt_global_entry->flags |= TT_CLIENT_ROAM;
+ tt_global_entry->roam_at = jiffies;
+
+ send_roam_adv(bat_priv, tt_global_entry->addr,
+ tt_global_entry->orig_node);
+ }
+out:
+ if (tt_local_entry)
+ tt_local_entry_free_ref(tt_local_entry);
if (tt_global_entry)
- _tt_global_del_orig(bat_priv, tt_global_entry,
- "local tt received");
-
- spin_unlock_bh(&bat_priv->tt_ghash_lock);
+ tt_global_entry_free_ref(tt_global_entry);
}
-int tt_local_fill_buffer(struct bat_priv *bat_priv,
- unsigned char *buff, int buff_len)
+int tt_changes_fill_buffer(struct bat_priv *bat_priv,
+ unsigned char *buff, int buff_len)
{
- struct hashtable_t *hash = bat_priv->tt_local_hash;
- struct tt_local_entry *tt_local_entry;
- struct hlist_node *node;
- struct hlist_head *head;
- int i, count = 0;
-
- spin_lock_bh(&bat_priv->tt_lhash_lock);
-
- for (i = 0; i < hash->size; i++) {
- head = &hash->table[i];
+ int count = 0, tot_changes = 0;
+ struct tt_change_node *entry, *safe;
- rcu_read_lock();
- hlist_for_each_entry_rcu(tt_local_entry, node,
- head, hash_entry) {
- if (buff_len < (count + 1) * ETH_ALEN)
- break;
+ if (buff_len > 0)
+ tot_changes = buff_len / tt_len(1);
- memcpy(buff + (count * ETH_ALEN), tt_local_entry->addr,
- ETH_ALEN);
+ spin_lock_bh(&bat_priv->tt_changes_list_lock);
+ atomic_set(&bat_priv->tt_local_changes, 0);
+ list_for_each_entry_safe(entry, safe, &bat_priv->tt_changes_list,
+ list) {
+ if (count < tot_changes) {
+ memcpy(buff + tt_len(count),
+ &entry->change, sizeof(struct tt_change));
count++;
}
- rcu_read_unlock();
+ list_del(&entry->list);
+ kfree(entry);
}
+ spin_unlock_bh(&bat_priv->tt_changes_list_lock);
+
+ /* Keep the buffer for possible tt_request */
+ spin_lock_bh(&bat_priv->tt_buff_lock);
+ kfree(bat_priv->tt_buff);
+ bat_priv->tt_buff_len = 0;
+ bat_priv->tt_buff = NULL;
+ /* We check whether this new OGM has no changes due to size
+ * problems */
+ if (buff_len > 0) {
+ /**
+ * if kmalloc() fails we will reply with the full table
+ * instead of providing the diff
+ */
+ bat_priv->tt_buff = kmalloc(buff_len, GFP_ATOMIC);
+ if (bat_priv->tt_buff) {
+ memcpy(bat_priv->tt_buff, buff, buff_len);
+ bat_priv->tt_buff_len = buff_len;
+ }
+ }
+ spin_unlock_bh(&bat_priv->tt_buff_lock);
- /* if we did not get all new local tts see you next time ;-) */
- if (count == bat_priv->num_local_tt)
- atomic_set(&bat_priv->tt_local_changed, 0);
-
- spin_unlock_bh(&bat_priv->tt_lhash_lock);
- return count;
+ return tot_changes;
}
int tt_local_seq_print_text(struct seq_file *seq, void *offset)
@@ -261,10 +336,8 @@ int tt_local_seq_print_text(struct seq_file *seq, void *offset)
}
seq_printf(seq, "Locally retrieved addresses (from %s) "
- "announced via TT:\n",
- net_dev->name);
-
- spin_lock_bh(&bat_priv->tt_lhash_lock);
+ "announced via TT (TTVN: %u):\n",
+ net_dev->name, (uint8_t)atomic_read(&bat_priv->ttvn));
buf_size = 1;
/* Estimate length for: " * xx:xx:xx:xx:xx:xx\n" */
@@ -273,13 +346,12 @@ int tt_local_seq_print_text(struct seq_file *seq, void *offset)
rcu_read_lock();
__hlist_for_each_rcu(node, head)
- buf_size += 21;
+ buf_size += 29;
rcu_read_unlock();
}
buff = kmalloc(buf_size, GFP_ATOMIC);
if (!buff) {
- spin_unlock_bh(&bat_priv->tt_lhash_lock);
ret = -ENOMEM;
goto out;
}
@@ -293,14 +365,23 @@ int tt_local_seq_print_text(struct seq_file *seq, void *offset)
rcu_read_lock();
hlist_for_each_entry_rcu(tt_local_entry, node,
head, hash_entry) {
- pos += snprintf(buff + pos, 22, " * %pM\n",
- tt_local_entry->addr);
+ pos += snprintf(buff + pos, 30, " * %pM "
+ "[%c%c%c%c%c]\n",
+ tt_local_entry->addr,
+ (tt_local_entry->flags &
+ TT_CLIENT_ROAM ? 'R' : '.'),
+ (tt_local_entry->flags &
+ TT_CLIENT_NOPURGE ? 'P' : '.'),
+ (tt_local_entry->flags &
+ TT_CLIENT_NEW ? 'N' : '.'),
+ (tt_local_entry->flags &
+ TT_CLIENT_PENDING ? 'X' : '.'),
+ (tt_local_entry->flags &
+ TT_CLIENT_WIFI ? 'W' : '.'));
}
rcu_read_unlock();
}
- spin_unlock_bh(&bat_priv->tt_lhash_lock);
-
seq_printf(seq, "%s", buff);
kfree(buff);
out:
@@ -309,92 +390,109 @@ out:
return ret;
}
-static void _tt_local_del(struct hlist_node *node, void *arg)
+static void tt_local_set_pending(struct bat_priv *bat_priv,
+ struct tt_local_entry *tt_local_entry,
+ uint16_t flags)
{
- struct bat_priv *bat_priv = (struct bat_priv *)arg;
- void *data = container_of(node, struct tt_local_entry, hash_entry);
+ tt_local_event(bat_priv, tt_local_entry->addr,
+ tt_local_entry->flags | flags);
- kfree(data);
- bat_priv->num_local_tt--;
- atomic_set(&bat_priv->tt_local_changed, 1);
+ /* The local client has to be marked as "pending to be removed" but has
+ * to be kept in the table in order to send it in a full table
+ * response issued before the net ttvn increment (consistency check) */
+ tt_local_entry->flags |= TT_CLIENT_PENDING;
}
-static void tt_local_del(struct bat_priv *bat_priv,
- struct tt_local_entry *tt_local_entry,
- char *message)
+void tt_local_remove(struct bat_priv *bat_priv, const uint8_t *addr,
+ const char *message, bool roaming)
{
- bat_dbg(DBG_ROUTES, bat_priv, "Deleting local tt entry (%pM): %s\n",
- tt_local_entry->addr, message);
-
- hash_remove(bat_priv->tt_local_hash, compare_ltt, choose_orig,
- tt_local_entry->addr);
- _tt_local_del(&tt_local_entry->hash_entry, bat_priv);
-}
-
-void tt_local_remove(struct bat_priv *bat_priv,
- uint8_t *addr, char *message)
-{
- struct tt_local_entry *tt_local_entry;
-
- spin_lock_bh(&bat_priv->tt_lhash_lock);
+ struct tt_local_entry *tt_local_entry = NULL;
tt_local_entry = tt_local_hash_find(bat_priv, addr);
+ if (!tt_local_entry)
+ goto out;
- if (tt_local_entry)
- tt_local_del(bat_priv, tt_local_entry, message);
+ tt_local_set_pending(bat_priv, tt_local_entry, TT_CLIENT_DEL |
+ (roaming ? TT_CLIENT_ROAM : NO_FLAGS));
- spin_unlock_bh(&bat_priv->tt_lhash_lock);
+ bat_dbg(DBG_TT, bat_priv, "Local tt entry (%pM) pending to be removed: "
+ "%s\n", tt_local_entry->addr, message);
+out:
+ if (tt_local_entry)
+ tt_local_entry_free_ref(tt_local_entry);
}
-static void tt_local_purge(struct work_struct *work)
+static void tt_local_purge(struct bat_priv *bat_priv)
{
- struct delayed_work *delayed_work =
- container_of(work, struct delayed_work, work);
- struct bat_priv *bat_priv =
- container_of(delayed_work, struct bat_priv, tt_work);
struct hashtable_t *hash = bat_priv->tt_local_hash;
struct tt_local_entry *tt_local_entry;
struct hlist_node *node, *node_tmp;
struct hlist_head *head;
- unsigned long timeout;
+ spinlock_t *list_lock; /* protects write access to the hash lists */
int i;
- spin_lock_bh(&bat_priv->tt_lhash_lock);
-
for (i = 0; i < hash->size; i++) {
head = &hash->table[i];
+ list_lock = &hash->list_locks[i];
+ spin_lock_bh(list_lock);
hlist_for_each_entry_safe(tt_local_entry, node, node_tmp,
head, hash_entry) {
- if (tt_local_entry->never_purge)
+ if (tt_local_entry->flags & TT_CLIENT_NOPURGE)
continue;
- timeout = tt_local_entry->last_seen;
- timeout += TT_LOCAL_TIMEOUT * HZ;
+ /* entry already marked for deletion */
+ if (tt_local_entry->flags & TT_CLIENT_PENDING)
+ continue;
- if (time_before(jiffies, timeout))
+ if (!is_out_of_time(tt_local_entry->last_seen,
+ TT_LOCAL_TIMEOUT * 1000))
continue;
- tt_local_del(bat_priv, tt_local_entry,
- "address timed out");
+ tt_local_set_pending(bat_priv, tt_local_entry,
+ TT_CLIENT_DEL);
+ bat_dbg(DBG_TT, bat_priv, "Local tt entry (%pM) "
+ "pending to be removed: timed out\n",
+ tt_local_entry->addr);
}
+ spin_unlock_bh(list_lock);
}
- spin_unlock_bh(&bat_priv->tt_lhash_lock);
- tt_local_start_timer(bat_priv);
}
-void tt_local_free(struct bat_priv *bat_priv)
+static void tt_local_table_free(struct bat_priv *bat_priv)
{
+ struct hashtable_t *hash;
+ spinlock_t *list_lock; /* protects write access to the hash lists */
+ struct tt_local_entry *tt_local_entry;
+ struct hlist_node *node, *node_tmp;
+ struct hlist_head *head;
+ int i;
+
if (!bat_priv->tt_local_hash)
return;
- cancel_delayed_work_sync(&bat_priv->tt_work);
- hash_delete(bat_priv->tt_local_hash, _tt_local_del, bat_priv);
+ hash = bat_priv->tt_local_hash;
+
+ for (i = 0; i < hash->size; i++) {
+ head = &hash->table[i];
+ list_lock = &hash->list_locks[i];
+
+ spin_lock_bh(list_lock);
+ hlist_for_each_entry_safe(tt_local_entry, node, node_tmp,
+ head, hash_entry) {
+ hlist_del_rcu(node);
+ tt_local_entry_free_ref(tt_local_entry);
+ }
+ spin_unlock_bh(list_lock);
+ }
+
+ hash_destroy(hash);
+
bat_priv->tt_local_hash = NULL;
}
-int tt_global_init(struct bat_priv *bat_priv)
+static int tt_global_init(struct bat_priv *bat_priv)
{
if (bat_priv->tt_global_hash)
return 1;
@@ -407,74 +505,82 @@ int tt_global_init(struct bat_priv *bat_priv)
return 1;
}
-void tt_global_add_orig(struct bat_priv *bat_priv,
- struct orig_node *orig_node,
- unsigned char *tt_buff, int tt_buff_len)
+static void tt_changes_list_free(struct bat_priv *bat_priv)
{
- struct tt_global_entry *tt_global_entry;
- struct tt_local_entry *tt_local_entry;
- int tt_buff_count = 0;
- unsigned char *tt_ptr;
-
- while ((tt_buff_count + 1) * ETH_ALEN <= tt_buff_len) {
- spin_lock_bh(&bat_priv->tt_ghash_lock);
-
- tt_ptr = tt_buff + (tt_buff_count * ETH_ALEN);
- tt_global_entry = tt_global_hash_find(bat_priv, tt_ptr);
+ struct tt_change_node *entry, *safe;
- if (!tt_global_entry) {
- spin_unlock_bh(&bat_priv->tt_ghash_lock);
+ spin_lock_bh(&bat_priv->tt_changes_list_lock);
- tt_global_entry =
- kmalloc(sizeof(struct tt_global_entry),
- GFP_ATOMIC);
-
- if (!tt_global_entry)
- break;
+ list_for_each_entry_safe(entry, safe, &bat_priv->tt_changes_list,
+ list) {
+ list_del(&entry->list);
+ kfree(entry);
+ }
- memcpy(tt_global_entry->addr, tt_ptr, ETH_ALEN);
+ atomic_set(&bat_priv->tt_local_changes, 0);
+ spin_unlock_bh(&bat_priv->tt_changes_list_lock);
+}
- bat_dbg(DBG_ROUTES, bat_priv,
- "Creating new global tt entry: "
- "%pM (via %pM)\n",
- tt_global_entry->addr, orig_node->orig);
+/* caller must hold orig_node refcount */
+int tt_global_add(struct bat_priv *bat_priv, struct orig_node *orig_node,
+ const unsigned char *tt_addr, uint8_t ttvn, bool roaming,
+ bool wifi)
+{
+ struct tt_global_entry *tt_global_entry;
+ struct orig_node *orig_node_tmp;
+ int ret = 0;
- spin_lock_bh(&bat_priv->tt_ghash_lock);
- hash_add(bat_priv->tt_global_hash, compare_gtt,
- choose_orig, tt_global_entry,
- &tt_global_entry->hash_entry);
+ tt_global_entry = tt_global_hash_find(bat_priv, tt_addr);
- }
+ if (!tt_global_entry) {
+ tt_global_entry =
+ kmalloc(sizeof(*tt_global_entry),
+ GFP_ATOMIC);
+ if (!tt_global_entry)
+ goto out;
+ memcpy(tt_global_entry->addr, tt_addr, ETH_ALEN);
+ /* Assign the new orig_node */
+ atomic_inc(&orig_node->refcount);
tt_global_entry->orig_node = orig_node;
- spin_unlock_bh(&bat_priv->tt_ghash_lock);
-
- /* remove address from local hash if present */
- spin_lock_bh(&bat_priv->tt_lhash_lock);
-
- tt_ptr = tt_buff + (tt_buff_count * ETH_ALEN);
- tt_local_entry = tt_local_hash_find(bat_priv, tt_ptr);
-
- if (tt_local_entry)
- tt_local_del(bat_priv, tt_local_entry,
- "global tt received");
-
- spin_unlock_bh(&bat_priv->tt_lhash_lock);
-
- tt_buff_count++;
+ tt_global_entry->ttvn = ttvn;
+ tt_global_entry->flags = NO_FLAGS;
+ tt_global_entry->roam_at = 0;
+ atomic_set(&tt_global_entry->refcount, 2);
+
+ hash_add(bat_priv->tt_global_hash, compare_gtt,
+ choose_orig, tt_global_entry,
+ &tt_global_entry->hash_entry);
+ atomic_inc(&orig_node->tt_size);
+ } else {
+ if (tt_global_entry->orig_node != orig_node) {
+ atomic_dec(&tt_global_entry->orig_node->tt_size);
+ orig_node_tmp = tt_global_entry->orig_node;
+ atomic_inc(&orig_node->refcount);
+ tt_global_entry->orig_node = orig_node;
+ orig_node_free_ref(orig_node_tmp);
+ atomic_inc(&orig_node->tt_size);
+ }
+ tt_global_entry->ttvn = ttvn;
+ tt_global_entry->flags = NO_FLAGS;
+ tt_global_entry->roam_at = 0;
}
- /* initialize, and overwrite if malloc succeeds */
- orig_node->tt_buff = NULL;
- orig_node->tt_buff_len = 0;
+ if (wifi)
+ tt_global_entry->flags |= TT_CLIENT_WIFI;
- if (tt_buff_len > 0) {
- orig_node->tt_buff = kmalloc(tt_buff_len, GFP_ATOMIC);
- if (orig_node->tt_buff) {
- memcpy(orig_node->tt_buff, tt_buff, tt_buff_len);
- orig_node->tt_buff_len = tt_buff_len;
- }
- }
+ bat_dbg(DBG_TT, bat_priv,
+ "Creating new global tt entry: %pM (via %pM)\n",
+ tt_global_entry->addr, orig_node->orig);
+
+ /* remove address from local hash if present */
+ tt_local_remove(bat_priv, tt_global_entry->addr,
+ "global tt received", roaming);
+ ret = 1;
+out:
+ if (tt_global_entry)
+ tt_global_entry_free_ref(tt_global_entry);
+ return ret;
}
int tt_global_seq_print_text(struct seq_file *seq, void *offset)
@@ -508,26 +614,27 @@ int tt_global_seq_print_text(struct seq_file *seq, void *offset)
seq_printf(seq,
"Globally announced TT entries received via the mesh %s\n",
net_dev->name);
-
- spin_lock_bh(&bat_priv->tt_ghash_lock);
+ seq_printf(seq, " %-13s %s %-15s %s %s\n",
+ "Client", "(TTVN)", "Originator", "(Curr TTVN)", "Flags");
buf_size = 1;
- /* Estimate length for: " * xx:xx:xx:xx:xx:xx via xx:xx:xx:xx:xx:xx\n"*/
+ /* Estimate length for: " * xx:xx:xx:xx:xx:xx (ttvn) via
+ * xx:xx:xx:xx:xx:xx (cur_ttvn)\n"*/
for (i = 0; i < hash->size; i++) {
head = &hash->table[i];
rcu_read_lock();
__hlist_for_each_rcu(node, head)
- buf_size += 43;
+ buf_size += 67;
rcu_read_unlock();
}
buff = kmalloc(buf_size, GFP_ATOMIC);
if (!buff) {
- spin_unlock_bh(&bat_priv->tt_ghash_lock);
ret = -ENOMEM;
goto out;
}
+
buff[0] = '\0';
pos = 0;
@@ -537,16 +644,24 @@ int tt_global_seq_print_text(struct seq_file *seq, void *offset)
rcu_read_lock();
hlist_for_each_entry_rcu(tt_global_entry, node,
head, hash_entry) {
- pos += snprintf(buff + pos, 44,
- " * %pM via %pM\n",
- tt_global_entry->addr,
- tt_global_entry->orig_node->orig);
+ pos += snprintf(buff + pos, 69,
+ " * %pM (%3u) via %pM (%3u) "
+ "[%c%c%c]\n", tt_global_entry->addr,
+ tt_global_entry->ttvn,
+ tt_global_entry->orig_node->orig,
+ (uint8_t) atomic_read(
+ &tt_global_entry->orig_node->
+ last_ttvn),
+ (tt_global_entry->flags &
+ TT_CLIENT_ROAM ? 'R' : '.'),
+ (tt_global_entry->flags &
+ TT_CLIENT_PENDING ? 'X' : '.'),
+ (tt_global_entry->flags &
+ TT_CLIENT_WIFI ? 'W' : '.'));
}
rcu_read_unlock();
}
- spin_unlock_bh(&bat_priv->tt_ghash_lock);
-
seq_printf(seq, "%s", buff);
kfree(buff);
out:
@@ -555,84 +670,1231 @@ out:
return ret;
}
-static void _tt_global_del_orig(struct bat_priv *bat_priv,
- struct tt_global_entry *tt_global_entry,
- char *message)
+static void _tt_global_del(struct bat_priv *bat_priv,
+ struct tt_global_entry *tt_global_entry,
+ const char *message)
{
- bat_dbg(DBG_ROUTES, bat_priv,
+ if (!tt_global_entry)
+ goto out;
+
+ bat_dbg(DBG_TT, bat_priv,
"Deleting global tt entry %pM (via %pM): %s\n",
tt_global_entry->addr, tt_global_entry->orig_node->orig,
message);
+ atomic_dec(&tt_global_entry->orig_node->tt_size);
+
hash_remove(bat_priv->tt_global_hash, compare_gtt, choose_orig,
tt_global_entry->addr);
- kfree(tt_global_entry);
+out:
+ if (tt_global_entry)
+ tt_global_entry_free_ref(tt_global_entry);
+}
+
+void tt_global_del(struct bat_priv *bat_priv,
+ struct orig_node *orig_node, const unsigned char *addr,
+ const char *message, bool roaming)
+{
+ struct tt_global_entry *tt_global_entry = NULL;
+ struct tt_local_entry *tt_local_entry = NULL;
+
+ tt_global_entry = tt_global_hash_find(bat_priv, addr);
+ if (!tt_global_entry)
+ goto out;
+
+ if (tt_global_entry->orig_node == orig_node) {
+ if (roaming) {
+ /* if we are deleting a global entry due to a roam
+ * event, there are two possibilities:
+ * 1) the client roamed from node A to node B => we mark
+ * it with TT_CLIENT_ROAM, we start a timer and we
+ * wait for node B to claim it. In case of timeout
+ * the entry is purged.
+ * 2) the client roamed to us => we can directly delete
+ * the global entry, since it is useless now. */
+ tt_local_entry = tt_local_hash_find(bat_priv,
+ tt_global_entry->addr);
+ if (!tt_local_entry) {
+ tt_global_entry->flags |= TT_CLIENT_ROAM;
+ tt_global_entry->roam_at = jiffies;
+ goto out;
+ }
+ }
+ _tt_global_del(bat_priv, tt_global_entry, message);
+ }
+out:
+ if (tt_global_entry)
+ tt_global_entry_free_ref(tt_global_entry);
+ if (tt_local_entry)
+ tt_local_entry_free_ref(tt_local_entry);
}
void tt_global_del_orig(struct bat_priv *bat_priv,
- struct orig_node *orig_node, char *message)
+ struct orig_node *orig_node, const char *message)
{
struct tt_global_entry *tt_global_entry;
- int tt_buff_count = 0;
- unsigned char *tt_ptr;
+ int i;
+ struct hashtable_t *hash = bat_priv->tt_global_hash;
+ struct hlist_node *node, *safe;
+ struct hlist_head *head;
+ spinlock_t *list_lock; /* protects write access to the hash lists */
- if (orig_node->tt_buff_len == 0)
+ if (!hash)
return;
- spin_lock_bh(&bat_priv->tt_ghash_lock);
-
- while ((tt_buff_count + 1) * ETH_ALEN <= orig_node->tt_buff_len) {
- tt_ptr = orig_node->tt_buff + (tt_buff_count * ETH_ALEN);
- tt_global_entry = tt_global_hash_find(bat_priv, tt_ptr);
-
- if ((tt_global_entry) &&
- (tt_global_entry->orig_node == orig_node))
- _tt_global_del_orig(bat_priv, tt_global_entry,
- message);
+ for (i = 0; i < hash->size; i++) {
+ head = &hash->table[i];
+ list_lock = &hash->list_locks[i];
- tt_buff_count++;
+ spin_lock_bh(list_lock);
+ hlist_for_each_entry_safe(tt_global_entry, node, safe,
+ head, hash_entry) {
+ if (tt_global_entry->orig_node == orig_node) {
+ bat_dbg(DBG_TT, bat_priv,
+ "Deleting global tt entry %pM "
+ "(via %pM): originator time out\n",
+ tt_global_entry->addr,
+ tt_global_entry->orig_node->orig);
+ hlist_del_rcu(node);
+ tt_global_entry_free_ref(tt_global_entry);
+ }
+ }
+ spin_unlock_bh(list_lock);
}
-
- spin_unlock_bh(&bat_priv->tt_ghash_lock);
-
- orig_node->tt_buff_len = 0;
- kfree(orig_node->tt_buff);
- orig_node->tt_buff = NULL;
+ atomic_set(&orig_node->tt_size, 0);
}
-static void tt_global_del(struct hlist_node *node, void *arg)
+static void tt_global_roam_purge(struct bat_priv *bat_priv)
{
- void *data = container_of(node, struct tt_global_entry, hash_entry);
+ struct hashtable_t *hash = bat_priv->tt_global_hash;
+ struct tt_global_entry *tt_global_entry;
+ struct hlist_node *node, *node_tmp;
+ struct hlist_head *head;
+ spinlock_t *list_lock; /* protects write access to the hash lists */
+ int i;
+
+ for (i = 0; i < hash->size; i++) {
+ head = &hash->table[i];
+ list_lock = &hash->list_locks[i];
+
+ spin_lock_bh(list_lock);
+ hlist_for_each_entry_safe(tt_global_entry, node, node_tmp,
+ head, hash_entry) {
+ if (!(tt_global_entry->flags & TT_CLIENT_ROAM))
+ continue;
+ if (!is_out_of_time(tt_global_entry->roam_at,
+ TT_CLIENT_ROAM_TIMEOUT * 1000))
+ continue;
+
+ bat_dbg(DBG_TT, bat_priv, "Deleting global "
+ "tt entry (%pM): Roaming timeout\n",
+ tt_global_entry->addr);
+ atomic_dec(&tt_global_entry->orig_node->tt_size);
+ hlist_del_rcu(node);
+ tt_global_entry_free_ref(tt_global_entry);
+ }
+ spin_unlock_bh(list_lock);
+ }
- kfree(data);
}
-void tt_global_free(struct bat_priv *bat_priv)
+static void tt_global_table_free(struct bat_priv *bat_priv)
{
+ struct hashtable_t *hash;
+ spinlock_t *list_lock; /* protects write access to the hash lists */
+ struct tt_global_entry *tt_global_entry;
+ struct hlist_node *node, *node_tmp;
+ struct hlist_head *head;
+ int i;
+
if (!bat_priv->tt_global_hash)
return;
- hash_delete(bat_priv->tt_global_hash, tt_global_del, NULL);
+ hash = bat_priv->tt_global_hash;
+
+ for (i = 0; i < hash->size; i++) {
+ head = &hash->table[i];
+ list_lock = &hash->list_locks[i];
+
+ spin_lock_bh(list_lock);
+ hlist_for_each_entry_safe(tt_global_entry, node, node_tmp,
+ head, hash_entry) {
+ hlist_del_rcu(node);
+ tt_global_entry_free_ref(tt_global_entry);
+ }
+ spin_unlock_bh(list_lock);
+ }
+
+ hash_destroy(hash);
+
bat_priv->tt_global_hash = NULL;
}
-struct orig_node *transtable_search(struct bat_priv *bat_priv, uint8_t *addr)
+static bool _is_ap_isolated(struct tt_local_entry *tt_local_entry,
+ struct tt_global_entry *tt_global_entry)
{
- struct tt_global_entry *tt_global_entry;
+ bool ret = false;
+
+ if (tt_local_entry->flags & TT_CLIENT_WIFI &&
+ tt_global_entry->flags & TT_CLIENT_WIFI)
+ ret = true;
+
+ return ret;
+}
+
+struct orig_node *transtable_search(struct bat_priv *bat_priv,
+ const uint8_t *src, const uint8_t *addr)
+{
+ struct tt_local_entry *tt_local_entry = NULL;
+ struct tt_global_entry *tt_global_entry = NULL;
struct orig_node *orig_node = NULL;
- spin_lock_bh(&bat_priv->tt_ghash_lock);
- tt_global_entry = tt_global_hash_find(bat_priv, addr);
+ if (src && atomic_read(&bat_priv->ap_isolation)) {
+ tt_local_entry = tt_local_hash_find(bat_priv, src);
+ if (!tt_local_entry)
+ goto out;
+ }
+ tt_global_entry = tt_global_hash_find(bat_priv, addr);
if (!tt_global_entry)
goto out;
+ /* check whether the clients should not communicate due to AP
+ * isolation */
+ if (tt_local_entry && _is_ap_isolated(tt_local_entry, tt_global_entry))
+ goto out;
+
if (!atomic_inc_not_zero(&tt_global_entry->orig_node->refcount))
goto out;
+ /* A global client marked as PENDING has already moved from that
+ * originator */
+ if (tt_global_entry->flags & TT_CLIENT_PENDING)
+ goto out;
+
orig_node = tt_global_entry->orig_node;
out:
- spin_unlock_bh(&bat_priv->tt_ghash_lock);
+ if (tt_global_entry)
+ tt_global_entry_free_ref(tt_global_entry);
+ if (tt_local_entry)
+ tt_local_entry_free_ref(tt_local_entry);
+
return orig_node;
}
+
+/* Calculates the checksum of the local table of a given orig_node */
+uint16_t tt_global_crc(struct bat_priv *bat_priv, struct orig_node *orig_node)
+{
+ uint16_t total = 0, total_one;
+ struct hashtable_t *hash = bat_priv->tt_global_hash;
+ struct tt_global_entry *tt_global_entry;
+ struct hlist_node *node;
+ struct hlist_head *head;
+ int i, j;
+
+ for (i = 0; i < hash->size; i++) {
+ head = &hash->table[i];
+
+ rcu_read_lock();
+ hlist_for_each_entry_rcu(tt_global_entry, node,
+ head, hash_entry) {
+ if (compare_eth(tt_global_entry->orig_node,
+ orig_node)) {
+ /* Roaming clients are in the global table for
+ * consistency only. They don't have to be
+ * taken into account while computing the
+ * global crc */
+ if (tt_global_entry->flags & TT_CLIENT_ROAM)
+ continue;
+ total_one = 0;
+ for (j = 0; j < ETH_ALEN; j++)
+ total_one = crc16_byte(total_one,
+ tt_global_entry->addr[j]);
+ total ^= total_one;
+ }
+ }
+ rcu_read_unlock();
+ }
+
+ return total;
+}
+
+/* Calculates the checksum of the local table */
+uint16_t tt_local_crc(struct bat_priv *bat_priv)
+{
+ uint16_t total = 0, total_one;
+ struct hashtable_t *hash = bat_priv->tt_local_hash;
+ struct tt_local_entry *tt_local_entry;
+ struct hlist_node *node;
+ struct hlist_head *head;
+ int i, j;
+
+ for (i = 0; i < hash->size; i++) {
+ head = &hash->table[i];
+
+ rcu_read_lock();
+ hlist_for_each_entry_rcu(tt_local_entry, node,
+ head, hash_entry) {
+ /* not yet committed clients have not to be taken into
+ * account while computing the CRC */
+ if (tt_local_entry->flags & TT_CLIENT_NEW)
+ continue;
+ total_one = 0;
+ for (j = 0; j < ETH_ALEN; j++)
+ total_one = crc16_byte(total_one,
+ tt_local_entry->addr[j]);
+ total ^= total_one;
+ }
+ rcu_read_unlock();
+ }
+
+ return total;
+}
+
+static void tt_req_list_free(struct bat_priv *bat_priv)
+{
+ struct tt_req_node *node, *safe;
+
+ spin_lock_bh(&bat_priv->tt_req_list_lock);
+
+ list_for_each_entry_safe(node, safe, &bat_priv->tt_req_list, list) {
+ list_del(&node->list);
+ kfree(node);
+ }
+
+ spin_unlock_bh(&bat_priv->tt_req_list_lock);
+}
+
+void tt_save_orig_buffer(struct bat_priv *bat_priv, struct orig_node *orig_node,
+ const unsigned char *tt_buff, uint8_t tt_num_changes)
+{
+ uint16_t tt_buff_len = tt_len(tt_num_changes);
+
+ /* Replace the old buffer only if I received something in the
+ * last OGM (the OGM could carry no changes) */
+ spin_lock_bh(&orig_node->tt_buff_lock);
+ if (tt_buff_len > 0) {
+ kfree(orig_node->tt_buff);
+ orig_node->tt_buff_len = 0;
+ orig_node->tt_buff = kmalloc(tt_buff_len, GFP_ATOMIC);
+ if (orig_node->tt_buff) {
+ memcpy(orig_node->tt_buff, tt_buff, tt_buff_len);
+ orig_node->tt_buff_len = tt_buff_len;
+ }
+ }
+ spin_unlock_bh(&orig_node->tt_buff_lock);
+}
+
+static void tt_req_purge(struct bat_priv *bat_priv)
+{
+ struct tt_req_node *node, *safe;
+
+ spin_lock_bh(&bat_priv->tt_req_list_lock);
+ list_for_each_entry_safe(node, safe, &bat_priv->tt_req_list, list) {
+ if (is_out_of_time(node->issued_at,
+ TT_REQUEST_TIMEOUT * 1000)) {
+ list_del(&node->list);
+ kfree(node);
+ }
+ }
+ spin_unlock_bh(&bat_priv->tt_req_list_lock);
+}
+
+/* returns the pointer to the new tt_req_node struct if no request
+ * has already been issued for this orig_node, NULL otherwise */
+static struct tt_req_node *new_tt_req_node(struct bat_priv *bat_priv,
+ struct orig_node *orig_node)
+{
+ struct tt_req_node *tt_req_node_tmp, *tt_req_node = NULL;
+
+ spin_lock_bh(&bat_priv->tt_req_list_lock);
+ list_for_each_entry(tt_req_node_tmp, &bat_priv->tt_req_list, list) {
+ if (compare_eth(tt_req_node_tmp, orig_node) &&
+ !is_out_of_time(tt_req_node_tmp->issued_at,
+ TT_REQUEST_TIMEOUT * 1000))
+ goto unlock;
+ }
+
+ tt_req_node = kmalloc(sizeof(*tt_req_node), GFP_ATOMIC);
+ if (!tt_req_node)
+ goto unlock;
+
+ memcpy(tt_req_node->addr, orig_node->orig, ETH_ALEN);
+ tt_req_node->issued_at = jiffies;
+
+ list_add(&tt_req_node->list, &bat_priv->tt_req_list);
+unlock:
+ spin_unlock_bh(&bat_priv->tt_req_list_lock);
+ return tt_req_node;
+}
+
+/* data_ptr is useless here, but has to be kept to respect the prototype */
+static int tt_local_valid_entry(const void *entry_ptr, const void *data_ptr)
+{
+ const struct tt_local_entry *tt_local_entry = entry_ptr;
+
+ if (tt_local_entry->flags & TT_CLIENT_NEW)
+ return 0;
+ return 1;
+}
+
+static int tt_global_valid_entry(const void *entry_ptr, const void *data_ptr)
+{
+ const struct tt_global_entry *tt_global_entry = entry_ptr;
+ const struct orig_node *orig_node = data_ptr;
+
+ if (tt_global_entry->flags & TT_CLIENT_ROAM)
+ return 0;
+
+ return (tt_global_entry->orig_node == orig_node);
+}
+
+static struct sk_buff *tt_response_fill_table(uint16_t tt_len, uint8_t ttvn,
+ struct hashtable_t *hash,
+ struct hard_iface *primary_if,
+ int (*valid_cb)(const void *,
+ const void *),
+ void *cb_data)
+{
+ struct tt_local_entry *tt_local_entry;
+ struct tt_query_packet *tt_response;
+ struct tt_change *tt_change;
+ struct hlist_node *node;
+ struct hlist_head *head;
+ struct sk_buff *skb = NULL;
+ uint16_t tt_tot, tt_count;
+ ssize_t tt_query_size = sizeof(struct tt_query_packet);
+ int i;
+
+ if (tt_query_size + tt_len > primary_if->soft_iface->mtu) {
+ tt_len = primary_if->soft_iface->mtu - tt_query_size;
+ tt_len -= tt_len % sizeof(struct tt_change);
+ }
+ tt_tot = tt_len / sizeof(struct tt_change);
+
+ skb = dev_alloc_skb(tt_query_size + tt_len + ETH_HLEN);
+ if (!skb)
+ goto out;
+
+ skb_reserve(skb, ETH_HLEN);
+ tt_response = (struct tt_query_packet *)skb_put(skb,
+ tt_query_size + tt_len);
+ tt_response->ttvn = ttvn;
+
+ tt_change = (struct tt_change *)(skb->data + tt_query_size);
+ tt_count = 0;
+
+ rcu_read_lock();
+ for (i = 0; i < hash->size; i++) {
+ head = &hash->table[i];
+
+ hlist_for_each_entry_rcu(tt_local_entry, node,
+ head, hash_entry) {
+ if (tt_count == tt_tot)
+ break;
+
+ if ((valid_cb) && (!valid_cb(tt_local_entry, cb_data)))
+ continue;
+
+ memcpy(tt_change->addr, tt_local_entry->addr, ETH_ALEN);
+ tt_change->flags = NO_FLAGS;
+
+ tt_count++;
+ tt_change++;
+ }
+ }
+ rcu_read_unlock();
+
+ /* store in the message the number of entries we have successfully
+ * copied */
+ tt_response->tt_data = htons(tt_count);
+
+out:
+ return skb;
+}
+
+static int send_tt_request(struct bat_priv *bat_priv,
+ struct orig_node *dst_orig_node,
+ uint8_t ttvn, uint16_t tt_crc, bool full_table)
+{
+ struct sk_buff *skb = NULL;
+ struct tt_query_packet *tt_request;
+ struct neigh_node *neigh_node = NULL;
+ struct hard_iface *primary_if;
+ struct tt_req_node *tt_req_node = NULL;
+ int ret = 1;
+
+ primary_if = primary_if_get_selected(bat_priv);
+ if (!primary_if)
+ goto out;
+
+ /* The new tt_req will be issued only if I'm not waiting for a
+ * reply from the same orig_node yet */
+ tt_req_node = new_tt_req_node(bat_priv, dst_orig_node);
+ if (!tt_req_node)
+ goto out;
+
+ skb = dev_alloc_skb(sizeof(struct tt_query_packet) + ETH_HLEN);
+ if (!skb)
+ goto out;
+
+ skb_reserve(skb, ETH_HLEN);
+
+ tt_request = (struct tt_query_packet *)skb_put(skb,
+ sizeof(struct tt_query_packet));
+
+ tt_request->packet_type = BAT_TT_QUERY;
+ tt_request->version = COMPAT_VERSION;
+ memcpy(tt_request->src, primary_if->net_dev->dev_addr, ETH_ALEN);
+ memcpy(tt_request->dst, dst_orig_node->orig, ETH_ALEN);
+ tt_request->ttl = TTL;
+ tt_request->ttvn = ttvn;
+ tt_request->tt_data = tt_crc;
+ tt_request->flags = TT_REQUEST;
+
+ if (full_table)
+ tt_request->flags |= TT_FULL_TABLE;
+
+ neigh_node = orig_node_get_router(dst_orig_node);
+ if (!neigh_node)
+ goto out;
+
+ bat_dbg(DBG_TT, bat_priv, "Sending TT_REQUEST to %pM via %pM "
+ "[%c]\n", dst_orig_node->orig, neigh_node->addr,
+ (full_table ? 'F' : '.'));
+
+ send_skb_packet(skb, neigh_node->if_incoming, neigh_node->addr);
+ ret = 0;
+
+out:
+ if (neigh_node)
+ neigh_node_free_ref(neigh_node);
+ if (primary_if)
+ hardif_free_ref(primary_if);
+ if (ret)
+ kfree_skb(skb);
+ if (ret && tt_req_node) {
+ spin_lock_bh(&bat_priv->tt_req_list_lock);
+ list_del(&tt_req_node->list);
+ spin_unlock_bh(&bat_priv->tt_req_list_lock);
+ kfree(tt_req_node);
+ }
+ return ret;
+}
+
+static bool send_other_tt_response(struct bat_priv *bat_priv,
+ struct tt_query_packet *tt_request)
+{
+ struct orig_node *req_dst_orig_node = NULL, *res_dst_orig_node = NULL;
+ struct neigh_node *neigh_node = NULL;
+ struct hard_iface *primary_if = NULL;
+ uint8_t orig_ttvn, req_ttvn, ttvn;
+ int ret = false;
+ unsigned char *tt_buff;
+ bool full_table;
+ uint16_t tt_len, tt_tot;
+ struct sk_buff *skb = NULL;
+ struct tt_query_packet *tt_response;
+
+ bat_dbg(DBG_TT, bat_priv,
+ "Received TT_REQUEST from %pM for "
+ "ttvn: %u (%pM) [%c]\n", tt_request->src,
+ tt_request->ttvn, tt_request->dst,
+ (tt_request->flags & TT_FULL_TABLE ? 'F' : '.'));
+
+ /* Let's get the orig node of the REAL destination */
+ req_dst_orig_node = get_orig_node(bat_priv, tt_request->dst);
+ if (!req_dst_orig_node)
+ goto out;
+
+ res_dst_orig_node = get_orig_node(bat_priv, tt_request->src);
+ if (!res_dst_orig_node)
+ goto out;
+
+ neigh_node = orig_node_get_router(res_dst_orig_node);
+ if (!neigh_node)
+ goto out;
+
+ primary_if = primary_if_get_selected(bat_priv);
+ if (!primary_if)
+ goto out;
+
+ orig_ttvn = (uint8_t)atomic_read(&req_dst_orig_node->last_ttvn);
+ req_ttvn = tt_request->ttvn;
+
+ /* I don't have the requested data */
+ if (orig_ttvn != req_ttvn ||
+ tt_request->tt_data != req_dst_orig_node->tt_crc)
+ goto out;
+
+ /* If the full table has been explicitly requested */
+ if (tt_request->flags & TT_FULL_TABLE ||
+ !req_dst_orig_node->tt_buff)
+ full_table = true;
+ else
+ full_table = false;
+
+ /* In this version, fragmentation is not implemented, then
+ * I'll send only one packet with as much TT entries as I can */
+ if (!full_table) {
+ spin_lock_bh(&req_dst_orig_node->tt_buff_lock);
+ tt_len = req_dst_orig_node->tt_buff_len;
+ tt_tot = tt_len / sizeof(struct tt_change);
+
+ skb = dev_alloc_skb(sizeof(struct tt_query_packet) +
+ tt_len + ETH_HLEN);
+ if (!skb)
+ goto unlock;
+
+ skb_reserve(skb, ETH_HLEN);
+ tt_response = (struct tt_query_packet *)skb_put(skb,
+ sizeof(struct tt_query_packet) + tt_len);
+ tt_response->ttvn = req_ttvn;
+ tt_response->tt_data = htons(tt_tot);
+
+ tt_buff = skb->data + sizeof(struct tt_query_packet);
+ /* Copy the last orig_node's OGM buffer */
+ memcpy(tt_buff, req_dst_orig_node->tt_buff,
+ req_dst_orig_node->tt_buff_len);
+
+ spin_unlock_bh(&req_dst_orig_node->tt_buff_lock);
+ } else {
+ tt_len = (uint16_t)atomic_read(&req_dst_orig_node->tt_size) *
+ sizeof(struct tt_change);
+ ttvn = (uint8_t)atomic_read(&req_dst_orig_node->last_ttvn);
+
+ skb = tt_response_fill_table(tt_len, ttvn,
+ bat_priv->tt_global_hash,
+ primary_if, tt_global_valid_entry,
+ req_dst_orig_node);
+ if (!skb)
+ goto out;
+
+ tt_response = (struct tt_query_packet *)skb->data;
+ }
+
+ tt_response->packet_type = BAT_TT_QUERY;
+ tt_response->version = COMPAT_VERSION;
+ tt_response->ttl = TTL;
+ memcpy(tt_response->src, req_dst_orig_node->orig, ETH_ALEN);
+ memcpy(tt_response->dst, tt_request->src, ETH_ALEN);
+ tt_response->flags = TT_RESPONSE;
+
+ if (full_table)
+ tt_response->flags |= TT_FULL_TABLE;
+
+ bat_dbg(DBG_TT, bat_priv,
+ "Sending TT_RESPONSE %pM via %pM for %pM (ttvn: %u)\n",
+ res_dst_orig_node->orig, neigh_node->addr,
+ req_dst_orig_node->orig, req_ttvn);
+
+ send_skb_packet(skb, neigh_node->if_incoming, neigh_node->addr);
+ ret = true;
+ goto out;
+
+unlock:
+ spin_unlock_bh(&req_dst_orig_node->tt_buff_lock);
+
+out:
+ if (res_dst_orig_node)
+ orig_node_free_ref(res_dst_orig_node);
+ if (req_dst_orig_node)
+ orig_node_free_ref(req_dst_orig_node);
+ if (neigh_node)
+ neigh_node_free_ref(neigh_node);
+ if (primary_if)
+ hardif_free_ref(primary_if);
+ if (!ret)
+ kfree_skb(skb);
+ return ret;
+
+}
+static bool send_my_tt_response(struct bat_priv *bat_priv,
+ struct tt_query_packet *tt_request)
+{
+ struct orig_node *orig_node = NULL;
+ struct neigh_node *neigh_node = NULL;
+ struct hard_iface *primary_if = NULL;
+ uint8_t my_ttvn, req_ttvn, ttvn;
+ int ret = false;
+ unsigned char *tt_buff;
+ bool full_table;
+ uint16_t tt_len, tt_tot;
+ struct sk_buff *skb = NULL;
+ struct tt_query_packet *tt_response;
+
+ bat_dbg(DBG_TT, bat_priv,
+ "Received TT_REQUEST from %pM for "
+ "ttvn: %u (me) [%c]\n", tt_request->src,
+ tt_request->ttvn,
+ (tt_request->flags & TT_FULL_TABLE ? 'F' : '.'));
+
+
+ my_ttvn = (uint8_t)atomic_read(&bat_priv->ttvn);
+ req_ttvn = tt_request->ttvn;
+
+ orig_node = get_orig_node(bat_priv, tt_request->src);
+ if (!orig_node)
+ goto out;
+
+ neigh_node = orig_node_get_router(orig_node);
+ if (!neigh_node)
+ goto out;
+
+ primary_if = primary_if_get_selected(bat_priv);
+ if (!primary_if)
+ goto out;
+
+ /* If the full table has been explicitly requested or the gap
+ * is too big send the whole local translation table */
+ if (tt_request->flags & TT_FULL_TABLE || my_ttvn != req_ttvn ||
+ !bat_priv->tt_buff)
+ full_table = true;
+ else
+ full_table = false;
+
+ /* In this version, fragmentation is not implemented, then
+ * I'll send only one packet with as much TT entries as I can */
+ if (!full_table) {
+ spin_lock_bh(&bat_priv->tt_buff_lock);
+ tt_len = bat_priv->tt_buff_len;
+ tt_tot = tt_len / sizeof(struct tt_change);
+
+ skb = dev_alloc_skb(sizeof(struct tt_query_packet) +
+ tt_len + ETH_HLEN);
+ if (!skb)
+ goto unlock;
+
+ skb_reserve(skb, ETH_HLEN);
+ tt_response = (struct tt_query_packet *)skb_put(skb,
+ sizeof(struct tt_query_packet) + tt_len);
+ tt_response->ttvn = req_ttvn;
+ tt_response->tt_data = htons(tt_tot);
+
+ tt_buff = skb->data + sizeof(struct tt_query_packet);
+ memcpy(tt_buff, bat_priv->tt_buff,
+ bat_priv->tt_buff_len);
+ spin_unlock_bh(&bat_priv->tt_buff_lock);
+ } else {
+ tt_len = (uint16_t)atomic_read(&bat_priv->num_local_tt) *
+ sizeof(struct tt_change);
+ ttvn = (uint8_t)atomic_read(&bat_priv->ttvn);
+
+ skb = tt_response_fill_table(tt_len, ttvn,
+ bat_priv->tt_local_hash,
+ primary_if, tt_local_valid_entry,
+ NULL);
+ if (!skb)
+ goto out;
+
+ tt_response = (struct tt_query_packet *)skb->data;
+ }
+
+ tt_response->packet_type = BAT_TT_QUERY;
+ tt_response->version = COMPAT_VERSION;
+ tt_response->ttl = TTL;
+ memcpy(tt_response->src, primary_if->net_dev->dev_addr, ETH_ALEN);
+ memcpy(tt_response->dst, tt_request->src, ETH_ALEN);
+ tt_response->flags = TT_RESPONSE;
+
+ if (full_table)
+ tt_response->flags |= TT_FULL_TABLE;
+
+ bat_dbg(DBG_TT, bat_priv,
+ "Sending TT_RESPONSE to %pM via %pM [%c]\n",
+ orig_node->orig, neigh_node->addr,
+ (tt_response->flags & TT_FULL_TABLE ? 'F' : '.'));
+
+ send_skb_packet(skb, neigh_node->if_incoming, neigh_node->addr);
+ ret = true;
+ goto out;
+
+unlock:
+ spin_unlock_bh(&bat_priv->tt_buff_lock);
+out:
+ if (orig_node)
+ orig_node_free_ref(orig_node);
+ if (neigh_node)
+ neigh_node_free_ref(neigh_node);
+ if (primary_if)
+ hardif_free_ref(primary_if);
+ if (!ret)
+ kfree_skb(skb);
+ /* This packet was for me, so it doesn't need to be re-routed */
+ return true;
+}
+
+bool send_tt_response(struct bat_priv *bat_priv,
+ struct tt_query_packet *tt_request)
+{
+ if (is_my_mac(tt_request->dst))
+ return send_my_tt_response(bat_priv, tt_request);
+ else
+ return send_other_tt_response(bat_priv, tt_request);
+}
+
+static void _tt_update_changes(struct bat_priv *bat_priv,
+ struct orig_node *orig_node,
+ struct tt_change *tt_change,
+ uint16_t tt_num_changes, uint8_t ttvn)
+{
+ int i;
+
+ for (i = 0; i < tt_num_changes; i++) {
+ if ((tt_change + i)->flags & TT_CLIENT_DEL)
+ tt_global_del(bat_priv, orig_node,
+ (tt_change + i)->addr,
+ "tt removed by changes",
+ (tt_change + i)->flags & TT_CLIENT_ROAM);
+ else
+ if (!tt_global_add(bat_priv, orig_node,
+ (tt_change + i)->addr, ttvn, false,
+ (tt_change + i)->flags &
+ TT_CLIENT_WIFI))
+ /* In case of problem while storing a
+ * global_entry, we stop the updating
+ * procedure without committing the
+ * ttvn change. This will avoid to send
+ * corrupted data on tt_request
+ */
+ return;
+ }
+}
+
+static void tt_fill_gtable(struct bat_priv *bat_priv,
+ struct tt_query_packet *tt_response)
+{
+ struct orig_node *orig_node = NULL;
+
+ orig_node = orig_hash_find(bat_priv, tt_response->src);
+ if (!orig_node)
+ goto out;
+
+ /* Purge the old table first.. */
+ tt_global_del_orig(bat_priv, orig_node, "Received full table");
+
+ _tt_update_changes(bat_priv, orig_node,
+ (struct tt_change *)(tt_response + 1),
+ tt_response->tt_data, tt_response->ttvn);
+
+ spin_lock_bh(&orig_node->tt_buff_lock);
+ kfree(orig_node->tt_buff);
+ orig_node->tt_buff_len = 0;
+ orig_node->tt_buff = NULL;
+ spin_unlock_bh(&orig_node->tt_buff_lock);
+
+ atomic_set(&orig_node->last_ttvn, tt_response->ttvn);
+
+out:
+ if (orig_node)
+ orig_node_free_ref(orig_node);
+}
+
+static void tt_update_changes(struct bat_priv *bat_priv,
+ struct orig_node *orig_node,
+ uint16_t tt_num_changes, uint8_t ttvn,
+ struct tt_change *tt_change)
+{
+ _tt_update_changes(bat_priv, orig_node, tt_change, tt_num_changes,
+ ttvn);
+
+ tt_save_orig_buffer(bat_priv, orig_node, (unsigned char *)tt_change,
+ tt_num_changes);
+ atomic_set(&orig_node->last_ttvn, ttvn);
+}
+
+bool is_my_client(struct bat_priv *bat_priv, const uint8_t *addr)
+{
+ struct tt_local_entry *tt_local_entry = NULL;
+ bool ret = false;
+
+ tt_local_entry = tt_local_hash_find(bat_priv, addr);
+ if (!tt_local_entry)
+ goto out;
+ /* Check if the client has been logically deleted (but is kept for
+ * consistency purpose) */
+ if (tt_local_entry->flags & TT_CLIENT_PENDING)
+ goto out;
+ ret = true;
+out:
+ if (tt_local_entry)
+ tt_local_entry_free_ref(tt_local_entry);
+ return ret;
+}
+
+void handle_tt_response(struct bat_priv *bat_priv,
+ struct tt_query_packet *tt_response)
+{
+ struct tt_req_node *node, *safe;
+ struct orig_node *orig_node = NULL;
+
+ bat_dbg(DBG_TT, bat_priv, "Received TT_RESPONSE from %pM for "
+ "ttvn %d t_size: %d [%c]\n",
+ tt_response->src, tt_response->ttvn,
+ tt_response->tt_data,
+ (tt_response->flags & TT_FULL_TABLE ? 'F' : '.'));
+
+ orig_node = orig_hash_find(bat_priv, tt_response->src);
+ if (!orig_node)
+ goto out;
+
+ if (tt_response->flags & TT_FULL_TABLE)
+ tt_fill_gtable(bat_priv, tt_response);
+ else
+ tt_update_changes(bat_priv, orig_node, tt_response->tt_data,
+ tt_response->ttvn,
+ (struct tt_change *)(tt_response + 1));
+
+ /* Delete the tt_req_node from pending tt_requests list */
+ spin_lock_bh(&bat_priv->tt_req_list_lock);
+ list_for_each_entry_safe(node, safe, &bat_priv->tt_req_list, list) {
+ if (!compare_eth(node->addr, tt_response->src))
+ continue;
+ list_del(&node->list);
+ kfree(node);
+ }
+ spin_unlock_bh(&bat_priv->tt_req_list_lock);
+
+ /* Recalculate the CRC for this orig_node and store it */
+ orig_node->tt_crc = tt_global_crc(bat_priv, orig_node);
+ /* Roaming phase is over: tables are in sync again. I can
+ * unset the flag */
+ orig_node->tt_poss_change = false;
+out:
+ if (orig_node)
+ orig_node_free_ref(orig_node);
+}
+
+int tt_init(struct bat_priv *bat_priv)
+{
+ if (!tt_local_init(bat_priv))
+ return 0;
+
+ if (!tt_global_init(bat_priv))
+ return 0;
+
+ tt_start_timer(bat_priv);
+
+ return 1;
+}
+
+static void tt_roam_list_free(struct bat_priv *bat_priv)
+{
+ struct tt_roam_node *node, *safe;
+
+ spin_lock_bh(&bat_priv->tt_roam_list_lock);
+
+ list_for_each_entry_safe(node, safe, &bat_priv->tt_roam_list, list) {
+ list_del(&node->list);
+ kfree(node);
+ }
+
+ spin_unlock_bh(&bat_priv->tt_roam_list_lock);
+}
+
+static void tt_roam_purge(struct bat_priv *bat_priv)
+{
+ struct tt_roam_node *node, *safe;
+
+ spin_lock_bh(&bat_priv->tt_roam_list_lock);
+ list_for_each_entry_safe(node, safe, &bat_priv->tt_roam_list, list) {
+ if (!is_out_of_time(node->first_time,
+ ROAMING_MAX_TIME * 1000))
+ continue;
+
+ list_del(&node->list);
+ kfree(node);
+ }
+ spin_unlock_bh(&bat_priv->tt_roam_list_lock);
+}
+
+/* This function checks whether the client already reached the
+ * maximum number of possible roaming phases. In this case the ROAMING_ADV
+ * will not be sent.
+ *
+ * returns true if the ROAMING_ADV can be sent, false otherwise */
+static bool tt_check_roam_count(struct bat_priv *bat_priv,
+ uint8_t *client)
+{
+ struct tt_roam_node *tt_roam_node;
+ bool ret = false;
+
+ spin_lock_bh(&bat_priv->tt_roam_list_lock);
+ /* The new tt_req will be issued only if I'm not waiting for a
+ * reply from the same orig_node yet */
+ list_for_each_entry(tt_roam_node, &bat_priv->tt_roam_list, list) {
+ if (!compare_eth(tt_roam_node->addr, client))
+ continue;
+
+ if (is_out_of_time(tt_roam_node->first_time,
+ ROAMING_MAX_TIME * 1000))
+ continue;
+
+ if (!atomic_dec_not_zero(&tt_roam_node->counter))
+ /* Sorry, you roamed too many times! */
+ goto unlock;
+ ret = true;
+ break;
+ }
+
+ if (!ret) {
+ tt_roam_node = kmalloc(sizeof(*tt_roam_node), GFP_ATOMIC);
+ if (!tt_roam_node)
+ goto unlock;
+
+ tt_roam_node->first_time = jiffies;
+ atomic_set(&tt_roam_node->counter, ROAMING_MAX_COUNT - 1);
+ memcpy(tt_roam_node->addr, client, ETH_ALEN);
+
+ list_add(&tt_roam_node->list, &bat_priv->tt_roam_list);
+ ret = true;
+ }
+
+unlock:
+ spin_unlock_bh(&bat_priv->tt_roam_list_lock);
+ return ret;
+}
+
+void send_roam_adv(struct bat_priv *bat_priv, uint8_t *client,
+ struct orig_node *orig_node)
+{
+ struct neigh_node *neigh_node = NULL;
+ struct sk_buff *skb = NULL;
+ struct roam_adv_packet *roam_adv_packet;
+ int ret = 1;
+ struct hard_iface *primary_if;
+
+ /* before going on we have to check whether the client has
+ * already roamed to us too many times */
+ if (!tt_check_roam_count(bat_priv, client))
+ goto out;
+
+ skb = dev_alloc_skb(sizeof(struct roam_adv_packet) + ETH_HLEN);
+ if (!skb)
+ goto out;
+
+ skb_reserve(skb, ETH_HLEN);
+
+ roam_adv_packet = (struct roam_adv_packet *)skb_put(skb,
+ sizeof(struct roam_adv_packet));
+
+ roam_adv_packet->packet_type = BAT_ROAM_ADV;
+ roam_adv_packet->version = COMPAT_VERSION;
+ roam_adv_packet->ttl = TTL;
+ primary_if = primary_if_get_selected(bat_priv);
+ if (!primary_if)
+ goto out;
+ memcpy(roam_adv_packet->src, primary_if->net_dev->dev_addr, ETH_ALEN);
+ hardif_free_ref(primary_if);
+ memcpy(roam_adv_packet->dst, orig_node->orig, ETH_ALEN);
+ memcpy(roam_adv_packet->client, client, ETH_ALEN);
+
+ neigh_node = orig_node_get_router(orig_node);
+ if (!neigh_node)
+ goto out;
+
+ bat_dbg(DBG_TT, bat_priv,
+ "Sending ROAMING_ADV to %pM (client %pM) via %pM\n",
+ orig_node->orig, client, neigh_node->addr);
+
+ send_skb_packet(skb, neigh_node->if_incoming, neigh_node->addr);
+ ret = 0;
+
+out:
+ if (neigh_node)
+ neigh_node_free_ref(neigh_node);
+ if (ret)
+ kfree_skb(skb);
+ return;
+}
+
+static void tt_purge(struct work_struct *work)
+{
+ struct delayed_work *delayed_work =
+ container_of(work, struct delayed_work, work);
+ struct bat_priv *bat_priv =
+ container_of(delayed_work, struct bat_priv, tt_work);
+
+ tt_local_purge(bat_priv);
+ tt_global_roam_purge(bat_priv);
+ tt_req_purge(bat_priv);
+ tt_roam_purge(bat_priv);
+
+ tt_start_timer(bat_priv);
+}
+
+void tt_free(struct bat_priv *bat_priv)
+{
+ cancel_delayed_work_sync(&bat_priv->tt_work);
+
+ tt_local_table_free(bat_priv);
+ tt_global_table_free(bat_priv);
+ tt_req_list_free(bat_priv);
+ tt_changes_list_free(bat_priv);
+ tt_roam_list_free(bat_priv);
+
+ kfree(bat_priv->tt_buff);
+}
+
+/* This function will reset the specified flags from all the entries in
+ * the given hash table and will increment num_local_tt for each involved
+ * entry */
+static void tt_local_reset_flags(struct bat_priv *bat_priv, uint16_t flags)
+{
+ int i;
+ struct hashtable_t *hash = bat_priv->tt_local_hash;
+ struct hlist_head *head;
+ struct hlist_node *node;
+ struct tt_local_entry *tt_local_entry;
+
+ if (!hash)
+ return;
+
+ for (i = 0; i < hash->size; i++) {
+ head = &hash->table[i];
+
+ rcu_read_lock();
+ hlist_for_each_entry_rcu(tt_local_entry, node,
+ head, hash_entry) {
+ if (!(tt_local_entry->flags & flags))
+ continue;
+ tt_local_entry->flags &= ~flags;
+ atomic_inc(&bat_priv->num_local_tt);
+ }
+ rcu_read_unlock();
+ }
+
+}
+
+/* Purge out all the tt local entries marked with TT_CLIENT_PENDING */
+static void tt_local_purge_pending_clients(struct bat_priv *bat_priv)
+{
+ struct hashtable_t *hash = bat_priv->tt_local_hash;
+ struct tt_local_entry *tt_local_entry;
+ struct hlist_node *node, *node_tmp;
+ struct hlist_head *head;
+ spinlock_t *list_lock; /* protects write access to the hash lists */
+ int i;
+
+ if (!hash)
+ return;
+
+ for (i = 0; i < hash->size; i++) {
+ head = &hash->table[i];
+ list_lock = &hash->list_locks[i];
+
+ spin_lock_bh(list_lock);
+ hlist_for_each_entry_safe(tt_local_entry, node, node_tmp,
+ head, hash_entry) {
+ if (!(tt_local_entry->flags & TT_CLIENT_PENDING))
+ continue;
+
+ bat_dbg(DBG_TT, bat_priv, "Deleting local tt entry "
+ "(%pM): pending\n", tt_local_entry->addr);
+
+ atomic_dec(&bat_priv->num_local_tt);
+ hlist_del_rcu(node);
+ tt_local_entry_free_ref(tt_local_entry);
+ }
+ spin_unlock_bh(list_lock);
+ }
+
+}
+
+void tt_commit_changes(struct bat_priv *bat_priv)
+{
+ tt_local_reset_flags(bat_priv, TT_CLIENT_NEW);
+ tt_local_purge_pending_clients(bat_priv);
+
+ /* Increment the TTVN only once per OGM interval */
+ atomic_inc(&bat_priv->ttvn);
+ bat_priv->tt_poss_change = false;
+}
+
+bool is_ap_isolated(struct bat_priv *bat_priv, uint8_t *src, uint8_t *dst)
+{
+ struct tt_local_entry *tt_local_entry = NULL;
+ struct tt_global_entry *tt_global_entry = NULL;
+ bool ret = false;
+
+ if (!atomic_read(&bat_priv->ap_isolation))
+ goto out;
+
+ tt_local_entry = tt_local_hash_find(bat_priv, dst);
+ if (!tt_local_entry)
+ goto out;
+
+ tt_global_entry = tt_global_hash_find(bat_priv, src);
+ if (!tt_global_entry)
+ goto out;
+
+ if (!_is_ap_isolated(tt_local_entry, tt_global_entry))
+ goto out;
+
+ ret = true;
+
+out:
+ if (tt_global_entry)
+ tt_global_entry_free_ref(tt_global_entry);
+ if (tt_local_entry)
+ tt_local_entry_free_ref(tt_local_entry);
+ return ret;
+}
+
+void tt_update_orig(struct bat_priv *bat_priv, struct orig_node *orig_node,
+ const unsigned char *tt_buff, uint8_t tt_num_changes,
+ uint8_t ttvn, uint16_t tt_crc)
+{
+ uint8_t orig_ttvn = (uint8_t)atomic_read(&orig_node->last_ttvn);
+ bool full_table = true;
+
+ /* the ttvn increased by one -> we can apply the attached changes */
+ if (ttvn - orig_ttvn == 1) {
+ /* the OGM could not contain the changes due to their size or
+ * because they have already been sent TT_OGM_APPEND_MAX times.
+ * In this case send a tt request */
+ if (!tt_num_changes) {
+ full_table = false;
+ goto request_table;
+ }
+
+ tt_update_changes(bat_priv, orig_node, tt_num_changes, ttvn,
+ (struct tt_change *)tt_buff);
+
+ /* Even if we received the precomputed crc with the OGM, we
+ * prefer to recompute it to spot any possible inconsistency
+ * in the global table */
+ orig_node->tt_crc = tt_global_crc(bat_priv, orig_node);
+
+ /* The ttvn alone is not enough to guarantee consistency
+ * because a single value could represent different states
+ * (due to the wrap around). Thus a node has to check whether
+ * the resulting table (after applying the changes) is still
+ * consistent or not. E.g. a node could disconnect while its
+ * ttvn is X and reconnect on ttvn = X + TTVN_MAX: in this case
+ * checking the CRC value is mandatory to detect the
+ * inconsistency */
+ if (orig_node->tt_crc != tt_crc)
+ goto request_table;
+
+ /* Roaming phase is over: tables are in sync again. I can
+ * unset the flag */
+ orig_node->tt_poss_change = false;
+ } else {
+ /* if we missed more than one change or our tables are not
+ * in sync anymore -> request fresh tt data */
+ if (ttvn != orig_ttvn || orig_node->tt_crc != tt_crc) {
+request_table:
+ bat_dbg(DBG_TT, bat_priv, "TT inconsistency for %pM. "
+ "Need to retrieve the correct information "
+ "(ttvn: %u last_ttvn: %u crc: %u last_crc: "
+ "%u num_changes: %u)\n", orig_node->orig, ttvn,
+ orig_ttvn, tt_crc, orig_node->tt_crc,
+ tt_num_changes);
+ send_tt_request(bat_priv, orig_node, ttvn, tt_crc,
+ full_table);
+ return;
+ }
+ }
+}
diff --git a/net/batman-adv/translation-table.h b/net/batman-adv/translation-table.h
index 46152c3..30efd49 100644
--- a/net/batman-adv/translation-table.h
+++ b/net/batman-adv/translation-table.h
@@ -22,22 +22,44 @@
#ifndef _NET_BATMAN_ADV_TRANSLATION_TABLE_H_
#define _NET_BATMAN_ADV_TRANSLATION_TABLE_H_
-int tt_local_init(struct bat_priv *bat_priv);
-void tt_local_add(struct net_device *soft_iface, uint8_t *addr);
+int tt_len(int changes_num);
+int tt_changes_fill_buffer(struct bat_priv *bat_priv,
+ unsigned char *buff, int buff_len);
+int tt_init(struct bat_priv *bat_priv);
+void tt_local_add(struct net_device *soft_iface, const uint8_t *addr,
+ int ifindex);
void tt_local_remove(struct bat_priv *bat_priv,
- uint8_t *addr, char *message);
-int tt_local_fill_buffer(struct bat_priv *bat_priv,
- unsigned char *buff, int buff_len);
+ const uint8_t *addr, const char *message, bool roaming);
int tt_local_seq_print_text(struct seq_file *seq, void *offset);
-void tt_local_free(struct bat_priv *bat_priv);
-int tt_global_init(struct bat_priv *bat_priv);
-void tt_global_add_orig(struct bat_priv *bat_priv,
- struct orig_node *orig_node,
- unsigned char *tt_buff, int tt_buff_len);
+void tt_global_add_orig(struct bat_priv *bat_priv, struct orig_node *orig_node,
+ const unsigned char *tt_buff, int tt_buff_len);
+int tt_global_add(struct bat_priv *bat_priv, struct orig_node *orig_node,
+ const unsigned char *addr, uint8_t ttvn, bool roaming,
+ bool wifi);
int tt_global_seq_print_text(struct seq_file *seq, void *offset);
void tt_global_del_orig(struct bat_priv *bat_priv,
- struct orig_node *orig_node, char *message);
-void tt_global_free(struct bat_priv *bat_priv);
-struct orig_node *transtable_search(struct bat_priv *bat_priv, uint8_t *addr);
+ struct orig_node *orig_node, const char *message);
+void tt_global_del(struct bat_priv *bat_priv,
+ struct orig_node *orig_node, const unsigned char *addr,
+ const char *message, bool roaming);
+struct orig_node *transtable_search(struct bat_priv *bat_priv,
+ const uint8_t *src, const uint8_t *addr);
+void tt_save_orig_buffer(struct bat_priv *bat_priv, struct orig_node *orig_node,
+ const unsigned char *tt_buff, uint8_t tt_num_changes);
+uint16_t tt_local_crc(struct bat_priv *bat_priv);
+uint16_t tt_global_crc(struct bat_priv *bat_priv, struct orig_node *orig_node);
+void tt_free(struct bat_priv *bat_priv);
+bool send_tt_response(struct bat_priv *bat_priv,
+ struct tt_query_packet *tt_request);
+bool is_my_client(struct bat_priv *bat_priv, const uint8_t *addr);
+void handle_tt_response(struct bat_priv *bat_priv,
+ struct tt_query_packet *tt_response);
+void send_roam_adv(struct bat_priv *bat_priv, uint8_t *client,
+ struct orig_node *orig_node);
+void tt_commit_changes(struct bat_priv *bat_priv);
+bool is_ap_isolated(struct bat_priv *bat_priv, uint8_t *src, uint8_t *dst);
+void tt_update_orig(struct bat_priv *bat_priv, struct orig_node *orig_node,
+ const unsigned char *tt_buff, uint8_t tt_num_changes,
+ uint8_t ttvn, uint16_t tt_crc);
#endif /* _NET_BATMAN_ADV_TRANSLATION_TABLE_H_ */
diff --git a/net/batman-adv/types.h b/net/batman-adv/types.h
index fab70e8..ab8d0fe 100644
--- a/net/batman-adv/types.h
+++ b/net/batman-adv/types.h
@@ -57,7 +57,7 @@ struct hard_iface {
* @batman_seqno_reset: time when the batman seqno window was reset
* @gw_flags: flags related to gateway class
* @flags: for now only VIS_SERVER flag
- * @last_real_seqno: last and best known squence number
+ * @last_real_seqno: last and best known sequence number
* @last_ttl: ttl of last received packet
* @last_bcast_seqno: last broadcast sequence number received by this host
*
@@ -75,8 +75,18 @@ struct orig_node {
unsigned long batman_seqno_reset;
uint8_t gw_flags;
uint8_t flags;
+ atomic_t last_ttvn; /* last seen translation table version number */
+ uint16_t tt_crc;
unsigned char *tt_buff;
int16_t tt_buff_len;
+ spinlock_t tt_buff_lock; /* protects tt_buff */
+ atomic_t tt_size;
+ /* The tt_poss_change flag is used to detect an ongoing roaming phase.
+ * If true, then I sent a Roaming_adv to this orig_node and I have to
+ * inspect every packet directed to it to check whether it is still
+ * the true destination or not. This flag will be reset to false as
+ * soon as I receive a new TTVN from this orig_node */
+ bool tt_poss_change;
uint32_t last_real_seqno;
uint8_t last_ttl;
unsigned long bcast_bits[NUM_WORDS];
@@ -94,6 +104,7 @@ struct orig_node {
spinlock_t ogm_cnt_lock;
/* bcast_seqno_lock protects bcast_bits, last_bcast_seqno */
spinlock_t bcast_seqno_lock;
+ spinlock_t tt_list_lock; /* protects tt_list */
atomic_t bond_candidates;
struct list_head bond_list;
};
@@ -135,6 +146,7 @@ struct bat_priv {
atomic_t aggregated_ogms; /* boolean */
atomic_t bonding; /* boolean */
atomic_t fragmentation; /* boolean */
+ atomic_t ap_isolation; /* boolean */
atomic_t vis_mode; /* VIS_TYPE_* */
atomic_t gw_mode; /* GW_MODE_* */
atomic_t gw_sel_class; /* uint */
@@ -145,6 +157,15 @@ struct bat_priv {
atomic_t bcast_seqno;
atomic_t bcast_queue_left;
atomic_t batman_queue_left;
+ atomic_t ttvn; /* translation table version number */
+ atomic_t tt_ogm_append_cnt;
+ atomic_t tt_local_changes; /* changes registered in a OGM interval */
+ /* The tt_poss_change flag is used to detect an ongoing roaming phase.
+ * If true, then I received a Roaming_adv and I have to inspect every
+ * packet directed to me to check whether I am still the true
+ * destination or not. This flag will be reset to false as soon as I
+ * increase my TTVN */
+ bool tt_poss_change;
char num_ifaces;
struct debug_log *debug_log;
struct kobject *mesh_obj;
@@ -153,26 +174,35 @@ struct bat_priv {
struct hlist_head forw_bcast_list;
struct hlist_head gw_list;
struct hlist_head softif_neigh_vids;
+ struct list_head tt_changes_list; /* tracks changes in a OGM int */
struct list_head vis_send_list;
struct hashtable_t *orig_hash;
struct hashtable_t *tt_local_hash;
struct hashtable_t *tt_global_hash;
+ struct list_head tt_req_list; /* list of pending tt_requests */
+ struct list_head tt_roam_list;
struct hashtable_t *vis_hash;
spinlock_t forw_bat_list_lock; /* protects forw_bat_list */
spinlock_t forw_bcast_list_lock; /* protects */
- spinlock_t tt_lhash_lock; /* protects tt_local_hash */
- spinlock_t tt_ghash_lock; /* protects tt_global_hash */
+ spinlock_t tt_changes_list_lock; /* protects tt_changes */
+ spinlock_t tt_req_list_lock; /* protects tt_req_list */
+ spinlock_t tt_roam_list_lock; /* protects tt_roam_list */
spinlock_t gw_list_lock; /* protects gw_list and curr_gw */
spinlock_t vis_hash_lock; /* protects vis_hash */
spinlock_t vis_list_lock; /* protects vis_info::recv_list */
spinlock_t softif_neigh_lock; /* protects soft-interface neigh list */
spinlock_t softif_neigh_vid_lock; /* protects soft-interface vid list */
- int16_t num_local_tt;
- atomic_t tt_local_changed;
+ atomic_t num_local_tt;
+ /* Checksum of the local table, recomputed before sending a new OGM */
+ atomic_t tt_crc;
+ unsigned char *tt_buff;
+ int16_t tt_buff_len;
+ spinlock_t tt_buff_lock; /* protects tt_buff */
struct delayed_work tt_work;
struct delayed_work orig_work;
struct delayed_work vis_work;
struct gw_node __rcu *curr_gw; /* rcu protected pointer */
+ atomic_t gw_reselect;
struct hard_iface __rcu *primary_if; /* rcu protected pointer */
struct vis_info *my_vis_info;
};
@@ -194,15 +224,40 @@ struct socket_packet {
struct tt_local_entry {
uint8_t addr[ETH_ALEN];
- unsigned long last_seen;
- char never_purge;
struct hlist_node hash_entry;
+ unsigned long last_seen;
+ uint16_t flags;
+ atomic_t refcount;
+ struct rcu_head rcu;
};
struct tt_global_entry {
uint8_t addr[ETH_ALEN];
+ struct hlist_node hash_entry; /* entry in the global table */
struct orig_node *orig_node;
- struct hlist_node hash_entry;
+ uint8_t ttvn;
+ uint16_t flags; /* only TT_GLOBAL_ROAM is used */
+ unsigned long roam_at; /* time at which TT_GLOBAL_ROAM was set */
+ atomic_t refcount;
+ struct rcu_head rcu;
+};
+
+struct tt_change_node {
+ struct list_head list;
+ struct tt_change change;
+};
+
+struct tt_req_node {
+ uint8_t addr[ETH_ALEN];
+ unsigned long issued_at;
+ struct list_head list;
+};
+
+struct tt_roam_node {
+ uint8_t addr[ETH_ALEN];
+ atomic_t counter;
+ unsigned long first_time;
+ struct list_head list;
};
/**
@@ -246,10 +301,10 @@ struct frag_packet_list_entry {
};
struct vis_info {
- unsigned long first_seen;
- struct list_head recv_list;
- /* list of server-neighbors we received a vis-packet
- * from. we should not reply to them. */
+ unsigned long first_seen;
+ /* list of server-neighbors we received a vis-packet
+ * from. we should not reply to them. */
+ struct list_head recv_list;
struct list_head send_list;
struct kref refcount;
struct hlist_node hash_entry;
diff --git a/net/batman-adv/unicast.c b/net/batman-adv/unicast.c
index 19c3daf..07d1c1d 100644
--- a/net/batman-adv/unicast.c
+++ b/net/batman-adv/unicast.c
@@ -39,8 +39,8 @@ static struct sk_buff *frag_merge_packet(struct list_head *head,
(struct unicast_frag_packet *)skb->data;
struct sk_buff *tmp_skb;
struct unicast_packet *unicast_packet;
- int hdr_len = sizeof(struct unicast_packet);
- int uni_diff = sizeof(struct unicast_frag_packet) - hdr_len;
+ int hdr_len = sizeof(*unicast_packet);
+ int uni_diff = sizeof(*up) - hdr_len;
/* set skb to the first part and tmp_skb to the second part */
if (up->flags & UNI_FRAG_HEAD) {
@@ -53,7 +53,7 @@ static struct sk_buff *frag_merge_packet(struct list_head *head,
if (skb_linearize(skb) < 0 || skb_linearize(tmp_skb) < 0)
goto err;
- skb_pull(tmp_skb, sizeof(struct unicast_frag_packet));
+ skb_pull(tmp_skb, sizeof(*up));
if (pskb_expand_head(skb, 0, tmp_skb->len, GFP_ATOMIC) < 0)
goto err;
@@ -99,8 +99,7 @@ static int frag_create_buffer(struct list_head *head)
struct frag_packet_list_entry *tfp;
for (i = 0; i < FRAG_BUFFER_SIZE; i++) {
- tfp = kmalloc(sizeof(struct frag_packet_list_entry),
- GFP_ATOMIC);
+ tfp = kmalloc(sizeof(*tfp), GFP_ATOMIC);
if (!tfp) {
frag_list_free(head);
return -ENOMEM;
@@ -115,7 +114,7 @@ static int frag_create_buffer(struct list_head *head)
}
static struct frag_packet_list_entry *frag_search_packet(struct list_head *head,
- struct unicast_frag_packet *up)
+ const struct unicast_frag_packet *up)
{
struct frag_packet_list_entry *tfp;
struct unicast_frag_packet *tmp_up = NULL;
@@ -218,14 +217,14 @@ out:
}
int frag_send_skb(struct sk_buff *skb, struct bat_priv *bat_priv,
- struct hard_iface *hard_iface, uint8_t dstaddr[])
+ struct hard_iface *hard_iface, const uint8_t dstaddr[])
{
struct unicast_packet tmp_uc, *unicast_packet;
struct hard_iface *primary_if;
struct sk_buff *frag_skb;
struct unicast_frag_packet *frag1, *frag2;
- int uc_hdr_len = sizeof(struct unicast_packet);
- int ucf_hdr_len = sizeof(struct unicast_frag_packet);
+ int uc_hdr_len = sizeof(*unicast_packet);
+ int ucf_hdr_len = sizeof(*frag1);
int data_len = skb->len - uc_hdr_len;
int large_tail = 0, ret = NET_RX_DROP;
uint16_t seqno;
@@ -250,14 +249,14 @@ int frag_send_skb(struct sk_buff *skb, struct bat_priv *bat_priv,
frag1 = (struct unicast_frag_packet *)skb->data;
frag2 = (struct unicast_frag_packet *)frag_skb->data;
- memcpy(frag1, &tmp_uc, sizeof(struct unicast_packet));
+ memcpy(frag1, &tmp_uc, sizeof(tmp_uc));
frag1->ttl--;
frag1->version = COMPAT_VERSION;
frag1->packet_type = BAT_UNICAST_FRAG;
memcpy(frag1->orig, primary_if->net_dev->dev_addr, ETH_ALEN);
- memcpy(frag2, frag1, sizeof(struct unicast_frag_packet));
+ memcpy(frag2, frag1, sizeof(*frag2));
if (data_len & 1)
large_tail = UNI_FRAG_LARGETAIL;
@@ -295,13 +294,15 @@ int unicast_send_skb(struct sk_buff *skb, struct bat_priv *bat_priv)
/* get routing information */
if (is_multicast_ether_addr(ethhdr->h_dest)) {
- orig_node = (struct orig_node *)gw_get_selected_orig(bat_priv);
+ orig_node = gw_get_selected_orig(bat_priv);
if (orig_node)
goto find_router;
}
- /* check for tt host - increases orig_node refcount */
- orig_node = transtable_search(bat_priv, ethhdr->h_dest);
+ /* check for tt host - increases orig_node refcount.
+ * returns NULL in case of AP isolation */
+ orig_node = transtable_search(bat_priv, ethhdr->h_source,
+ ethhdr->h_dest);
find_router:
/**
@@ -314,10 +315,7 @@ find_router:
if (!neigh_node)
goto out;
- if (neigh_node->if_incoming->if_status != IF_ACTIVE)
- goto out;
-
- if (my_skb_head_push(skb, sizeof(struct unicast_packet)) < 0)
+ if (my_skb_head_push(skb, sizeof(*unicast_packet)) < 0)
goto out;
unicast_packet = (struct unicast_packet *)skb->data;
@@ -329,9 +327,12 @@ find_router:
unicast_packet->ttl = TTL;
/* copy the destination for faster routing */
memcpy(unicast_packet->dest, orig_node->orig, ETH_ALEN);
+ /* set the destination tt version number */
+ unicast_packet->ttvn =
+ (uint8_t)atomic_read(&orig_node->last_ttvn);
if (atomic_read(&bat_priv->fragmentation) &&
- data_len + sizeof(struct unicast_packet) >
+ data_len + sizeof(*unicast_packet) >
neigh_node->if_incoming->net_dev->mtu) {
/* send frag skb decreases ttl */
unicast_packet->ttl++;
diff --git a/net/batman-adv/unicast.h b/net/batman-adv/unicast.h
index 16ad7a9..8fd5535 100644
--- a/net/batman-adv/unicast.h
+++ b/net/batman-adv/unicast.h
@@ -24,7 +24,7 @@
#include "packet.h"
-#define FRAG_TIMEOUT 10000 /* purge frag list entrys after time in ms */
+#define FRAG_TIMEOUT 10000 /* purge frag list entries after time in ms */
#define FRAG_BUFFER_SIZE 6 /* number of list elements in buffer */
int frag_reassemble_skb(struct sk_buff *skb, struct bat_priv *bat_priv,
@@ -32,11 +32,11 @@ int frag_reassemble_skb(struct sk_buff *skb, struct bat_priv *bat_priv,
void frag_list_free(struct list_head *head);
int unicast_send_skb(struct sk_buff *skb, struct bat_priv *bat_priv);
int frag_send_skb(struct sk_buff *skb, struct bat_priv *bat_priv,
- struct hard_iface *hard_iface, uint8_t dstaddr[]);
+ struct hard_iface *hard_iface, const uint8_t dstaddr[]);
-static inline int frag_can_reassemble(struct sk_buff *skb, int mtu)
+static inline int frag_can_reassemble(const struct sk_buff *skb, int mtu)
{
- struct unicast_frag_packet *unicast_packet;
+ const struct unicast_frag_packet *unicast_packet;
int uneven_correction = 0;
unsigned int merged_size;
@@ -49,7 +49,7 @@ static inline int frag_can_reassemble(struct sk_buff *skb, int mtu)
uneven_correction = -1;
}
- merged_size = (skb->len - sizeof(struct unicast_frag_packet)) * 2;
+ merged_size = (skb->len - sizeof(*unicast_packet)) * 2;
merged_size += sizeof(struct unicast_packet) + uneven_correction;
return merged_size <= mtu;
diff --git a/net/batman-adv/vis.c b/net/batman-adv/vis.c
index c39f20c..f81a6b6 100644
--- a/net/batman-adv/vis.c
+++ b/net/batman-adv/vis.c
@@ -30,22 +30,6 @@
#define MAX_VIS_PACKET_SIZE 1000
-/* Returns the smallest signed integer in two's complement with the sizeof x */
-#define smallest_signed_int(x) (1u << (7u + 8u * (sizeof(x) - 1u)))
-
-/* Checks if a sequence number x is a predecessor/successor of y.
- * they handle overflows/underflows and can correctly check for a
- * predecessor/successor unless the variable sequence number has grown by
- * more then 2**(bitwidth(x)-1)-1.
- * This means that for a uint8_t with the maximum value 255, it would think:
- * - when adding nothing - it is neither a predecessor nor a successor
- * - before adding more than 127 to the starting value - it is a predecessor,
- * - when adding 128 - it is neither a predecessor nor a successor,
- * - after adding more than 127 to the starting value - it is a successor */
-#define seq_before(x, y) ({typeof(x) _dummy = (x - y); \
- _dummy > smallest_signed_int(_dummy); })
-#define seq_after(x, y) seq_before(y, x)
-
static void start_vis_timer(struct bat_priv *bat_priv);
/* free the info */
@@ -68,10 +52,10 @@ static void free_info(struct kref *ref)
}
/* Compare two vis packets, used by the hashing algorithm */
-static int vis_info_cmp(struct hlist_node *node, void *data2)
+static int vis_info_cmp(const struct hlist_node *node, const void *data2)
{
- struct vis_info *d1, *d2;
- struct vis_packet *p1, *p2;
+ const struct vis_info *d1, *d2;
+ const struct vis_packet *p1, *p2;
d1 = container_of(node, struct vis_info, hash_entry);
d2 = data2;
@@ -82,11 +66,11 @@ static int vis_info_cmp(struct hlist_node *node, void *data2)
/* hash function to choose an entry in a hash table of given size */
/* hash algorithm from http://en.wikipedia.org/wiki/Hash_table */
-static int vis_info_choose(void *data, int size)
+static int vis_info_choose(const void *data, int size)
{
- struct vis_info *vis_info = data;
- struct vis_packet *packet;
- unsigned char *key;
+ const struct vis_info *vis_info = data;
+ const struct vis_packet *packet;
+ const unsigned char *key;
uint32_t hash = 0;
size_t i;
@@ -106,7 +90,7 @@ static int vis_info_choose(void *data, int size)
}
static struct vis_info *vis_hash_find(struct bat_priv *bat_priv,
- void *data)
+ const void *data)
{
struct hashtable_t *hash = bat_priv->vis_hash;
struct hlist_head *head;
@@ -143,11 +127,11 @@ static void vis_data_insert_interface(const uint8_t *interface,
struct hlist_node *pos;
hlist_for_each_entry(entry, pos, if_list, list) {
- if (compare_eth(entry->addr, (void *)interface))
+ if (compare_eth(entry->addr, interface))
return;
}
- /* its a new address, add it to the list */
+ /* it's a new address, add it to the list */
entry = kmalloc(sizeof(*entry), GFP_ATOMIC);
if (!entry)
return;
@@ -156,7 +140,8 @@ static void vis_data_insert_interface(const uint8_t *interface,
hlist_add_head(&entry->list, if_list);
}
-static ssize_t vis_data_read_prim_sec(char *buff, struct hlist_head *if_list)
+static ssize_t vis_data_read_prim_sec(char *buff,
+ const struct hlist_head *if_list)
{
struct if_list_entry *entry;
struct hlist_node *pos;
@@ -189,8 +174,9 @@ static size_t vis_data_count_prim_sec(struct hlist_head *if_list)
}
/* read an entry */
-static ssize_t vis_data_read_entry(char *buff, struct vis_info_entry *entry,
- uint8_t *src, bool primary)
+static ssize_t vis_data_read_entry(char *buff,
+ const struct vis_info_entry *entry,
+ const uint8_t *src, bool primary)
{
/* maximal length: max(4+17+2, 3+17+1+3+2) == 26 */
if (primary && entry->quality == 0)
@@ -239,7 +225,7 @@ int vis_seq_print_text(struct seq_file *seq, void *offset)
hlist_for_each_entry_rcu(info, node, head, hash_entry) {
packet = (struct vis_packet *)info->skb_packet->data;
entries = (struct vis_info_entry *)
- ((char *)packet + sizeof(struct vis_packet));
+ ((char *)packet + sizeof(*packet));
for (j = 0; j < packet->entries; j++) {
if (entries[j].quality == 0)
@@ -287,7 +273,7 @@ int vis_seq_print_text(struct seq_file *seq, void *offset)
hlist_for_each_entry_rcu(info, node, head, hash_entry) {
packet = (struct vis_packet *)info->skb_packet->data;
entries = (struct vis_info_entry *)
- ((char *)packet + sizeof(struct vis_packet));
+ ((char *)packet + sizeof(*packet));
for (j = 0; j < packet->entries; j++) {
if (entries[j].quality == 0)
@@ -361,11 +347,11 @@ static void send_list_del(struct vis_info *info)
/* tries to add one entry to the receive list. */
static void recv_list_add(struct bat_priv *bat_priv,
- struct list_head *recv_list, char *mac)
+ struct list_head *recv_list, const char *mac)
{
struct recvlist_node *entry;
- entry = kmalloc(sizeof(struct recvlist_node), GFP_ATOMIC);
+ entry = kmalloc(sizeof(*entry), GFP_ATOMIC);
if (!entry)
return;
@@ -377,9 +363,9 @@ static void recv_list_add(struct bat_priv *bat_priv,
/* returns 1 if this mac is in the recv_list */
static int recv_list_is_in(struct bat_priv *bat_priv,
- struct list_head *recv_list, char *mac)
+ const struct list_head *recv_list, const char *mac)
{
- struct recvlist_node *entry;
+ const struct recvlist_node *entry;
spin_lock_bh(&bat_priv->vis_list_lock);
list_for_each_entry(entry, recv_list, list) {
@@ -412,11 +398,11 @@ static struct vis_info *add_packet(struct bat_priv *bat_priv,
return NULL;
/* see if the packet is already in vis_hash */
- search_elem.skb_packet = dev_alloc_skb(sizeof(struct vis_packet));
+ search_elem.skb_packet = dev_alloc_skb(sizeof(*search_packet));
if (!search_elem.skb_packet)
return NULL;
search_packet = (struct vis_packet *)skb_put(search_elem.skb_packet,
- sizeof(struct vis_packet));
+ sizeof(*search_packet));
memcpy(search_packet->vis_orig, vis_packet->vis_orig, ETH_ALEN);
old_info = vis_hash_find(bat_priv, &search_elem);
@@ -442,27 +428,26 @@ static struct vis_info *add_packet(struct bat_priv *bat_priv,
kref_put(&old_info->refcount, free_info);
}
- info = kmalloc(sizeof(struct vis_info), GFP_ATOMIC);
+ info = kmalloc(sizeof(*info), GFP_ATOMIC);
if (!info)
return NULL;
- info->skb_packet = dev_alloc_skb(sizeof(struct vis_packet) +
- vis_info_len + sizeof(struct ethhdr));
+ info->skb_packet = dev_alloc_skb(sizeof(*packet) + vis_info_len +
+ sizeof(struct ethhdr));
if (!info->skb_packet) {
kfree(info);
return NULL;
}
skb_reserve(info->skb_packet, sizeof(struct ethhdr));
- packet = (struct vis_packet *)skb_put(info->skb_packet,
- sizeof(struct vis_packet) +
- vis_info_len);
+ packet = (struct vis_packet *)skb_put(info->skb_packet, sizeof(*packet)
+ + vis_info_len);
kref_init(&info->refcount);
INIT_LIST_HEAD(&info->send_list);
INIT_LIST_HEAD(&info->recv_list);
info->first_seen = jiffies;
info->bat_priv = bat_priv;
- memcpy(packet, vis_packet, sizeof(struct vis_packet) + vis_info_len);
+ memcpy(packet, vis_packet, sizeof(*packet) + vis_info_len);
/* initialize and add new packet. */
*is_new = 1;
@@ -480,7 +465,7 @@ static struct vis_info *add_packet(struct bat_priv *bat_priv,
/* try to add it */
hash_added = hash_add(bat_priv->vis_hash, vis_info_cmp, vis_info_choose,
info, &info->hash_entry);
- if (hash_added < 0) {
+ if (hash_added != 0) {
/* did not work (for some reason) */
kref_put(&info->refcount, free_info);
info = NULL;
@@ -599,9 +584,9 @@ static int find_best_vis_server(struct bat_priv *bat_priv,
}
/* Return true if the vis packet is full. */
-static bool vis_packet_full(struct vis_info *info)
+static bool vis_packet_full(const struct vis_info *info)
{
- struct vis_packet *packet;
+ const struct vis_packet *packet;
packet = (struct vis_packet *)info->skb_packet->data;
if (MAX_VIS_PACKET_SIZE / sizeof(struct vis_info_entry)
@@ -619,7 +604,7 @@ static int generate_vis_packet(struct bat_priv *bat_priv)
struct hlist_head *head;
struct orig_node *orig_node;
struct neigh_node *router;
- struct vis_info *info = (struct vis_info *)bat_priv->my_vis_info;
+ struct vis_info *info = bat_priv->my_vis_info;
struct vis_packet *packet = (struct vis_packet *)info->skb_packet->data;
struct vis_info_entry *entry;
struct tt_local_entry *tt_local_entry;
@@ -632,7 +617,7 @@ static int generate_vis_packet(struct bat_priv *bat_priv)
packet->ttl = TTL;
packet->seqno = htonl(ntohl(packet->seqno) + 1);
packet->entries = 0;
- skb_trim(info->skb_packet, sizeof(struct vis_packet));
+ skb_trim(info->skb_packet, sizeof(*packet));
if (packet->vis_type == VIS_TYPE_CLIENT_UPDATE) {
best_tq = find_best_vis_server(bat_priv, info);
@@ -680,11 +665,12 @@ next:
hash = bat_priv->tt_local_hash;
- spin_lock_bh(&bat_priv->tt_lhash_lock);
for (i = 0; i < hash->size; i++) {
head = &hash->table[i];
- hlist_for_each_entry(tt_local_entry, node, head, hash_entry) {
+ rcu_read_lock();
+ hlist_for_each_entry_rcu(tt_local_entry, node, head,
+ hash_entry) {
entry = (struct vis_info_entry *)
skb_put(info->skb_packet,
sizeof(*entry));
@@ -693,14 +679,12 @@ next:
entry->quality = 0; /* 0 means TT */
packet->entries++;
- if (vis_packet_full(info)) {
- spin_unlock_bh(&bat_priv->tt_lhash_lock);
- return 0;
- }
+ if (vis_packet_full(info))
+ goto unlock;
}
+ rcu_read_unlock();
}
- spin_unlock_bh(&bat_priv->tt_lhash_lock);
return 0;
unlock:
@@ -903,22 +887,18 @@ int vis_init(struct bat_priv *bat_priv)
}
bat_priv->my_vis_info = kmalloc(MAX_VIS_PACKET_SIZE, GFP_ATOMIC);
- if (!bat_priv->my_vis_info) {
- pr_err("Can't initialize vis packet\n");
+ if (!bat_priv->my_vis_info)
goto err;
- }
- bat_priv->my_vis_info->skb_packet = dev_alloc_skb(
- sizeof(struct vis_packet) +
- MAX_VIS_PACKET_SIZE +
- sizeof(struct ethhdr));
+ bat_priv->my_vis_info->skb_packet = dev_alloc_skb(sizeof(*packet) +
+ MAX_VIS_PACKET_SIZE +
+ sizeof(struct ethhdr));
if (!bat_priv->my_vis_info->skb_packet)
goto free_info;
skb_reserve(bat_priv->my_vis_info->skb_packet, sizeof(struct ethhdr));
- packet = (struct vis_packet *)skb_put(
- bat_priv->my_vis_info->skb_packet,
- sizeof(struct vis_packet));
+ packet = (struct vis_packet *)skb_put(bat_priv->my_vis_info->skb_packet,
+ sizeof(*packet));
/* prefill the vis info */
bat_priv->my_vis_info->first_seen = jiffies -
@@ -938,7 +918,7 @@ int vis_init(struct bat_priv *bat_priv)
hash_added = hash_add(bat_priv->vis_hash, vis_info_cmp, vis_info_choose,
bat_priv->my_vis_info,
&bat_priv->my_vis_info->hash_entry);
- if (hash_added < 0) {
+ if (hash_added != 0) {
pr_err("Can't add own vis packet into hash\n");
/* not in hash, need to remove it manually. */
kref_put(&bat_priv->my_vis_info->refcount, free_info);
diff --git a/net/bluetooth_tizen/Kconfig b/net/bluetooth_tizen/Kconfig
deleted file mode 100644
index 6d17deb..0000000
--- a/net/bluetooth_tizen/Kconfig
+++ /dev/null
@@ -1,49 +0,0 @@
-#
-# Bluetooth subsystem configuration
-#
-
-menuconfig BT
- tristate "Bluetooth subsystem support(Tizen)"
- depends on NET && !S390
- depends on RFKILL || !RFKILL
- select CRC16
- select CRYPTO
- select CRYPTO_BLKCIPHER
- select CRYPTO_AES
- select CRYPTO_ECB
- help
- Bluetooth is low-cost, low-power, short-range wireless technology.
- It was designed as a replacement for cables and other short-range
- technologies like IrDA. Bluetooth operates in personal area range
- that typically extends up to 10 meters. More information about
- Bluetooth can be found at <http://www.bluetooth.com/>.
-
- Linux Bluetooth subsystem consist of several layers:
- Bluetooth Core
- HCI device and connection manager, scheduler
- SCO audio links
- L2CAP (Logical Link Control and Adaptation Protocol)
- SMP (Security Manager Protocol) on LE (Low Energy) links
- HCI Device drivers (Interface to the hardware)
- RFCOMM Module (RFCOMM Protocol)
- BNEP Module (Bluetooth Network Encapsulation Protocol)
- CMTP Module (CAPI Message Transport Protocol)
- HIDP Module (Human Interface Device Protocol)
-
- Say Y here to compile Bluetooth support into the kernel or say M to
- compile it as module (bluetooth).
-
- To use Linux Bluetooth subsystem, you will need several user-space
- utilities like hciconfig and bluetoothd. These utilities and updates
- to Bluetooth kernel modules are provided in the BlueZ packages. For
- more information, see <http://www.bluez.org/>.
-
-source "net/bluetooth_tizen/rfcomm/Kconfig"
-
-source "net/bluetooth_tizen/bnep/Kconfig"
-
-source "net/bluetooth_tizen/cmtp/Kconfig"
-
-source "net/bluetooth_tizen/hidp/Kconfig"
-
-source "drivers/bluetooth_tizen/Kconfig"
diff --git a/net/bluetooth_tizen/Makefile b/net/bluetooth_tizen/Makefile
deleted file mode 100644
index 2dc5a57..0000000
--- a/net/bluetooth_tizen/Makefile
+++ /dev/null
@@ -1,12 +0,0 @@
-#
-# Makefile for the Linux Bluetooth subsystem.
-#
-
-obj-$(CONFIG_BT) += bluetooth.o
-obj-$(CONFIG_BT_RFCOMM) += rfcomm/
-obj-$(CONFIG_BT_BNEP) += bnep/
-obj-$(CONFIG_BT_CMTP) += cmtp/
-obj-$(CONFIG_BT_HIDP) += hidp/
-
-bluetooth-y := af_bluetooth.o hci_core.o hci_conn.o hci_event.o mgmt.o \
- hci_sock.o hci_sysfs.o l2cap_core.o l2cap_sock.o smp.o sco.o lib.o
diff --git a/net/bluetooth_tizen/af_bluetooth.c b/net/bluetooth_tizen/af_bluetooth.c
deleted file mode 100644
index 6fb68a9..0000000
--- a/net/bluetooth_tizen/af_bluetooth.c
+++ /dev/null
@@ -1,616 +0,0 @@
-/*
- BlueZ - Bluetooth protocol stack for Linux
- Copyright (C) 2000-2001 Qualcomm Incorporated
-
- Written 2000,2001 by Maxim Krasnyansky <maxk@qualcomm.com>
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License version 2 as
- published by the Free Software Foundation;
-
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
- OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS.
- IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY
- CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES
- WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
- OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
-
- ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS,
- COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS
- SOFTWARE IS DISCLAIMED.
-*/
-
-/* Bluetooth address family and sockets. */
-
-#include <linux/module.h>
-
-#include <linux/types.h>
-#include <linux/list.h>
-#include <linux/errno.h>
-#include <linux/kernel.h>
-#include <linux/sched.h>
-#include <linux/skbuff.h>
-#include <linux/init.h>
-#include <linux/poll.h>
-#include <net/sock.h>
-#include <asm/ioctls.h>
-#include <linux/kmod.h>
-
-#include <net/bluetooth/bluetooth.h>
-
-#define VERSION "2.16"
-
-/* Bluetooth sockets */
-#define BT_MAX_PROTO 8
-static const struct net_proto_family *bt_proto[BT_MAX_PROTO];
-static DEFINE_RWLOCK(bt_proto_lock);
-
-static struct lock_class_key bt_lock_key[BT_MAX_PROTO];
-static const char *const bt_key_strings[BT_MAX_PROTO] = {
- "sk_lock-AF_BLUETOOTH-BTPROTO_L2CAP",
- "sk_lock-AF_BLUETOOTH-BTPROTO_HCI",
- "sk_lock-AF_BLUETOOTH-BTPROTO_SCO",
- "sk_lock-AF_BLUETOOTH-BTPROTO_RFCOMM",
- "sk_lock-AF_BLUETOOTH-BTPROTO_BNEP",
- "sk_lock-AF_BLUETOOTH-BTPROTO_CMTP",
- "sk_lock-AF_BLUETOOTH-BTPROTO_HIDP",
- "sk_lock-AF_BLUETOOTH-BTPROTO_AVDTP",
-};
-
-static struct lock_class_key bt_slock_key[BT_MAX_PROTO];
-static const char *const bt_slock_key_strings[BT_MAX_PROTO] = {
- "slock-AF_BLUETOOTH-BTPROTO_L2CAP",
- "slock-AF_BLUETOOTH-BTPROTO_HCI",
- "slock-AF_BLUETOOTH-BTPROTO_SCO",
- "slock-AF_BLUETOOTH-BTPROTO_RFCOMM",
- "slock-AF_BLUETOOTH-BTPROTO_BNEP",
- "slock-AF_BLUETOOTH-BTPROTO_CMTP",
- "slock-AF_BLUETOOTH-BTPROTO_HIDP",
- "slock-AF_BLUETOOTH-BTPROTO_AVDTP",
-};
-
-void bt_sock_reclassify_lock(struct sock *sk, int proto)
-{
- BUG_ON(!sk);
- BUG_ON(sock_owned_by_user(sk));
-
- sock_lock_init_class_and_name(sk,
- bt_slock_key_strings[proto], &bt_slock_key[proto],
- bt_key_strings[proto], &bt_lock_key[proto]);
-}
-EXPORT_SYMBOL(bt_sock_reclassify_lock);
-
-int bt_sock_register(int proto, const struct net_proto_family *ops)
-{
- int err = 0;
-
- if (proto < 0 || proto >= BT_MAX_PROTO)
- return -EINVAL;
-
- write_lock(&bt_proto_lock);
-
- if (bt_proto[proto])
- err = -EEXIST;
- else
- bt_proto[proto] = ops;
-
- write_unlock(&bt_proto_lock);
-
- return err;
-}
-EXPORT_SYMBOL(bt_sock_register);
-
-int bt_sock_unregister(int proto)
-{
- int err = 0;
-
- if (proto < 0 || proto >= BT_MAX_PROTO)
- return -EINVAL;
-
- write_lock(&bt_proto_lock);
-
- if (!bt_proto[proto])
- err = -ENOENT;
- else
- bt_proto[proto] = NULL;
-
- write_unlock(&bt_proto_lock);
-
- return err;
-}
-EXPORT_SYMBOL(bt_sock_unregister);
-
-static int bt_sock_create(struct net *net, struct socket *sock, int proto,
- int kern)
-{
- int err;
-
- if (net != &init_net)
- return -EAFNOSUPPORT;
-
- if (proto < 0 || proto >= BT_MAX_PROTO)
- return -EINVAL;
-
- if (!bt_proto[proto])
- request_module("bt-proto-%d", proto);
-
- err = -EPROTONOSUPPORT;
-
- read_lock(&bt_proto_lock);
-
- if (bt_proto[proto] && try_module_get(bt_proto[proto]->owner)) {
- err = bt_proto[proto]->create(net, sock, proto, kern);
- if (!err)
- bt_sock_reclassify_lock(sock->sk, proto);
- module_put(bt_proto[proto]->owner);
- }
-
- read_unlock(&bt_proto_lock);
-
- return err;
-}
-
-void bt_sock_link(struct bt_sock_list *l, struct sock *sk)
-{
- write_lock(&l->lock);
- sk_add_node(sk, &l->head);
- write_unlock(&l->lock);
-}
-EXPORT_SYMBOL(bt_sock_link);
-
-void bt_sock_unlink(struct bt_sock_list *l, struct sock *sk)
-{
- write_lock(&l->lock);
- sk_del_node_init(sk);
- write_unlock(&l->lock);
-}
-EXPORT_SYMBOL(bt_sock_unlink);
-
-void bt_accept_enqueue(struct sock *parent, struct sock *sk)
-{
- BT_DBG("parent %p, sk %p", parent, sk);
-
- sock_hold(sk);
- list_add_tail(&bt_sk(sk)->accept_q, &bt_sk(parent)->accept_q);
- bt_sk(sk)->parent = parent;
- parent->sk_ack_backlog++;
-}
-EXPORT_SYMBOL(bt_accept_enqueue);
-
-void bt_accept_unlink(struct sock *sk)
-{
- BT_DBG("sk %p state %d", sk, sk->sk_state);
-
- list_del_init(&bt_sk(sk)->accept_q);
- bt_sk(sk)->parent->sk_ack_backlog--;
- bt_sk(sk)->parent = NULL;
- sock_put(sk);
-}
-EXPORT_SYMBOL(bt_accept_unlink);
-
-struct sock *bt_accept_dequeue(struct sock *parent, struct socket *newsock)
-{
- struct list_head *p, *n;
- struct sock *sk;
-
- BT_DBG("parent %p", parent);
-
- list_for_each_safe(p, n, &bt_sk(parent)->accept_q) {
- sk = (struct sock *) list_entry(p, struct bt_sock, accept_q);
-
- lock_sock(sk);
-
- /* FIXME: Is this check still needed */
- if (sk->sk_state == BT_CLOSED) {
- release_sock(sk);
- bt_accept_unlink(sk);
- continue;
- }
-
- if (sk->sk_state == BT_CONNECTED || !newsock ||
- bt_sk(parent)->defer_setup) {
- bt_accept_unlink(sk);
- if (newsock)
- sock_graft(sk, newsock);
-
- release_sock(sk);
- return sk;
- }
-
- release_sock(sk);
- }
-
- return NULL;
-}
-EXPORT_SYMBOL(bt_accept_dequeue);
-
-int bt_sock_recvmsg(struct kiocb *iocb, struct socket *sock,
- struct msghdr *msg, size_t len, int flags)
-{
- int noblock = flags & MSG_DONTWAIT;
- struct sock *sk = sock->sk;
- struct sk_buff *skb;
- size_t copied;
- int err;
-
- BT_DBG("sock %p sk %p len %zu", sock, sk, len);
-
- if (flags & (MSG_OOB))
- return -EOPNOTSUPP;
-
- skb = skb_recv_datagram(sk, flags, noblock, &err);
- if (!skb) {
- if (sk->sk_shutdown & RCV_SHUTDOWN)
- return 0;
- return err;
- }
-
- msg->msg_namelen = 0;
-
- copied = skb->len;
- if (len < copied) {
- msg->msg_flags |= MSG_TRUNC;
- copied = len;
- }
-
- skb_reset_transport_header(skb);
- err = skb_copy_datagram_iovec(skb, 0, msg->msg_iov, copied);
- if (err == 0)
- sock_recv_ts_and_drops(msg, sk, skb);
-
- skb_free_datagram(sk, skb);
-
- return err ? : copied;
-}
-EXPORT_SYMBOL(bt_sock_recvmsg);
-
-static long bt_sock_data_wait(struct sock *sk, long timeo)
-{
- DECLARE_WAITQUEUE(wait, current);
-
- add_wait_queue(sk_sleep(sk), &wait);
- for (;;) {
- set_current_state(TASK_INTERRUPTIBLE);
-
- if (!skb_queue_empty(&sk->sk_receive_queue))
- break;
-
- if (sk->sk_err || (sk->sk_shutdown & RCV_SHUTDOWN))
- break;
-
- if (signal_pending(current) || !timeo)
- break;
-
- set_bit(SOCK_ASYNC_WAITDATA, &sk->sk_socket->flags);
- release_sock(sk);
- timeo = schedule_timeout(timeo);
- lock_sock(sk);
- clear_bit(SOCK_ASYNC_WAITDATA, &sk->sk_socket->flags);
- }
-
- __set_current_state(TASK_RUNNING);
- remove_wait_queue(sk_sleep(sk), &wait);
- return timeo;
-}
-
-int bt_sock_stream_recvmsg(struct kiocb *iocb, struct socket *sock,
- struct msghdr *msg, size_t size, int flags)
-{
- struct sock *sk = sock->sk;
- int err = 0;
- size_t target, copied = 0;
- long timeo;
-
- if (flags & MSG_OOB)
- return -EOPNOTSUPP;
-
- msg->msg_namelen = 0;
-
- BT_DBG("sk %p size %zu", sk, size);
-
- lock_sock(sk);
-
- target = sock_rcvlowat(sk, flags & MSG_WAITALL, size);
- timeo = sock_rcvtimeo(sk, flags & MSG_DONTWAIT);
-
- do {
- struct sk_buff *skb;
- int chunk;
-
- skb = skb_dequeue(&sk->sk_receive_queue);
- if (!skb) {
- if (copied >= target)
- break;
-
- err = sock_error(sk);
- if (err)
- break;
- if (sk->sk_shutdown & RCV_SHUTDOWN)
- break;
-
- err = -EAGAIN;
- if (!timeo)
- break;
-
- timeo = bt_sock_data_wait(sk, timeo);
-
- if (signal_pending(current)) {
- err = sock_intr_errno(timeo);
- goto out;
- }
- continue;
- }
-
- chunk = min_t(unsigned int, skb->len, size);
- if (skb_copy_datagram_iovec(skb, 0, msg->msg_iov, chunk)) {
- skb_queue_head(&sk->sk_receive_queue, skb);
- if (!copied)
- copied = -EFAULT;
- break;
- }
- copied += chunk;
- size -= chunk;
-
- sock_recv_ts_and_drops(msg, sk, skb);
-
- if (!(flags & MSG_PEEK)) {
- int skb_len = skb_headlen(skb);
-
- if (chunk <= skb_len) {
- __skb_pull(skb, chunk);
- } else {
- struct sk_buff *frag;
-
- __skb_pull(skb, skb_len);
- chunk -= skb_len;
-
- skb_walk_frags(skb, frag) {
- if (chunk <= frag->len) {
- /* Pulling partial data */
- skb->len -= chunk;
- skb->data_len -= chunk;
- __skb_pull(frag, chunk);
- break;
- } else if (frag->len) {
- /* Pulling all frag data */
- chunk -= frag->len;
- skb->len -= frag->len;
- skb->data_len -= frag->len;
- __skb_pull(frag, frag->len);
- }
- }
- }
-
- if (skb->len) {
- skb_queue_head(&sk->sk_receive_queue, skb);
- break;
- }
- kfree_skb(skb);
-
- } else {
- /* put message back and return */
- skb_queue_head(&sk->sk_receive_queue, skb);
- break;
- }
- } while (size);
-
-out:
- release_sock(sk);
- return copied ? : err;
-}
-EXPORT_SYMBOL(bt_sock_stream_recvmsg);
-
-static inline unsigned int bt_accept_poll(struct sock *parent)
-{
- struct list_head *p, *n;
- struct sock *sk;
-
- list_for_each_safe(p, n, &bt_sk(parent)->accept_q) {
- sk = (struct sock *) list_entry(p, struct bt_sock, accept_q);
- if (sk->sk_state == BT_CONNECTED ||
- (bt_sk(parent)->defer_setup &&
- sk->sk_state == BT_CONNECT2))
- return POLLIN | POLLRDNORM;
- }
-
- return 0;
-}
-
-unsigned int bt_sock_poll(struct file *file, struct socket *sock, poll_table *wait)
-{
- struct sock *sk = sock->sk;
- unsigned int mask = 0;
-
- BT_DBG("sock %p, sk %p", sock, sk);
-
- poll_wait(file, sk_sleep(sk), wait);
-
- if (sk->sk_state == BT_LISTEN)
- return bt_accept_poll(sk);
-
- if (sk->sk_err || !skb_queue_empty(&sk->sk_error_queue))
- mask |= POLLERR;
-
- if (sk->sk_shutdown & RCV_SHUTDOWN)
- mask |= POLLRDHUP | POLLIN | POLLRDNORM;
-
- if (sk->sk_shutdown == SHUTDOWN_MASK)
- mask |= POLLHUP;
-
- if (!skb_queue_empty(&sk->sk_receive_queue))
- mask |= POLLIN | POLLRDNORM;
-
- if (sk->sk_state == BT_CLOSED)
- mask |= POLLHUP;
-
- if (sk->sk_state == BT_CONNECT ||
- sk->sk_state == BT_CONNECT2 ||
- sk->sk_state == BT_CONFIG)
- return mask;
-
- if (!bt_sk(sk)->suspended && sock_writeable(sk))
- mask |= POLLOUT | POLLWRNORM | POLLWRBAND;
- else
- set_bit(SOCK_ASYNC_NOSPACE, &sk->sk_socket->flags);
-
- return mask;
-}
-EXPORT_SYMBOL(bt_sock_poll);
-
-int bt_sock_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
-{
- struct sock *sk = sock->sk;
- struct sk_buff *skb;
- long amount;
- int err;
-
- BT_DBG("sk %p cmd %x arg %lx", sk, cmd, arg);
-
- switch (cmd) {
- case TIOCOUTQ:
- if (sk->sk_state == BT_LISTEN)
- return -EINVAL;
-
- amount = sk->sk_sndbuf - sk_wmem_alloc_get(sk);
- if (amount < 0)
- amount = 0;
- err = put_user(amount, (int __user *) arg);
- break;
-
- case TIOCINQ:
- if (sk->sk_state == BT_LISTEN)
- return -EINVAL;
-
- lock_sock(sk);
- skb = skb_peek(&sk->sk_receive_queue);
- amount = skb ? skb->len : 0;
- release_sock(sk);
- err = put_user(amount, (int __user *) arg);
- break;
-
- case SIOCGSTAMP:
- err = sock_get_timestamp(sk, (struct timeval __user *) arg);
- break;
-
- case SIOCGSTAMPNS:
- err = sock_get_timestampns(sk, (struct timespec __user *) arg);
- break;
-
- default:
- err = -ENOIOCTLCMD;
- break;
- }
-
- return err;
-}
-EXPORT_SYMBOL(bt_sock_ioctl);
-
-int bt_sock_wait_state(struct sock *sk, int state, unsigned long timeo)
-{
- DECLARE_WAITQUEUE(wait, current);
- int err = 0;
-
- BT_DBG("sk %p", sk);
-
- add_wait_queue(sk_sleep(sk), &wait);
- set_current_state(TASK_INTERRUPTIBLE);
- while (sk->sk_state != state) {
- if (!timeo) {
- err = -EINPROGRESS;
- break;
- }
-
- if (signal_pending(current)) {
- err = sock_intr_errno(timeo);
- break;
- }
-
- release_sock(sk);
- timeo = schedule_timeout(timeo);
- lock_sock(sk);
- set_current_state(TASK_INTERRUPTIBLE);
-
- err = sock_error(sk);
- if (err)
- break;
- }
- __set_current_state(TASK_RUNNING);
- remove_wait_queue(sk_sleep(sk), &wait);
- return err;
-}
-EXPORT_SYMBOL(bt_sock_wait_state);
-
-static struct net_proto_family bt_sock_family_ops = {
- .owner = THIS_MODULE,
- .family = PF_BLUETOOTH,
- .create = bt_sock_create,
-};
-
-static int __init bt_init(void)
-{
- int err;
-
- BT_INFO("Core ver %s", VERSION);
-
- err = bt_sysfs_init();
- if (err < 0)
- return err;
-
- err = sock_register(&bt_sock_family_ops);
- if (err < 0) {
- bt_sysfs_cleanup();
- return err;
- }
-
- BT_INFO("HCI device and connection manager initialized");
-
- err = hci_sock_init();
- if (err < 0)
- goto error;
-
- err = l2cap_init();
- if (err < 0)
- goto sock_err;
-
- err = sco_init();
- if (err < 0) {
- l2cap_exit();
- goto sock_err;
- }
-
- return 0;
-
-sock_err:
- hci_sock_cleanup();
-
-error:
- sock_unregister(PF_BLUETOOTH);
- bt_sysfs_cleanup();
-
- return err;
-}
-
-static void __exit bt_exit(void)
-{
-
- sco_exit();
-
- l2cap_exit();
-
- hci_sock_cleanup();
-
- sock_unregister(PF_BLUETOOTH);
-
- bt_sysfs_cleanup();
-}
-
-subsys_initcall(bt_init);
-module_exit(bt_exit);
-
-MODULE_AUTHOR("Marcel Holtmann <marcel@holtmann.org>");
-MODULE_DESCRIPTION("Bluetooth Core ver " VERSION);
-MODULE_VERSION(VERSION);
-MODULE_LICENSE("GPL");
-MODULE_ALIAS_NETPROTO(PF_BLUETOOTH);
diff --git a/net/bluetooth_tizen/bnep/Kconfig b/net/bluetooth_tizen/bnep/Kconfig
deleted file mode 100644
index 71791fc..0000000
--- a/net/bluetooth_tizen/bnep/Kconfig
+++ /dev/null
@@ -1,24 +0,0 @@
-config BT_BNEP
- tristate "BNEP protocol support"
- depends on BT
- select CRC32
- help
- BNEP (Bluetooth Network Encapsulation Protocol) is Ethernet
- emulation layer on top of Bluetooth. BNEP is required for
- Bluetooth PAN (Personal Area Network).
-
- Say Y here to compile BNEP support into the kernel or say M to
- compile it as module (bnep).
-
-config BT_BNEP_MC_FILTER
- bool "Multicast filter support"
- depends on BT_BNEP
- help
- This option enables the multicast filter support for BNEP.
-
-config BT_BNEP_PROTO_FILTER
- bool "Protocol filter support"
- depends on BT_BNEP
- help
- This option enables the protocol filter support for BNEP.
-
diff --git a/net/bluetooth_tizen/bnep/Makefile b/net/bluetooth_tizen/bnep/Makefile
deleted file mode 100644
index c7821e7..0000000
--- a/net/bluetooth_tizen/bnep/Makefile
+++ /dev/null
@@ -1,7 +0,0 @@
-#
-# Makefile for the Linux Bluetooth BNEP layer.
-#
-
-obj-$(CONFIG_BT_BNEP) += bnep.o
-
-bnep-objs := core.o sock.o netdev.o
diff --git a/net/bluetooth_tizen/bnep/bnep.h b/net/bluetooth_tizen/bnep/bnep.h
deleted file mode 100644
index e7ee531..0000000
--- a/net/bluetooth_tizen/bnep/bnep.h
+++ /dev/null
@@ -1,180 +0,0 @@
-/*
- BNEP protocol definition for Linux Bluetooth stack (BlueZ).
- Copyright (C) 2002 Maxim Krasnyansky <maxk@qualcomm.com>
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License, version 2, as
- published by the Free Software Foundation.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-*/
-
-#ifndef _BNEP_H
-#define _BNEP_H
-
-#include <linux/types.h>
-#include <linux/crc32.h>
-#include <net/bluetooth/bluetooth.h>
-
-/* Limits */
-#define BNEP_MAX_PROTO_FILTERS 5
-#define BNEP_MAX_MULTICAST_FILTERS 20
-
-/* UUIDs */
-#define BNEP_BASE_UUID 0x0000000000001000800000805F9B34FB
-#define BNEP_UUID16 0x02
-#define BNEP_UUID32 0x04
-#define BNEP_UUID128 0x16
-
-#define BNEP_SVC_PANU 0x1115
-#define BNEP_SVC_NAP 0x1116
-#define BNEP_SVC_GN 0x1117
-
-/* Packet types */
-#define BNEP_GENERAL 0x00
-#define BNEP_CONTROL 0x01
-#define BNEP_COMPRESSED 0x02
-#define BNEP_COMPRESSED_SRC_ONLY 0x03
-#define BNEP_COMPRESSED_DST_ONLY 0x04
-
-/* Control types */
-#define BNEP_CMD_NOT_UNDERSTOOD 0x00
-#define BNEP_SETUP_CONN_REQ 0x01
-#define BNEP_SETUP_CONN_RSP 0x02
-#define BNEP_FILTER_NET_TYPE_SET 0x03
-#define BNEP_FILTER_NET_TYPE_RSP 0x04
-#define BNEP_FILTER_MULTI_ADDR_SET 0x05
-#define BNEP_FILTER_MULTI_ADDR_RSP 0x06
-
-/* Extension types */
-#define BNEP_EXT_CONTROL 0x00
-
-/* Response messages */
-#define BNEP_SUCCESS 0x00
-
-#define BNEP_CONN_INVALID_DST 0x01
-#define BNEP_CONN_INVALID_SRC 0x02
-#define BNEP_CONN_INVALID_SVC 0x03
-#define BNEP_CONN_NOT_ALLOWED 0x04
-
-#define BNEP_FILTER_UNSUPPORTED_REQ 0x01
-#define BNEP_FILTER_INVALID_RANGE 0x02
-#define BNEP_FILTER_INVALID_MCADDR 0x02
-#define BNEP_FILTER_LIMIT_REACHED 0x03
-#define BNEP_FILTER_DENIED_SECURITY 0x04
-
-/* L2CAP settings */
-#define BNEP_MTU 1691
-#define BNEP_PSM 0x0f
-#define BNEP_FLUSH_TO 0xffff
-#define BNEP_CONNECT_TO 15
-#define BNEP_FILTER_TO 15
-
-/* Headers */
-#define BNEP_TYPE_MASK 0x7f
-#define BNEP_EXT_HEADER 0x80
-
-struct bnep_setup_conn_req {
- __u8 type;
- __u8 ctrl;
- __u8 uuid_size;
- __u8 service[0];
-} __packed;
-
-struct bnep_set_filter_req {
- __u8 type;
- __u8 ctrl;
- __be16 len;
- __u8 list[0];
-} __packed;
-
-struct bnep_control_rsp {
- __u8 type;
- __u8 ctrl;
- __be16 resp;
-} __packed;
-
-struct bnep_ext_hdr {
- __u8 type;
- __u8 len;
- __u8 data[0];
-} __packed;
-
-/* BNEP ioctl defines */
-#define BNEPCONNADD _IOW('B', 200, int)
-#define BNEPCONNDEL _IOW('B', 201, int)
-#define BNEPGETCONNLIST _IOR('B', 210, int)
-#define BNEPGETCONNINFO _IOR('B', 211, int)
-
-struct bnep_connadd_req {
- int sock; /* Connected socket */
- __u32 flags;
- __u16 role;
- char device[16]; /* Name of the Ethernet device */
-};
-
-struct bnep_conndel_req {
- __u32 flags;
- __u8 dst[ETH_ALEN];
-};
-
-struct bnep_conninfo {
- __u32 flags;
- __u16 role;
- __u16 state;
- __u8 dst[ETH_ALEN];
- char device[16];
-};
-
-struct bnep_connlist_req {
- __u32 cnum;
- struct bnep_conninfo __user *ci;
-};
-
-struct bnep_proto_filter {
- __u16 start;
- __u16 end;
-};
-
-int bnep_add_connection(struct bnep_connadd_req *req, struct socket *sock);
-int bnep_del_connection(struct bnep_conndel_req *req);
-int bnep_get_connlist(struct bnep_connlist_req *req);
-int bnep_get_conninfo(struct bnep_conninfo *ci);
-
-/* BNEP sessions */
-struct bnep_session {
- struct list_head list;
-
- unsigned int role;
- unsigned long state;
- unsigned long flags;
- atomic_t terminate;
- struct task_struct *task;
-
- struct ethhdr eh;
- struct msghdr msg;
-
- struct bnep_proto_filter proto_filter[BNEP_MAX_PROTO_FILTERS];
- unsigned long long mc_filter;
-
- struct socket *sock;
- struct net_device *dev;
-};
-
-void bnep_net_setup(struct net_device *dev);
-int bnep_sock_init(void);
-void bnep_sock_cleanup(void);
-
-static inline int bnep_mc_hash(__u8 *addr)
-{
- return crc32_be(~0, addr, ETH_ALEN) >> 26;
-}
-
-#endif
diff --git a/net/bluetooth_tizen/bnep/core.c b/net/bluetooth_tizen/bnep/core.c
deleted file mode 100644
index a779ec7..0000000
--- a/net/bluetooth_tizen/bnep/core.c
+++ /dev/null
@@ -1,747 +0,0 @@
-/*
- BNEP implementation for Linux Bluetooth stack (BlueZ).
- Copyright (C) 2001-2002 Inventel Systemes
- Written 2001-2002 by
- Clément Moreau <clement.moreau@inventel.fr>
- David Libault <david.libault@inventel.fr>
-
- Copyright (C) 2002 Maxim Krasnyansky <maxk@qualcomm.com>
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License version 2 as
- published by the Free Software Foundation;
-
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
- OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS.
- IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY
- CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES
- WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
- OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
-
- ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS,
- COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS
- SOFTWARE IS DISCLAIMED.
-*/
-
-#include <linux/module.h>
-
-#include <linux/kernel.h>
-#include <linux/sched.h>
-#include <linux/signal.h>
-#include <linux/init.h>
-#include <linux/wait.h>
-#include <linux/freezer.h>
-#include <linux/errno.h>
-#include <linux/net.h>
-#include <linux/slab.h>
-#include <linux/kthread.h>
-#include <net/sock.h>
-
-#include <linux/socket.h>
-#include <linux/file.h>
-
-#include <linux/netdevice.h>
-#include <linux/etherdevice.h>
-#include <linux/skbuff.h>
-
-#include <asm/unaligned.h>
-
-#include <net/bluetooth/bluetooth.h>
-#include <net/bluetooth/hci_core.h>
-#include <net/bluetooth/l2cap.h>
-
-#include "bnep.h"
-
-#define VERSION "1.3"
-
-static bool compress_src = true;
-static bool compress_dst = true;
-
-static LIST_HEAD(bnep_session_list);
-static DECLARE_RWSEM(bnep_session_sem);
-
-static struct bnep_session *__bnep_get_session(u8 *dst)
-{
- struct bnep_session *s;
-
- BT_DBG("");
-
- list_for_each_entry(s, &bnep_session_list, list)
- if (!compare_ether_addr(dst, s->eh.h_source))
- return s;
-
- return NULL;
-}
-
-static void __bnep_link_session(struct bnep_session *s)
-{
- list_add(&s->list, &bnep_session_list);
-}
-
-static void __bnep_unlink_session(struct bnep_session *s)
-{
- list_del(&s->list);
-}
-
-static int bnep_send(struct bnep_session *s, void *data, size_t len)
-{
- struct socket *sock = s->sock;
- struct kvec iv = { data, len };
-
- return kernel_sendmsg(sock, &s->msg, &iv, 1, len);
-}
-
-static int bnep_send_rsp(struct bnep_session *s, u8 ctrl, u16 resp)
-{
- struct bnep_control_rsp rsp;
- rsp.type = BNEP_CONTROL;
- rsp.ctrl = ctrl;
- rsp.resp = htons(resp);
- return bnep_send(s, &rsp, sizeof(rsp));
-}
-
-#ifdef CONFIG_BT_BNEP_PROTO_FILTER
-static inline void bnep_set_default_proto_filter(struct bnep_session *s)
-{
- /* (IPv4, ARP) */
- s->proto_filter[0].start = ETH_P_IP;
- s->proto_filter[0].end = ETH_P_ARP;
- /* (RARP, AppleTalk) */
- s->proto_filter[1].start = ETH_P_RARP;
- s->proto_filter[1].end = ETH_P_AARP;
- /* (IPX, IPv6) */
- s->proto_filter[2].start = ETH_P_IPX;
- s->proto_filter[2].end = ETH_P_IPV6;
-}
-#endif
-
-static int bnep_ctrl_set_netfilter(struct bnep_session *s, __be16 *data, int len)
-{
- int n;
-
- if (len < 2)
- return -EILSEQ;
-
- n = get_unaligned_be16(data);
- data++;
- len -= 2;
-
- if (len < n)
- return -EILSEQ;
-
- BT_DBG("filter len %d", n);
-
-#ifdef CONFIG_BT_BNEP_PROTO_FILTER
- n /= 4;
- if (n <= BNEP_MAX_PROTO_FILTERS) {
- struct bnep_proto_filter *f = s->proto_filter;
- int i;
-
- for (i = 0; i < n; i++) {
- f[i].start = get_unaligned_be16(data++);
- f[i].end = get_unaligned_be16(data++);
-
- BT_DBG("proto filter start %d end %d",
- f[i].start, f[i].end);
- }
-
- if (i < BNEP_MAX_PROTO_FILTERS)
- memset(f + i, 0, sizeof(*f));
-
- if (n == 0)
- bnep_set_default_proto_filter(s);
-
- bnep_send_rsp(s, BNEP_FILTER_NET_TYPE_RSP, BNEP_SUCCESS);
- } else {
- bnep_send_rsp(s, BNEP_FILTER_NET_TYPE_RSP, BNEP_FILTER_LIMIT_REACHED);
- }
-#else
- bnep_send_rsp(s, BNEP_FILTER_NET_TYPE_RSP, BNEP_FILTER_UNSUPPORTED_REQ);
-#endif
- return 0;
-}
-
-static int bnep_ctrl_set_mcfilter(struct bnep_session *s, u8 *data, int len)
-{
- int n;
-
- if (len < 2)
- return -EILSEQ;
-
- n = get_unaligned_be16(data);
- data += 2;
- len -= 2;
-
- if (len < n)
- return -EILSEQ;
-
- BT_DBG("filter len %d", n);
-
-#ifdef CONFIG_BT_BNEP_MC_FILTER
- n /= (ETH_ALEN * 2);
-
- if (n > 0) {
- int i;
-
- s->mc_filter = 0;
-
- /* Always send broadcast */
- set_bit(bnep_mc_hash(s->dev->broadcast), (ulong *) &s->mc_filter);
-
- /* Add address ranges to the multicast hash */
- for (; n > 0; n--) {
- u8 a1[6], *a2;
-
- memcpy(a1, data, ETH_ALEN);
- data += ETH_ALEN;
- a2 = data;
- data += ETH_ALEN;
-
- BT_DBG("mc filter %s -> %s",
- batostr((void *) a1), batostr((void *) a2));
-
- /* Iterate from a1 to a2 */
- set_bit(bnep_mc_hash(a1), (ulong *) &s->mc_filter);
- while (memcmp(a1, a2, 6) < 0 && s->mc_filter != ~0LL) {
- /* Increment a1 */
- i = 5;
- while (i >= 0 && ++a1[i--] == 0)
- ;
-
- set_bit(bnep_mc_hash(a1), (ulong *) &s->mc_filter);
- }
- }
- }
-
- BT_DBG("mc filter hash 0x%llx", s->mc_filter);
-
- bnep_send_rsp(s, BNEP_FILTER_MULTI_ADDR_RSP, BNEP_SUCCESS);
-#else
- bnep_send_rsp(s, BNEP_FILTER_MULTI_ADDR_RSP, BNEP_FILTER_UNSUPPORTED_REQ);
-#endif
- return 0;
-}
-
-static int bnep_rx_control(struct bnep_session *s, void *data, int len)
-{
- u8 cmd = *(u8 *)data;
- int err = 0;
-
- data++;
- len--;
-
- switch (cmd) {
- case BNEP_CMD_NOT_UNDERSTOOD:
- case BNEP_SETUP_CONN_RSP:
- case BNEP_FILTER_NET_TYPE_RSP:
- case BNEP_FILTER_MULTI_ADDR_RSP:
- /* Ignore these for now */
- break;
-
- case BNEP_FILTER_NET_TYPE_SET:
- err = bnep_ctrl_set_netfilter(s, data, len);
- break;
-
- case BNEP_FILTER_MULTI_ADDR_SET:
- err = bnep_ctrl_set_mcfilter(s, data, len);
- break;
-
- case BNEP_SETUP_CONN_REQ:
- err = bnep_send_rsp(s, BNEP_SETUP_CONN_RSP, BNEP_CONN_NOT_ALLOWED);
- break;
-
- default: {
- u8 pkt[3];
- pkt[0] = BNEP_CONTROL;
- pkt[1] = BNEP_CMD_NOT_UNDERSTOOD;
- pkt[2] = cmd;
- bnep_send(s, pkt, sizeof(pkt));
- }
- break;
- }
-
- return err;
-}
-
-static int bnep_rx_extension(struct bnep_session *s, struct sk_buff *skb)
-{
- struct bnep_ext_hdr *h;
- int err = 0;
-
- do {
- h = (void *) skb->data;
- if (!skb_pull(skb, sizeof(*h))) {
- err = -EILSEQ;
- break;
- }
-
- BT_DBG("type 0x%x len %d", h->type, h->len);
-
- switch (h->type & BNEP_TYPE_MASK) {
- case BNEP_EXT_CONTROL:
- bnep_rx_control(s, skb->data, skb->len);
- break;
-
- default:
- /* Unknown extension, skip it. */
- break;
- }
-
- if (!skb_pull(skb, h->len)) {
- err = -EILSEQ;
- break;
- }
- } while (!err && (h->type & BNEP_EXT_HEADER));
-
- return err;
-}
-
-static u8 __bnep_rx_hlen[] = {
- ETH_HLEN, /* BNEP_GENERAL */
- 0, /* BNEP_CONTROL */
- 2, /* BNEP_COMPRESSED */
- ETH_ALEN + 2, /* BNEP_COMPRESSED_SRC_ONLY */
- ETH_ALEN + 2 /* BNEP_COMPRESSED_DST_ONLY */
-};
-
-static inline int bnep_rx_frame(struct bnep_session *s, struct sk_buff *skb)
-{
- struct net_device *dev = s->dev;
- struct sk_buff *nskb;
- u8 type;
-
- dev->stats.rx_bytes += skb->len;
-
- type = *(u8 *) skb->data;
- skb_pull(skb, 1);
-
- if ((type & BNEP_TYPE_MASK) >= sizeof(__bnep_rx_hlen))
- goto badframe;
-
- if ((type & BNEP_TYPE_MASK) == BNEP_CONTROL) {
- bnep_rx_control(s, skb->data, skb->len);
- kfree_skb(skb);
- return 0;
- }
-
- skb_reset_mac_header(skb);
-
- /* Verify and pull out header */
- if (!skb_pull(skb, __bnep_rx_hlen[type & BNEP_TYPE_MASK]))
- goto badframe;
-
- s->eh.h_proto = get_unaligned((__be16 *) (skb->data - 2));
-
- if (type & BNEP_EXT_HEADER) {
- if (bnep_rx_extension(s, skb) < 0)
- goto badframe;
- }
-
- /* Strip 802.1p header */
- if (ntohs(s->eh.h_proto) == 0x8100) {
- if (!skb_pull(skb, 4))
- goto badframe;
- s->eh.h_proto = get_unaligned((__be16 *) (skb->data - 2));
- }
-
- /* We have to alloc new skb and copy data here :(. Because original skb
- * may not be modified and because of the alignment requirements. */
- nskb = alloc_skb(2 + ETH_HLEN + skb->len, GFP_KERNEL);
- if (!nskb) {
- dev->stats.rx_dropped++;
- kfree_skb(skb);
- return -ENOMEM;
- }
- skb_reserve(nskb, 2);
-
- /* Decompress header and construct ether frame */
- switch (type & BNEP_TYPE_MASK) {
- case BNEP_COMPRESSED:
- memcpy(__skb_put(nskb, ETH_HLEN), &s->eh, ETH_HLEN);
- break;
-
- case BNEP_COMPRESSED_SRC_ONLY:
- memcpy(__skb_put(nskb, ETH_ALEN), s->eh.h_dest, ETH_ALEN);
- memcpy(__skb_put(nskb, ETH_ALEN), skb_mac_header(skb), ETH_ALEN);
- put_unaligned(s->eh.h_proto, (__be16 *) __skb_put(nskb, 2));
- break;
-
- case BNEP_COMPRESSED_DST_ONLY:
- memcpy(__skb_put(nskb, ETH_ALEN), skb_mac_header(skb),
- ETH_ALEN);
- memcpy(__skb_put(nskb, ETH_ALEN + 2), s->eh.h_source,
- ETH_ALEN + 2);
- break;
-
- case BNEP_GENERAL:
- memcpy(__skb_put(nskb, ETH_ALEN * 2), skb_mac_header(skb),
- ETH_ALEN * 2);
- put_unaligned(s->eh.h_proto, (__be16 *) __skb_put(nskb, 2));
- break;
- }
-
- skb_copy_from_linear_data(skb, __skb_put(nskb, skb->len), skb->len);
- kfree_skb(skb);
-
- dev->stats.rx_packets++;
- nskb->ip_summed = CHECKSUM_NONE;
- nskb->protocol = eth_type_trans(nskb, dev);
- netif_rx_ni(nskb);
- return 0;
-
-badframe:
- dev->stats.rx_errors++;
- kfree_skb(skb);
- return 0;
-}
-
-static u8 __bnep_tx_types[] = {
- BNEP_GENERAL,
- BNEP_COMPRESSED_SRC_ONLY,
- BNEP_COMPRESSED_DST_ONLY,
- BNEP_COMPRESSED
-};
-
-static inline int bnep_tx_frame(struct bnep_session *s, struct sk_buff *skb)
-{
- struct ethhdr *eh = (void *) skb->data;
- struct socket *sock = s->sock;
- struct kvec iv[3];
- int len = 0, il = 0;
- u8 type = 0;
-
- BT_DBG("skb %p dev %p type %d", skb, skb->dev, skb->pkt_type);
-
- if (!skb->dev) {
- /* Control frame sent by us */
- goto send;
- }
-
- iv[il++] = (struct kvec) { &type, 1 };
- len++;
-
- if (compress_src && !compare_ether_addr(eh->h_dest, s->eh.h_source))
- type |= 0x01;
-
- if (compress_dst && !compare_ether_addr(eh->h_source, s->eh.h_dest))
- type |= 0x02;
-
- if (type)
- skb_pull(skb, ETH_ALEN * 2);
-
- type = __bnep_tx_types[type];
- switch (type) {
- case BNEP_COMPRESSED_SRC_ONLY:
- iv[il++] = (struct kvec) { eh->h_source, ETH_ALEN };
- len += ETH_ALEN;
- break;
-
- case BNEP_COMPRESSED_DST_ONLY:
- iv[il++] = (struct kvec) { eh->h_dest, ETH_ALEN };
- len += ETH_ALEN;
- break;
- }
-
-send:
- iv[il++] = (struct kvec) { skb->data, skb->len };
- len += skb->len;
-
- /* FIXME: linearize skb */
- {
- len = kernel_sendmsg(sock, &s->msg, iv, il, len);
- }
- kfree_skb(skb);
-
- if (len > 0) {
- s->dev->stats.tx_bytes += len;
- s->dev->stats.tx_packets++;
- return 0;
- }
-
- return len;
-}
-
-static int bnep_session(void *arg)
-{
- struct bnep_session *s = arg;
- struct net_device *dev = s->dev;
- struct sock *sk = s->sock->sk;
- struct sk_buff *skb;
- wait_queue_t wait;
-
- BT_DBG("");
-
- set_user_nice(current, -15);
-
- init_waitqueue_entry(&wait, current);
- add_wait_queue(sk_sleep(sk), &wait);
- while (1) {
- set_current_state(TASK_INTERRUPTIBLE);
-
- if (atomic_read(&s->terminate))
- break;
- /* RX */
- while ((skb = skb_dequeue(&sk->sk_receive_queue))) {
- skb_orphan(skb);
- if (!skb_linearize(skb))
- bnep_rx_frame(s, skb);
- else
- kfree_skb(skb);
- }
-
- if (sk->sk_state != BT_CONNECTED)
- break;
-
- /* TX */
- while ((skb = skb_dequeue(&sk->sk_write_queue)))
- if (bnep_tx_frame(s, skb))
- break;
- netif_wake_queue(dev);
-
- schedule();
- }
- __set_current_state(TASK_RUNNING);
- remove_wait_queue(sk_sleep(sk), &wait);
-
- /* Cleanup session */
- down_write(&bnep_session_sem);
-
- /* Delete network device */
- unregister_netdev(dev);
-
- /* Wakeup user-space polling for socket errors */
- s->sock->sk->sk_err = EUNATCH;
-
- wake_up_interruptible(sk_sleep(s->sock->sk));
-
- /* Release the socket */
- fput(s->sock->file);
-
- __bnep_unlink_session(s);
-
- up_write(&bnep_session_sem);
- free_netdev(dev);
- module_put_and_exit(0);
- return 0;
-}
-
-static struct device *bnep_get_device(struct bnep_session *session)
-{
- bdaddr_t *src = &bt_sk(session->sock->sk)->src;
- bdaddr_t *dst = &bt_sk(session->sock->sk)->dst;
- struct hci_dev *hdev;
- struct hci_conn *conn;
-
- hdev = hci_get_route(dst, src);
- if (!hdev)
- return NULL;
-
- conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, dst);
-
- hci_dev_put(hdev);
-
- return conn ? &conn->dev : NULL;
-}
-
-static struct device_type bnep_type = {
- .name = "bluetooth",
-};
-
-int bnep_add_connection(struct bnep_connadd_req *req, struct socket *sock)
-{
- struct net_device *dev;
- struct bnep_session *s, *ss;
- u8 dst[ETH_ALEN], src[ETH_ALEN];
- int err;
-
- BT_DBG("");
-
- baswap((void *) dst, &bt_sk(sock->sk)->dst);
- baswap((void *) src, &bt_sk(sock->sk)->src);
-
- /* session struct allocated as private part of net_device */
- dev = alloc_netdev(sizeof(struct bnep_session),
- (*req->device) ? req->device : "bnep%d",
- bnep_net_setup);
- if (!dev)
- return -ENOMEM;
-
- down_write(&bnep_session_sem);
-
- ss = __bnep_get_session(dst);
- if (ss && ss->state == BT_CONNECTED) {
- err = -EEXIST;
- goto failed;
- }
-
- s = netdev_priv(dev);
-
- /* This is rx header therefore addresses are swapped.
- * ie. eh.h_dest is our local address. */
- memcpy(s->eh.h_dest, &src, ETH_ALEN);
- memcpy(s->eh.h_source, &dst, ETH_ALEN);
- memcpy(dev->dev_addr, s->eh.h_dest, ETH_ALEN);
-
- s->dev = dev;
- s->sock = sock;
- s->role = req->role;
- s->state = BT_CONNECTED;
-
- s->msg.msg_flags = MSG_NOSIGNAL;
-
-#ifdef CONFIG_BT_BNEP_MC_FILTER
- /* Set default mc filter */
- set_bit(bnep_mc_hash(dev->broadcast), (ulong *) &s->mc_filter);
-#endif
-
-#ifdef CONFIG_BT_BNEP_PROTO_FILTER
- /* Set default protocol filter */
- bnep_set_default_proto_filter(s);
-#endif
-
- SET_NETDEV_DEV(dev, bnep_get_device(s));
- SET_NETDEV_DEVTYPE(dev, &bnep_type);
-
- err = register_netdev(dev);
- if (err)
- goto failed;
-
- __bnep_link_session(s);
-
- __module_get(THIS_MODULE);
- s->task = kthread_run(bnep_session, s, "kbnepd %s", dev->name);
- if (IS_ERR(s->task)) {
- /* Session thread start failed, gotta cleanup. */
- module_put(THIS_MODULE);
- unregister_netdev(dev);
- __bnep_unlink_session(s);
- err = PTR_ERR(s->task);
- goto failed;
- }
-
- up_write(&bnep_session_sem);
- strcpy(req->device, dev->name);
- return 0;
-
-failed:
- up_write(&bnep_session_sem);
- free_netdev(dev);
- return err;
-}
-
-int bnep_del_connection(struct bnep_conndel_req *req)
-{
- struct bnep_session *s;
- int err = 0;
-
- BT_DBG("");
-
- down_read(&bnep_session_sem);
-
- s = __bnep_get_session(req->dst);
- if (s) {
- atomic_inc(&s->terminate);
- wake_up_process(s->task);
- } else
- err = -ENOENT;
-
- up_read(&bnep_session_sem);
- return err;
-}
-
-static void __bnep_copy_ci(struct bnep_conninfo *ci, struct bnep_session *s)
-{
- memset(ci, 0, sizeof(*ci));
- memcpy(ci->dst, s->eh.h_source, ETH_ALEN);
- strcpy(ci->device, s->dev->name);
- ci->flags = s->flags;
- ci->state = s->state;
- ci->role = s->role;
-}
-
-int bnep_get_connlist(struct bnep_connlist_req *req)
-{
- struct bnep_session *s;
- int err = 0, n = 0;
-
- down_read(&bnep_session_sem);
-
- list_for_each_entry(s, &bnep_session_list, list) {
- struct bnep_conninfo ci;
-
- __bnep_copy_ci(&ci, s);
-
- if (copy_to_user(req->ci, &ci, sizeof(ci))) {
- err = -EFAULT;
- break;
- }
-
- if (++n >= req->cnum)
- break;
-
- req->ci++;
- }
- req->cnum = n;
-
- up_read(&bnep_session_sem);
- return err;
-}
-
-int bnep_get_conninfo(struct bnep_conninfo *ci)
-{
- struct bnep_session *s;
- int err = 0;
-
- down_read(&bnep_session_sem);
-
- s = __bnep_get_session(ci->dst);
- if (s)
- __bnep_copy_ci(ci, s);
- else
- err = -ENOENT;
-
- up_read(&bnep_session_sem);
- return err;
-}
-
-static int __init bnep_init(void)
-{
- char flt[50] = "";
-
-#ifdef CONFIG_BT_BNEP_PROTO_FILTER
- strcat(flt, "protocol ");
-#endif
-
-#ifdef CONFIG_BT_BNEP_MC_FILTER
- strcat(flt, "multicast");
-#endif
-
- BT_INFO("BNEP (Ethernet Emulation) ver %s", VERSION);
- if (flt[0])
- BT_INFO("BNEP filters: %s", flt);
-
- bnep_sock_init();
- return 0;
-}
-
-static void __exit bnep_exit(void)
-{
- bnep_sock_cleanup();
-}
-
-module_init(bnep_init);
-module_exit(bnep_exit);
-
-module_param(compress_src, bool, 0644);
-MODULE_PARM_DESC(compress_src, "Compress sources headers");
-
-module_param(compress_dst, bool, 0644);
-MODULE_PARM_DESC(compress_dst, "Compress destination headers");
-
-MODULE_AUTHOR("Marcel Holtmann <marcel@holtmann.org>");
-MODULE_DESCRIPTION("Bluetooth BNEP ver " VERSION);
-MODULE_VERSION(VERSION);
-MODULE_LICENSE("GPL");
-MODULE_ALIAS("bt-proto-4");
diff --git a/net/bluetooth_tizen/bnep/netdev.c b/net/bluetooth_tizen/bnep/netdev.c
deleted file mode 100644
index bc40864..0000000
--- a/net/bluetooth_tizen/bnep/netdev.c
+++ /dev/null
@@ -1,238 +0,0 @@
-/*
- BNEP implementation for Linux Bluetooth stack (BlueZ).
- Copyright (C) 2001-2002 Inventel Systemes
- Written 2001-2002 by
- Clément Moreau <clement.moreau@inventel.fr>
- David Libault <david.libault@inventel.fr>
-
- Copyright (C) 2002 Maxim Krasnyansky <maxk@qualcomm.com>
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License version 2 as
- published by the Free Software Foundation;
-
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
- OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS.
- IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY
- CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES
- WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
- OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
-
- ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS,
- COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS
- SOFTWARE IS DISCLAIMED.
-*/
-
-#include <linux/module.h>
-#include <linux/slab.h>
-
-#include <linux/socket.h>
-#include <linux/netdevice.h>
-#include <linux/etherdevice.h>
-#include <linux/skbuff.h>
-#include <linux/wait.h>
-
-#include <asm/unaligned.h>
-
-#include <net/bluetooth/bluetooth.h>
-#include <net/bluetooth/hci_core.h>
-#include <net/bluetooth/l2cap.h>
-
-#include "bnep.h"
-
-#define BNEP_TX_QUEUE_LEN 20
-
-static int bnep_net_open(struct net_device *dev)
-{
- netif_start_queue(dev);
- return 0;
-}
-
-static int bnep_net_close(struct net_device *dev)
-{
- netif_stop_queue(dev);
- return 0;
-}
-
-static void bnep_net_set_mc_list(struct net_device *dev)
-{
-#ifdef CONFIG_BT_BNEP_MC_FILTER
- struct bnep_session *s = netdev_priv(dev);
- struct sock *sk = s->sock->sk;
- struct bnep_set_filter_req *r;
- struct sk_buff *skb;
- int size;
-
- BT_DBG("%s mc_count %d", dev->name, netdev_mc_count(dev));
-
- size = sizeof(*r) + (BNEP_MAX_MULTICAST_FILTERS + 1) * ETH_ALEN * 2;
- skb = alloc_skb(size, GFP_ATOMIC);
- if (!skb) {
- BT_ERR("%s Multicast list allocation failed", dev->name);
- return;
- }
-
- r = (void *) skb->data;
- __skb_put(skb, sizeof(*r));
-
- r->type = BNEP_CONTROL;
- r->ctrl = BNEP_FILTER_MULTI_ADDR_SET;
-
- if (dev->flags & (IFF_PROMISC | IFF_ALLMULTI)) {
- u8 start[ETH_ALEN] = { 0x01 };
-
- /* Request all addresses */
- memcpy(__skb_put(skb, ETH_ALEN), start, ETH_ALEN);
- memcpy(__skb_put(skb, ETH_ALEN), dev->broadcast, ETH_ALEN);
- r->len = htons(ETH_ALEN * 2);
- } else {
- struct netdev_hw_addr *ha;
- int i, len = skb->len;
-
- if (dev->flags & IFF_BROADCAST) {
- memcpy(__skb_put(skb, ETH_ALEN), dev->broadcast, ETH_ALEN);
- memcpy(__skb_put(skb, ETH_ALEN), dev->broadcast, ETH_ALEN);
- }
-
- /* FIXME: We should group addresses here. */
-
- i = 0;
- netdev_for_each_mc_addr(ha, dev) {
- if (i == BNEP_MAX_MULTICAST_FILTERS)
- break;
- memcpy(__skb_put(skb, ETH_ALEN), ha->addr, ETH_ALEN);
- memcpy(__skb_put(skb, ETH_ALEN), ha->addr, ETH_ALEN);
-
- i++;
- }
- r->len = htons(skb->len - len);
- }
-
- skb_queue_tail(&sk->sk_write_queue, skb);
- wake_up_interruptible(sk_sleep(sk));
-#endif
-}
-
-static int bnep_net_set_mac_addr(struct net_device *dev, void *arg)
-{
- BT_DBG("%s", dev->name);
- return 0;
-}
-
-static void bnep_net_timeout(struct net_device *dev)
-{
- BT_DBG("net_timeout");
- netif_wake_queue(dev);
-}
-
-#ifdef CONFIG_BT_BNEP_MC_FILTER
-static inline int bnep_net_mc_filter(struct sk_buff *skb, struct bnep_session *s)
-{
- struct ethhdr *eh = (void *) skb->data;
-
- if ((eh->h_dest[0] & 1) && !test_bit(bnep_mc_hash(eh->h_dest), (ulong *) &s->mc_filter))
- return 1;
- return 0;
-}
-#endif
-
-#ifdef CONFIG_BT_BNEP_PROTO_FILTER
-/* Determine ether protocol. Based on eth_type_trans. */
-static inline u16 bnep_net_eth_proto(struct sk_buff *skb)
-{
- struct ethhdr *eh = (void *) skb->data;
- u16 proto = ntohs(eh->h_proto);
-
- if (proto >= 1536)
- return proto;
-
- if (get_unaligned((__be16 *) skb->data) == htons(0xFFFF))
- return ETH_P_802_3;
-
- return ETH_P_802_2;
-}
-
-static inline int bnep_net_proto_filter(struct sk_buff *skb, struct bnep_session *s)
-{
- u16 proto = bnep_net_eth_proto(skb);
- struct bnep_proto_filter *f = s->proto_filter;
- int i;
-
- for (i = 0; i < BNEP_MAX_PROTO_FILTERS && f[i].end; i++) {
- if (proto >= f[i].start && proto <= f[i].end)
- return 0;
- }
-
- BT_DBG("BNEP: filtered skb %p, proto 0x%.4x", skb, proto);
- return 1;
-}
-#endif
-
-static netdev_tx_t bnep_net_xmit(struct sk_buff *skb,
- struct net_device *dev)
-{
- struct bnep_session *s = netdev_priv(dev);
- struct sock *sk = s->sock->sk;
-
- BT_DBG("skb %p, dev %p", skb, dev);
-
-#ifdef CONFIG_BT_BNEP_MC_FILTER
- if (bnep_net_mc_filter(skb, s)) {
- kfree_skb(skb);
- return NETDEV_TX_OK;
- }
-#endif
-
-#ifdef CONFIG_BT_BNEP_PROTO_FILTER
- if (bnep_net_proto_filter(skb, s)) {
- kfree_skb(skb);
- return NETDEV_TX_OK;
- }
-#endif
-
- /*
- * We cannot send L2CAP packets from here as we are potentially in a bh.
- * So we have to queue them and wake up session thread which is sleeping
- * on the sk_sleep(sk).
- */
- dev->trans_start = jiffies;
- skb_queue_tail(&sk->sk_write_queue, skb);
- wake_up_interruptible(sk_sleep(sk));
-
- if (skb_queue_len(&sk->sk_write_queue) >= BNEP_TX_QUEUE_LEN) {
- BT_DBG("tx queue is full");
-
- /* Stop queuing.
- * Session thread will do netif_wake_queue() */
- netif_stop_queue(dev);
- }
-
- return NETDEV_TX_OK;
-}
-
-static const struct net_device_ops bnep_netdev_ops = {
- .ndo_open = bnep_net_open,
- .ndo_stop = bnep_net_close,
- .ndo_start_xmit = bnep_net_xmit,
- .ndo_validate_addr = eth_validate_addr,
- .ndo_set_rx_mode = bnep_net_set_mc_list,
- .ndo_set_mac_address = bnep_net_set_mac_addr,
- .ndo_tx_timeout = bnep_net_timeout,
- .ndo_change_mtu = eth_change_mtu,
-
-};
-
-void bnep_net_setup(struct net_device *dev)
-{
-
- memset(dev->broadcast, 0xff, ETH_ALEN);
- dev->addr_len = ETH_ALEN;
-
- ether_setup(dev);
- dev->priv_flags &= ~IFF_TX_SKB_SHARING;
- dev->netdev_ops = &bnep_netdev_ops;
-
- dev->watchdog_timeo = HZ * 2;
-}
diff --git a/net/bluetooth_tizen/bnep/sock.c b/net/bluetooth_tizen/bnep/sock.c
deleted file mode 100644
index 9f9c8dc..0000000
--- a/net/bluetooth_tizen/bnep/sock.c
+++ /dev/null
@@ -1,259 +0,0 @@
-/*
- BNEP implementation for Linux Bluetooth stack (BlueZ).
- Copyright (C) 2001-2002 Inventel Systemes
- Written 2001-2002 by
- David Libault <david.libault@inventel.fr>
-
- Copyright (C) 2002 Maxim Krasnyansky <maxk@qualcomm.com>
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License version 2 as
- published by the Free Software Foundation;
-
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
- OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS.
- IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY
- CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES
- WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
- OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
-
- ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS,
- COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS
- SOFTWARE IS DISCLAIMED.
-*/
-
-#include <linux/module.h>
-
-#include <linux/types.h>
-#include <linux/capability.h>
-#include <linux/errno.h>
-#include <linux/kernel.h>
-#include <linux/poll.h>
-#include <linux/fcntl.h>
-#include <linux/skbuff.h>
-#include <linux/socket.h>
-#include <linux/ioctl.h>
-#include <linux/file.h>
-#include <linux/init.h>
-#include <linux/compat.h>
-#include <linux/gfp.h>
-#include <linux/uaccess.h>
-#include <net/sock.h>
-
-#include <asm/system.h>
-
-#include "bnep.h"
-
-static int bnep_sock_release(struct socket *sock)
-{
- struct sock *sk = sock->sk;
-
- BT_DBG("sock %p sk %p", sock, sk);
-
- if (!sk)
- return 0;
-
- sock_orphan(sk);
- sock_put(sk);
- return 0;
-}
-
-static int bnep_sock_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
-{
- struct bnep_connlist_req cl;
- struct bnep_connadd_req ca;
- struct bnep_conndel_req cd;
- struct bnep_conninfo ci;
- struct socket *nsock;
- void __user *argp = (void __user *)arg;
- int err;
-
- BT_DBG("cmd %x arg %lx", cmd, arg);
-
- switch (cmd) {
- case BNEPCONNADD:
- if (!capable(CAP_NET_ADMIN))
- return -EACCES;
-
- if (copy_from_user(&ca, argp, sizeof(ca)))
- return -EFAULT;
-
- nsock = sockfd_lookup(ca.sock, &err);
- if (!nsock)
- return err;
-
- if (nsock->sk->sk_state != BT_CONNECTED) {
- sockfd_put(nsock);
- return -EBADFD;
- }
- ca.device[sizeof(ca.device)-1] = 0;
-
- err = bnep_add_connection(&ca, nsock);
- if (!err) {
- if (copy_to_user(argp, &ca, sizeof(ca)))
- err = -EFAULT;
- } else
- sockfd_put(nsock);
-
- return err;
-
- case BNEPCONNDEL:
- if (!capable(CAP_NET_ADMIN))
- return -EACCES;
-
- if (copy_from_user(&cd, argp, sizeof(cd)))
- return -EFAULT;
-
- return bnep_del_connection(&cd);
-
- case BNEPGETCONNLIST:
- if (copy_from_user(&cl, argp, sizeof(cl)))
- return -EFAULT;
-
- if (cl.cnum <= 0)
- return -EINVAL;
-
- err = bnep_get_connlist(&cl);
- if (!err && copy_to_user(argp, &cl, sizeof(cl)))
- return -EFAULT;
-
- return err;
-
- case BNEPGETCONNINFO:
- if (copy_from_user(&ci, argp, sizeof(ci)))
- return -EFAULT;
-
- err = bnep_get_conninfo(&ci);
- if (!err && copy_to_user(argp, &ci, sizeof(ci)))
- return -EFAULT;
-
- return err;
-
- default:
- return -EINVAL;
- }
-
- return 0;
-}
-
-#ifdef CONFIG_COMPAT
-static int bnep_sock_compat_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
-{
- if (cmd == BNEPGETCONNLIST) {
- struct bnep_connlist_req cl;
- u32 uci;
- int err;
-
- if (get_user(cl.cnum, (u32 __user *) arg) ||
- get_user(uci, (u32 __user *) (arg + 4)))
- return -EFAULT;
-
- cl.ci = compat_ptr(uci);
-
- if (cl.cnum <= 0)
- return -EINVAL;
-
- err = bnep_get_connlist(&cl);
-
- if (!err && put_user(cl.cnum, (u32 __user *) arg))
- err = -EFAULT;
-
- return err;
- }
-
- return bnep_sock_ioctl(sock, cmd, arg);
-}
-#endif
-
-static const struct proto_ops bnep_sock_ops = {
- .family = PF_BLUETOOTH,
- .owner = THIS_MODULE,
- .release = bnep_sock_release,
- .ioctl = bnep_sock_ioctl,
-#ifdef CONFIG_COMPAT
- .compat_ioctl = bnep_sock_compat_ioctl,
-#endif
- .bind = sock_no_bind,
- .getname = sock_no_getname,
- .sendmsg = sock_no_sendmsg,
- .recvmsg = sock_no_recvmsg,
- .poll = sock_no_poll,
- .listen = sock_no_listen,
- .shutdown = sock_no_shutdown,
- .setsockopt = sock_no_setsockopt,
- .getsockopt = sock_no_getsockopt,
- .connect = sock_no_connect,
- .socketpair = sock_no_socketpair,
- .accept = sock_no_accept,
- .mmap = sock_no_mmap
-};
-
-static struct proto bnep_proto = {
- .name = "BNEP",
- .owner = THIS_MODULE,
- .obj_size = sizeof(struct bt_sock)
-};
-
-static int bnep_sock_create(struct net *net, struct socket *sock, int protocol,
- int kern)
-{
- struct sock *sk;
-
- BT_DBG("sock %p", sock);
-
- if (sock->type != SOCK_RAW)
- return -ESOCKTNOSUPPORT;
-
- sk = sk_alloc(net, PF_BLUETOOTH, GFP_ATOMIC, &bnep_proto);
- if (!sk)
- return -ENOMEM;
-
- sock_init_data(sock, sk);
-
- sock->ops = &bnep_sock_ops;
-
- sock->state = SS_UNCONNECTED;
-
- sock_reset_flag(sk, SOCK_ZAPPED);
-
- sk->sk_protocol = protocol;
- sk->sk_state = BT_OPEN;
-
- return 0;
-}
-
-static const struct net_proto_family bnep_sock_family_ops = {
- .family = PF_BLUETOOTH,
- .owner = THIS_MODULE,
- .create = bnep_sock_create
-};
-
-int __init bnep_sock_init(void)
-{
- int err;
-
- err = proto_register(&bnep_proto, 0);
- if (err < 0)
- return err;
-
- err = bt_sock_register(BTPROTO_BNEP, &bnep_sock_family_ops);
- if (err < 0)
- goto error;
-
- return 0;
-
-error:
- BT_ERR("Can't register BNEP socket");
- proto_unregister(&bnep_proto);
- return err;
-}
-
-void __exit bnep_sock_cleanup(void)
-{
- if (bt_sock_unregister(BTPROTO_BNEP) < 0)
- BT_ERR("Can't unregister BNEP socket");
-
- proto_unregister(&bnep_proto);
-}
diff --git a/net/bluetooth_tizen/cmtp/Kconfig b/net/bluetooth_tizen/cmtp/Kconfig
deleted file mode 100644
index 94cbf42..0000000
--- a/net/bluetooth_tizen/cmtp/Kconfig
+++ /dev/null
@@ -1,11 +0,0 @@
-config BT_CMTP
- tristate "CMTP protocol support"
- depends on BT && ISDN_CAPI
- help
- CMTP (CAPI Message Transport Protocol) is a transport layer
- for CAPI messages. CMTP is required for the Bluetooth Common
- ISDN Access Profile.
-
- Say Y here to compile CMTP support into the kernel or say M to
- compile it as module (cmtp).
-
diff --git a/net/bluetooth_tizen/cmtp/Makefile b/net/bluetooth_tizen/cmtp/Makefile
deleted file mode 100644
index 890a9a5..0000000
--- a/net/bluetooth_tizen/cmtp/Makefile
+++ /dev/null
@@ -1,7 +0,0 @@
-#
-# Makefile for the Linux Bluetooth CMTP layer
-#
-
-obj-$(CONFIG_BT_CMTP) += cmtp.o
-
-cmtp-objs := core.o sock.o capi.o
diff --git a/net/bluetooth_tizen/cmtp/capi.c b/net/bluetooth_tizen/cmtp/capi.c
deleted file mode 100644
index 50f0d13..0000000
--- a/net/bluetooth_tizen/cmtp/capi.c
+++ /dev/null
@@ -1,624 +0,0 @@
-/*
- CMTP implementation for Linux Bluetooth stack (BlueZ).
- Copyright (C) 2002-2003 Marcel Holtmann <marcel@holtmann.org>
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License version 2 as
- published by the Free Software Foundation;
-
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
- OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS.
- IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY
- CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES
- WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
- OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
-
- ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS,
- COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS
- SOFTWARE IS DISCLAIMED.
-*/
-
-#include <linux/module.h>
-#include <linux/proc_fs.h>
-#include <linux/seq_file.h>
-#include <linux/types.h>
-#include <linux/errno.h>
-#include <linux/kernel.h>
-#include <linux/sched.h>
-#include <linux/slab.h>
-#include <linux/poll.h>
-#include <linux/fcntl.h>
-#include <linux/skbuff.h>
-#include <linux/socket.h>
-#include <linux/ioctl.h>
-#include <linux/file.h>
-#include <linux/wait.h>
-#include <linux/kthread.h>
-#include <net/sock.h>
-
-#include <linux/isdn/capilli.h>
-#include <linux/isdn/capicmd.h>
-#include <linux/isdn/capiutil.h>
-
-#include "cmtp.h"
-
-#define CAPI_INTEROPERABILITY 0x20
-
-#define CAPI_INTEROPERABILITY_REQ CAPICMD(CAPI_INTEROPERABILITY, CAPI_REQ)
-#define CAPI_INTEROPERABILITY_CONF CAPICMD(CAPI_INTEROPERABILITY, CAPI_CONF)
-#define CAPI_INTEROPERABILITY_IND CAPICMD(CAPI_INTEROPERABILITY, CAPI_IND)
-#define CAPI_INTEROPERABILITY_RESP CAPICMD(CAPI_INTEROPERABILITY, CAPI_RESP)
-
-#define CAPI_INTEROPERABILITY_REQ_LEN (CAPI_MSG_BASELEN + 2)
-#define CAPI_INTEROPERABILITY_CONF_LEN (CAPI_MSG_BASELEN + 4)
-#define CAPI_INTEROPERABILITY_IND_LEN (CAPI_MSG_BASELEN + 2)
-#define CAPI_INTEROPERABILITY_RESP_LEN (CAPI_MSG_BASELEN + 2)
-
-#define CAPI_FUNCTION_REGISTER 0
-#define CAPI_FUNCTION_RELEASE 1
-#define CAPI_FUNCTION_GET_PROFILE 2
-#define CAPI_FUNCTION_GET_MANUFACTURER 3
-#define CAPI_FUNCTION_GET_VERSION 4
-#define CAPI_FUNCTION_GET_SERIAL_NUMBER 5
-#define CAPI_FUNCTION_MANUFACTURER 6
-#define CAPI_FUNCTION_LOOPBACK 7
-
-
-#define CMTP_MSGNUM 1
-#define CMTP_APPLID 2
-#define CMTP_MAPPING 3
-
-static struct cmtp_application *cmtp_application_add(struct cmtp_session *session, __u16 appl)
-{
- struct cmtp_application *app = kzalloc(sizeof(*app), GFP_KERNEL);
-
- BT_DBG("session %p application %p appl %d", session, app, appl);
-
- if (!app)
- return NULL;
-
- app->state = BT_OPEN;
- app->appl = appl;
-
- list_add_tail(&app->list, &session->applications);
-
- return app;
-}
-
-static void cmtp_application_del(struct cmtp_session *session, struct cmtp_application *app)
-{
- BT_DBG("session %p application %p", session, app);
-
- if (app) {
- list_del(&app->list);
- kfree(app);
- }
-}
-
-static struct cmtp_application *cmtp_application_get(struct cmtp_session *session, int pattern, __u16 value)
-{
- struct cmtp_application *app;
- struct list_head *p, *n;
-
- list_for_each_safe(p, n, &session->applications) {
- app = list_entry(p, struct cmtp_application, list);
- switch (pattern) {
- case CMTP_MSGNUM:
- if (app->msgnum == value)
- return app;
- break;
- case CMTP_APPLID:
- if (app->appl == value)
- return app;
- break;
- case CMTP_MAPPING:
- if (app->mapping == value)
- return app;
- break;
- }
- }
-
- return NULL;
-}
-
-static int cmtp_msgnum_get(struct cmtp_session *session)
-{
- session->msgnum++;
-
- if ((session->msgnum & 0xff) > 200)
- session->msgnum = CMTP_INITIAL_MSGNUM + 1;
-
- return session->msgnum;
-}
-
-static void cmtp_send_capimsg(struct cmtp_session *session, struct sk_buff *skb)
-{
- struct cmtp_scb *scb = (void *) skb->cb;
-
- BT_DBG("session %p skb %p len %d", session, skb, skb->len);
-
- scb->id = -1;
- scb->data = (CAPIMSG_COMMAND(skb->data) == CAPI_DATA_B3);
-
- skb_queue_tail(&session->transmit, skb);
-
- wake_up_interruptible(sk_sleep(session->sock->sk));
-}
-
-static void cmtp_send_interopmsg(struct cmtp_session *session,
- __u8 subcmd, __u16 appl, __u16 msgnum,
- __u16 function, unsigned char *buf, int len)
-{
- struct sk_buff *skb;
- unsigned char *s;
-
- BT_DBG("session %p subcmd 0x%02x appl %d msgnum %d", session, subcmd, appl, msgnum);
-
- skb = alloc_skb(CAPI_MSG_BASELEN + 6 + len, GFP_ATOMIC);
- if (!skb) {
- BT_ERR("Can't allocate memory for interoperability packet");
- return;
- }
-
- s = skb_put(skb, CAPI_MSG_BASELEN + 6 + len);
-
- capimsg_setu16(s, 0, CAPI_MSG_BASELEN + 6 + len);
- capimsg_setu16(s, 2, appl);
- capimsg_setu8 (s, 4, CAPI_INTEROPERABILITY);
- capimsg_setu8 (s, 5, subcmd);
- capimsg_setu16(s, 6, msgnum);
-
- /* Interoperability selector (Bluetooth Device Management) */
- capimsg_setu16(s, 8, 0x0001);
-
- capimsg_setu8 (s, 10, 3 + len);
- capimsg_setu16(s, 11, function);
- capimsg_setu8 (s, 13, len);
-
- if (len > 0)
- memcpy(s + 14, buf, len);
-
- cmtp_send_capimsg(session, skb);
-}
-
-static void cmtp_recv_interopmsg(struct cmtp_session *session, struct sk_buff *skb)
-{
- struct capi_ctr *ctrl = &session->ctrl;
- struct cmtp_application *application;
- __u16 appl, msgnum, func, info;
- __u32 controller;
-
- BT_DBG("session %p skb %p len %d", session, skb, skb->len);
-
- switch (CAPIMSG_SUBCOMMAND(skb->data)) {
- case CAPI_CONF:
- if (skb->len < CAPI_MSG_BASELEN + 10)
- break;
-
- func = CAPIMSG_U16(skb->data, CAPI_MSG_BASELEN + 5);
- info = CAPIMSG_U16(skb->data, CAPI_MSG_BASELEN + 8);
-
- switch (func) {
- case CAPI_FUNCTION_REGISTER:
- msgnum = CAPIMSG_MSGID(skb->data);
-
- application = cmtp_application_get(session, CMTP_MSGNUM, msgnum);
- if (application) {
- application->state = BT_CONNECTED;
- application->msgnum = 0;
- application->mapping = CAPIMSG_APPID(skb->data);
- wake_up_interruptible(&session->wait);
- }
-
- break;
-
- case CAPI_FUNCTION_RELEASE:
- appl = CAPIMSG_APPID(skb->data);
-
- application = cmtp_application_get(session, CMTP_MAPPING, appl);
- if (application) {
- application->state = BT_CLOSED;
- application->msgnum = 0;
- wake_up_interruptible(&session->wait);
- }
-
- break;
-
- case CAPI_FUNCTION_GET_PROFILE:
- if (skb->len < CAPI_MSG_BASELEN + 11 + sizeof(capi_profile))
- break;
-
- controller = CAPIMSG_U16(skb->data, CAPI_MSG_BASELEN + 11);
- msgnum = CAPIMSG_MSGID(skb->data);
-
- if (!info && (msgnum == CMTP_INITIAL_MSGNUM)) {
- session->ncontroller = controller;
- wake_up_interruptible(&session->wait);
- break;
- }
-
- if (!info && ctrl) {
- memcpy(&ctrl->profile,
- skb->data + CAPI_MSG_BASELEN + 11,
- sizeof(capi_profile));
- session->state = BT_CONNECTED;
- capi_ctr_ready(ctrl);
- }
-
- break;
-
- case CAPI_FUNCTION_GET_MANUFACTURER:
- if (skb->len < CAPI_MSG_BASELEN + 15)
- break;
-
- controller = CAPIMSG_U32(skb->data, CAPI_MSG_BASELEN + 10);
-
- if (!info && ctrl) {
- int len = min_t(uint, CAPI_MANUFACTURER_LEN,
- skb->data[CAPI_MSG_BASELEN + 14]);
-
- memset(ctrl->manu, 0, CAPI_MANUFACTURER_LEN);
- strncpy(ctrl->manu,
- skb->data + CAPI_MSG_BASELEN + 15, len);
- }
-
- break;
-
- case CAPI_FUNCTION_GET_VERSION:
- if (skb->len < CAPI_MSG_BASELEN + 32)
- break;
-
- controller = CAPIMSG_U32(skb->data, CAPI_MSG_BASELEN + 12);
-
- if (!info && ctrl) {
- ctrl->version.majorversion = CAPIMSG_U32(skb->data, CAPI_MSG_BASELEN + 16);
- ctrl->version.minorversion = CAPIMSG_U32(skb->data, CAPI_MSG_BASELEN + 20);
- ctrl->version.majormanuversion = CAPIMSG_U32(skb->data, CAPI_MSG_BASELEN + 24);
- ctrl->version.minormanuversion = CAPIMSG_U32(skb->data, CAPI_MSG_BASELEN + 28);
- }
-
- break;
-
- case CAPI_FUNCTION_GET_SERIAL_NUMBER:
- if (skb->len < CAPI_MSG_BASELEN + 17)
- break;
-
- controller = CAPIMSG_U32(skb->data, CAPI_MSG_BASELEN + 12);
-
- if (!info && ctrl) {
- int len = min_t(uint, CAPI_SERIAL_LEN,
- skb->data[CAPI_MSG_BASELEN + 16]);
-
- memset(ctrl->serial, 0, CAPI_SERIAL_LEN);
- strncpy(ctrl->serial,
- skb->data + CAPI_MSG_BASELEN + 17, len);
- }
-
- break;
- }
-
- break;
-
- case CAPI_IND:
- if (skb->len < CAPI_MSG_BASELEN + 6)
- break;
-
- func = CAPIMSG_U16(skb->data, CAPI_MSG_BASELEN + 3);
-
- if (func == CAPI_FUNCTION_LOOPBACK) {
- int len = min_t(uint, skb->len - CAPI_MSG_BASELEN - 6,
- skb->data[CAPI_MSG_BASELEN + 5]);
- appl = CAPIMSG_APPID(skb->data);
- msgnum = CAPIMSG_MSGID(skb->data);
- cmtp_send_interopmsg(session, CAPI_RESP, appl, msgnum, func,
- skb->data + CAPI_MSG_BASELEN + 6, len);
- }
-
- break;
- }
-
- kfree_skb(skb);
-}
-
-void cmtp_recv_capimsg(struct cmtp_session *session, struct sk_buff *skb)
-{
- struct capi_ctr *ctrl = &session->ctrl;
- struct cmtp_application *application;
- __u16 appl;
- __u32 contr;
-
- BT_DBG("session %p skb %p len %d", session, skb, skb->len);
-
- if (skb->len < CAPI_MSG_BASELEN)
- return;
-
- if (CAPIMSG_COMMAND(skb->data) == CAPI_INTEROPERABILITY) {
- cmtp_recv_interopmsg(session, skb);
- return;
- }
-
- if (session->flags & (1 << CMTP_LOOPBACK)) {
- kfree_skb(skb);
- return;
- }
-
- appl = CAPIMSG_APPID(skb->data);
- contr = CAPIMSG_CONTROL(skb->data);
-
- application = cmtp_application_get(session, CMTP_MAPPING, appl);
- if (application) {
- appl = application->appl;
- CAPIMSG_SETAPPID(skb->data, appl);
- } else {
- BT_ERR("Can't find application with id %d", appl);
- kfree_skb(skb);
- return;
- }
-
- if ((contr & 0x7f) == 0x01) {
- contr = (contr & 0xffffff80) | session->num;
- CAPIMSG_SETCONTROL(skb->data, contr);
- }
-
- if (!ctrl) {
- BT_ERR("Can't find controller %d for message", session->num);
- kfree_skb(skb);
- return;
- }
-
- capi_ctr_handle_message(ctrl, appl, skb);
-}
-
-static int cmtp_load_firmware(struct capi_ctr *ctrl, capiloaddata *data)
-{
- BT_DBG("ctrl %p data %p", ctrl, data);
-
- return 0;
-}
-
-static void cmtp_reset_ctr(struct capi_ctr *ctrl)
-{
- struct cmtp_session *session = ctrl->driverdata;
-
- BT_DBG("ctrl %p", ctrl);
-
- capi_ctr_down(ctrl);
-
- atomic_inc(&session->terminate);
- wake_up_process(session->task);
-}
-
-static void cmtp_register_appl(struct capi_ctr *ctrl, __u16 appl, capi_register_params *rp)
-{
- DECLARE_WAITQUEUE(wait, current);
- struct cmtp_session *session = ctrl->driverdata;
- struct cmtp_application *application;
- unsigned long timeo = CMTP_INTEROP_TIMEOUT;
- unsigned char buf[8];
- int err = 0, nconn, want = rp->level3cnt;
-
- BT_DBG("ctrl %p appl %d level3cnt %d datablkcnt %d datablklen %d",
- ctrl, appl, rp->level3cnt, rp->datablkcnt, rp->datablklen);
-
- application = cmtp_application_add(session, appl);
- if (!application) {
- BT_ERR("Can't allocate memory for new application");
- return;
- }
-
- if (want < 0)
- nconn = ctrl->profile.nbchannel * -want;
- else
- nconn = want;
-
- if (nconn == 0)
- nconn = ctrl->profile.nbchannel;
-
- capimsg_setu16(buf, 0, nconn);
- capimsg_setu16(buf, 2, rp->datablkcnt);
- capimsg_setu16(buf, 4, rp->datablklen);
-
- application->state = BT_CONFIG;
- application->msgnum = cmtp_msgnum_get(session);
-
- cmtp_send_interopmsg(session, CAPI_REQ, 0x0000, application->msgnum,
- CAPI_FUNCTION_REGISTER, buf, 6);
-
- add_wait_queue(&session->wait, &wait);
- while (1) {
- set_current_state(TASK_INTERRUPTIBLE);
-
- if (!timeo) {
- err = -EAGAIN;
- break;
- }
-
- if (application->state == BT_CLOSED) {
- err = -application->err;
- break;
- }
-
- if (application->state == BT_CONNECTED)
- break;
-
- if (signal_pending(current)) {
- err = -EINTR;
- break;
- }
-
- timeo = schedule_timeout(timeo);
- }
- set_current_state(TASK_RUNNING);
- remove_wait_queue(&session->wait, &wait);
-
- if (err) {
- cmtp_application_del(session, application);
- return;
- }
-}
-
-static void cmtp_release_appl(struct capi_ctr *ctrl, __u16 appl)
-{
- struct cmtp_session *session = ctrl->driverdata;
- struct cmtp_application *application;
-
- BT_DBG("ctrl %p appl %d", ctrl, appl);
-
- application = cmtp_application_get(session, CMTP_APPLID, appl);
- if (!application) {
- BT_ERR("Can't find application");
- return;
- }
-
- application->msgnum = cmtp_msgnum_get(session);
-
- cmtp_send_interopmsg(session, CAPI_REQ, application->mapping, application->msgnum,
- CAPI_FUNCTION_RELEASE, NULL, 0);
-
- wait_event_interruptible_timeout(session->wait,
- (application->state == BT_CLOSED), CMTP_INTEROP_TIMEOUT);
-
- cmtp_application_del(session, application);
-}
-
-static u16 cmtp_send_message(struct capi_ctr *ctrl, struct sk_buff *skb)
-{
- struct cmtp_session *session = ctrl->driverdata;
- struct cmtp_application *application;
- __u16 appl;
- __u32 contr;
-
- BT_DBG("ctrl %p skb %p", ctrl, skb);
-
- appl = CAPIMSG_APPID(skb->data);
- contr = CAPIMSG_CONTROL(skb->data);
-
- application = cmtp_application_get(session, CMTP_APPLID, appl);
- if ((!application) || (application->state != BT_CONNECTED)) {
- BT_ERR("Can't find application with id %d", appl);
- return CAPI_ILLAPPNR;
- }
-
- CAPIMSG_SETAPPID(skb->data, application->mapping);
-
- if ((contr & 0x7f) == session->num) {
- contr = (contr & 0xffffff80) | 0x01;
- CAPIMSG_SETCONTROL(skb->data, contr);
- }
-
- cmtp_send_capimsg(session, skb);
-
- return CAPI_NOERROR;
-}
-
-static char *cmtp_procinfo(struct capi_ctr *ctrl)
-{
- return "CAPI Message Transport Protocol";
-}
-
-static int cmtp_proc_show(struct seq_file *m, void *v)
-{
- struct capi_ctr *ctrl = m->private;
- struct cmtp_session *session = ctrl->driverdata;
- struct cmtp_application *app;
- struct list_head *p, *n;
-
- seq_printf(m, "%s\n\n", cmtp_procinfo(ctrl));
- seq_printf(m, "addr %s\n", session->name);
- seq_printf(m, "ctrl %d\n", session->num);
-
- list_for_each_safe(p, n, &session->applications) {
- app = list_entry(p, struct cmtp_application, list);
- seq_printf(m, "appl %d -> %d\n", app->appl, app->mapping);
- }
-
- return 0;
-}
-
-static int cmtp_proc_open(struct inode *inode, struct file *file)
-{
- return single_open(file, cmtp_proc_show, PDE(inode)->data);
-}
-
-static const struct file_operations cmtp_proc_fops = {
- .owner = THIS_MODULE,
- .open = cmtp_proc_open,
- .read = seq_read,
- .llseek = seq_lseek,
- .release = single_release,
-};
-
-int cmtp_attach_device(struct cmtp_session *session)
-{
- unsigned char buf[4];
- long ret;
-
- BT_DBG("session %p", session);
-
- capimsg_setu32(buf, 0, 0);
-
- cmtp_send_interopmsg(session, CAPI_REQ, 0xffff, CMTP_INITIAL_MSGNUM,
- CAPI_FUNCTION_GET_PROFILE, buf, 4);
-
- ret = wait_event_interruptible_timeout(session->wait,
- session->ncontroller, CMTP_INTEROP_TIMEOUT);
-
- BT_INFO("Found %d CAPI controller(s) on device %s", session->ncontroller, session->name);
-
- if (!ret)
- return -ETIMEDOUT;
-
- if (!session->ncontroller)
- return -ENODEV;
-
- if (session->ncontroller > 1)
- BT_INFO("Setting up only CAPI controller 1");
-
- session->ctrl.owner = THIS_MODULE;
- session->ctrl.driverdata = session;
- strcpy(session->ctrl.name, session->name);
-
- session->ctrl.driver_name = "cmtp";
- session->ctrl.load_firmware = cmtp_load_firmware;
- session->ctrl.reset_ctr = cmtp_reset_ctr;
- session->ctrl.register_appl = cmtp_register_appl;
- session->ctrl.release_appl = cmtp_release_appl;
- session->ctrl.send_message = cmtp_send_message;
-
- session->ctrl.procinfo = cmtp_procinfo;
- session->ctrl.proc_fops = &cmtp_proc_fops;
-
- if (attach_capi_ctr(&session->ctrl) < 0) {
- BT_ERR("Can't attach new controller");
- return -EBUSY;
- }
-
- session->num = session->ctrl.cnr;
-
- BT_DBG("session %p num %d", session, session->num);
-
- capimsg_setu32(buf, 0, 1);
-
- cmtp_send_interopmsg(session, CAPI_REQ, 0xffff, cmtp_msgnum_get(session),
- CAPI_FUNCTION_GET_MANUFACTURER, buf, 4);
-
- cmtp_send_interopmsg(session, CAPI_REQ, 0xffff, cmtp_msgnum_get(session),
- CAPI_FUNCTION_GET_VERSION, buf, 4);
-
- cmtp_send_interopmsg(session, CAPI_REQ, 0xffff, cmtp_msgnum_get(session),
- CAPI_FUNCTION_GET_SERIAL_NUMBER, buf, 4);
-
- cmtp_send_interopmsg(session, CAPI_REQ, 0xffff, cmtp_msgnum_get(session),
- CAPI_FUNCTION_GET_PROFILE, buf, 4);
-
- return 0;
-}
-
-void cmtp_detach_device(struct cmtp_session *session)
-{
- BT_DBG("session %p", session);
-
- detach_capi_ctr(&session->ctrl);
-}
diff --git a/net/bluetooth_tizen/cmtp/cmtp.h b/net/bluetooth_tizen/cmtp/cmtp.h
deleted file mode 100644
index c32638d..0000000
--- a/net/bluetooth_tizen/cmtp/cmtp.h
+++ /dev/null
@@ -1,129 +0,0 @@
-/*
- CMTP implementation for Linux Bluetooth stack (BlueZ).
- Copyright (C) 2002-2003 Marcel Holtmann <marcel@holtmann.org>
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License version 2 as
- published by the Free Software Foundation;
-
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
- OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS.
- IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY
- CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES
- WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
- OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
-
- ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS,
- COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS
- SOFTWARE IS DISCLAIMED.
-*/
-
-#ifndef __CMTP_H
-#define __CMTP_H
-
-#include <linux/types.h>
-#include <net/bluetooth/bluetooth.h>
-
-#define BTNAMSIZ 18
-
-/* CMTP ioctl defines */
-#define CMTPCONNADD _IOW('C', 200, int)
-#define CMTPCONNDEL _IOW('C', 201, int)
-#define CMTPGETCONNLIST _IOR('C', 210, int)
-#define CMTPGETCONNINFO _IOR('C', 211, int)
-
-#define CMTP_LOOPBACK 0
-
-struct cmtp_connadd_req {
- int sock; /* Connected socket */
- __u32 flags;
-};
-
-struct cmtp_conndel_req {
- bdaddr_t bdaddr;
- __u32 flags;
-};
-
-struct cmtp_conninfo {
- bdaddr_t bdaddr;
- __u32 flags;
- __u16 state;
- int num;
-};
-
-struct cmtp_connlist_req {
- __u32 cnum;
- struct cmtp_conninfo __user *ci;
-};
-
-int cmtp_add_connection(struct cmtp_connadd_req *req, struct socket *sock);
-int cmtp_del_connection(struct cmtp_conndel_req *req);
-int cmtp_get_connlist(struct cmtp_connlist_req *req);
-int cmtp_get_conninfo(struct cmtp_conninfo *ci);
-
-/* CMTP session defines */
-#define CMTP_INTEROP_TIMEOUT (HZ * 5)
-#define CMTP_INITIAL_MSGNUM 0xff00
-
-struct cmtp_session {
- struct list_head list;
-
- struct socket *sock;
-
- bdaddr_t bdaddr;
-
- unsigned long state;
- unsigned long flags;
-
- uint mtu;
-
- char name[BTNAMSIZ];
-
- atomic_t terminate;
- struct task_struct *task;
-
- wait_queue_head_t wait;
-
- int ncontroller;
- int num;
- struct capi_ctr ctrl;
-
- struct list_head applications;
-
- unsigned long blockids;
- int msgnum;
-
- struct sk_buff_head transmit;
-
- struct sk_buff *reassembly[16];
-};
-
-struct cmtp_application {
- struct list_head list;
-
- unsigned long state;
- int err;
-
- __u16 appl;
- __u16 mapping;
-
- __u16 msgnum;
-};
-
-struct cmtp_scb {
- int id;
- int data;
-};
-
-int cmtp_attach_device(struct cmtp_session *session);
-void cmtp_detach_device(struct cmtp_session *session);
-
-void cmtp_recv_capimsg(struct cmtp_session *session, struct sk_buff *skb);
-
-/* CMTP init defines */
-int cmtp_init_sockets(void);
-void cmtp_cleanup_sockets(void);
-
-#endif /* __CMTP_H */
diff --git a/net/bluetooth_tizen/cmtp/core.c b/net/bluetooth_tizen/cmtp/core.c
deleted file mode 100644
index 6c9c1fd..0000000
--- a/net/bluetooth_tizen/cmtp/core.c
+++ /dev/null
@@ -1,500 +0,0 @@
-/*
- CMTP implementation for Linux Bluetooth stack (BlueZ).
- Copyright (C) 2002-2003 Marcel Holtmann <marcel@holtmann.org>
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License version 2 as
- published by the Free Software Foundation;
-
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
- OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS.
- IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY
- CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES
- WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
- OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
-
- ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS,
- COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS
- SOFTWARE IS DISCLAIMED.
-*/
-
-#include <linux/module.h>
-
-#include <linux/types.h>
-#include <linux/errno.h>
-#include <linux/kernel.h>
-#include <linux/sched.h>
-#include <linux/slab.h>
-#include <linux/poll.h>
-#include <linux/fcntl.h>
-#include <linux/freezer.h>
-#include <linux/skbuff.h>
-#include <linux/socket.h>
-#include <linux/ioctl.h>
-#include <linux/file.h>
-#include <linux/init.h>
-#include <linux/kthread.h>
-#include <net/sock.h>
-
-#include <linux/isdn/capilli.h>
-
-#include <net/bluetooth/bluetooth.h>
-#include <net/bluetooth/l2cap.h>
-
-#include "cmtp.h"
-
-#define VERSION "1.0"
-
-static DECLARE_RWSEM(cmtp_session_sem);
-static LIST_HEAD(cmtp_session_list);
-
-static struct cmtp_session *__cmtp_get_session(bdaddr_t *bdaddr)
-{
- struct cmtp_session *session;
-
- BT_DBG("");
-
- list_for_each_entry(session, &cmtp_session_list, list)
- if (!bacmp(bdaddr, &session->bdaddr))
- return session;
-
- return NULL;
-}
-
-static void __cmtp_link_session(struct cmtp_session *session)
-{
- list_add(&session->list, &cmtp_session_list);
-}
-
-static void __cmtp_unlink_session(struct cmtp_session *session)
-{
- list_del(&session->list);
-}
-
-static void __cmtp_copy_session(struct cmtp_session *session, struct cmtp_conninfo *ci)
-{
- memset(ci, 0, sizeof(*ci));
- bacpy(&ci->bdaddr, &session->bdaddr);
-
- ci->flags = session->flags;
- ci->state = session->state;
-
- ci->num = session->num;
-}
-
-
-static inline int cmtp_alloc_block_id(struct cmtp_session *session)
-{
- int i, id = -1;
-
- for (i = 0; i < 16; i++)
- if (!test_and_set_bit(i, &session->blockids)) {
- id = i;
- break;
- }
-
- return id;
-}
-
-static inline void cmtp_free_block_id(struct cmtp_session *session, int id)
-{
- clear_bit(id, &session->blockids);
-}
-
-static inline void cmtp_add_msgpart(struct cmtp_session *session, int id, const unsigned char *buf, int count)
-{
- struct sk_buff *skb = session->reassembly[id], *nskb;
- int size;
-
- BT_DBG("session %p buf %p count %d", session, buf, count);
-
- size = (skb) ? skb->len + count : count;
-
- nskb = alloc_skb(size, GFP_ATOMIC);
- if (!nskb) {
- BT_ERR("Can't allocate memory for CAPI message");
- return;
- }
-
- if (skb && (skb->len > 0))
- skb_copy_from_linear_data(skb, skb_put(nskb, skb->len), skb->len);
-
- memcpy(skb_put(nskb, count), buf, count);
-
- session->reassembly[id] = nskb;
-
- kfree_skb(skb);
-}
-
-static inline int cmtp_recv_frame(struct cmtp_session *session, struct sk_buff *skb)
-{
- __u8 hdr, hdrlen, id;
- __u16 len;
-
- BT_DBG("session %p skb %p len %d", session, skb, skb->len);
-
- while (skb->len > 0) {
- hdr = skb->data[0];
-
- switch (hdr & 0xc0) {
- case 0x40:
- hdrlen = 2;
- len = skb->data[1];
- break;
- case 0x80:
- hdrlen = 3;
- len = skb->data[1] | (skb->data[2] << 8);
- break;
- default:
- hdrlen = 1;
- len = 0;
- break;
- }
-
- id = (hdr & 0x3c) >> 2;
-
- BT_DBG("hdr 0x%02x hdrlen %d len %d id %d", hdr, hdrlen, len, id);
-
- if (hdrlen + len > skb->len) {
- BT_ERR("Wrong size or header information in CMTP frame");
- break;
- }
-
- if (len == 0) {
- skb_pull(skb, hdrlen);
- continue;
- }
-
- switch (hdr & 0x03) {
- case 0x00:
- cmtp_add_msgpart(session, id, skb->data + hdrlen, len);
- cmtp_recv_capimsg(session, session->reassembly[id]);
- session->reassembly[id] = NULL;
- break;
- case 0x01:
- cmtp_add_msgpart(session, id, skb->data + hdrlen, len);
- break;
- default:
- if (session->reassembly[id] != NULL)
- kfree_skb(session->reassembly[id]);
- session->reassembly[id] = NULL;
- break;
- }
-
- skb_pull(skb, hdrlen + len);
- }
-
- kfree_skb(skb);
- return 0;
-}
-
-static int cmtp_send_frame(struct cmtp_session *session, unsigned char *data, int len)
-{
- struct socket *sock = session->sock;
- struct kvec iv = { data, len };
- struct msghdr msg;
-
- BT_DBG("session %p data %p len %d", session, data, len);
-
- if (!len)
- return 0;
-
- memset(&msg, 0, sizeof(msg));
-
- return kernel_sendmsg(sock, &msg, &iv, 1, len);
-}
-
-static void cmtp_process_transmit(struct cmtp_session *session)
-{
- struct sk_buff *skb, *nskb;
- unsigned char *hdr;
- unsigned int size, tail;
-
- BT_DBG("session %p", session);
-
- nskb = alloc_skb(session->mtu, GFP_ATOMIC);
- if (!nskb) {
- BT_ERR("Can't allocate memory for new frame");
- return;
- }
-
- while ((skb = skb_dequeue(&session->transmit))) {
- struct cmtp_scb *scb = (void *) skb->cb;
-
- tail = session->mtu - nskb->len;
- if (tail < 5) {
- cmtp_send_frame(session, nskb->data, nskb->len);
- skb_trim(nskb, 0);
- tail = session->mtu;
- }
-
- size = min_t(uint, ((tail < 258) ? (tail - 2) : (tail - 3)), skb->len);
-
- if (scb->id < 0) {
- scb->id = cmtp_alloc_block_id(session);
- if (scb->id < 0) {
- skb_queue_head(&session->transmit, skb);
- break;
- }
- }
-
- if (size < 256) {
- hdr = skb_put(nskb, 2);
- hdr[0] = 0x40
- | ((scb->id << 2) & 0x3c)
- | ((skb->len == size) ? 0x00 : 0x01);
- hdr[1] = size;
- } else {
- hdr = skb_put(nskb, 3);
- hdr[0] = 0x80
- | ((scb->id << 2) & 0x3c)
- | ((skb->len == size) ? 0x00 : 0x01);
- hdr[1] = size & 0xff;
- hdr[2] = size >> 8;
- }
-
- skb_copy_from_linear_data(skb, skb_put(nskb, size), size);
- skb_pull(skb, size);
-
- if (skb->len > 0) {
- skb_queue_head(&session->transmit, skb);
- } else {
- cmtp_free_block_id(session, scb->id);
- if (scb->data) {
- cmtp_send_frame(session, nskb->data, nskb->len);
- skb_trim(nskb, 0);
- }
- kfree_skb(skb);
- }
- }
-
- cmtp_send_frame(session, nskb->data, nskb->len);
-
- kfree_skb(nskb);
-}
-
-static int cmtp_session(void *arg)
-{
- struct cmtp_session *session = arg;
- struct sock *sk = session->sock->sk;
- struct sk_buff *skb;
- wait_queue_t wait;
-
- BT_DBG("session %p", session);
-
- set_user_nice(current, -15);
-
- init_waitqueue_entry(&wait, current);
- add_wait_queue(sk_sleep(sk), &wait);
- while (1) {
- set_current_state(TASK_INTERRUPTIBLE);
-
- if (atomic_read(&session->terminate))
- break;
- if (sk->sk_state != BT_CONNECTED)
- break;
-
- while ((skb = skb_dequeue(&sk->sk_receive_queue))) {
- skb_orphan(skb);
- if (!skb_linearize(skb))
- cmtp_recv_frame(session, skb);
- else
- kfree_skb(skb);
- }
-
- cmtp_process_transmit(session);
-
- schedule();
- }
- __set_current_state(TASK_RUNNING);
- remove_wait_queue(sk_sleep(sk), &wait);
-
- down_write(&cmtp_session_sem);
-
- if (!(session->flags & (1 << CMTP_LOOPBACK)))
- cmtp_detach_device(session);
-
- fput(session->sock->file);
-
- __cmtp_unlink_session(session);
-
- up_write(&cmtp_session_sem);
-
- kfree(session);
- module_put_and_exit(0);
- return 0;
-}
-
-int cmtp_add_connection(struct cmtp_connadd_req *req, struct socket *sock)
-{
- struct cmtp_session *session, *s;
- int i, err;
-
- BT_DBG("");
-
- session = kzalloc(sizeof(struct cmtp_session), GFP_KERNEL);
- if (!session)
- return -ENOMEM;
-
- down_write(&cmtp_session_sem);
-
- s = __cmtp_get_session(&bt_sk(sock->sk)->dst);
- if (s && s->state == BT_CONNECTED) {
- err = -EEXIST;
- goto failed;
- }
-
- bacpy(&session->bdaddr, &bt_sk(sock->sk)->dst);
-
- session->mtu = min_t(uint, l2cap_pi(sock->sk)->chan->omtu,
- l2cap_pi(sock->sk)->chan->imtu);
-
- BT_DBG("mtu %d", session->mtu);
-
- sprintf(session->name, "%s", batostr(&bt_sk(sock->sk)->dst));
-
- session->sock = sock;
- session->state = BT_CONFIG;
-
- init_waitqueue_head(&session->wait);
-
- session->msgnum = CMTP_INITIAL_MSGNUM;
-
- INIT_LIST_HEAD(&session->applications);
-
- skb_queue_head_init(&session->transmit);
-
- for (i = 0; i < 16; i++)
- session->reassembly[i] = NULL;
-
- session->flags = req->flags;
-
- __cmtp_link_session(session);
-
- __module_get(THIS_MODULE);
- session->task = kthread_run(cmtp_session, session, "kcmtpd_ctr_%d",
- session->num);
- if (IS_ERR(session->task)) {
- module_put(THIS_MODULE);
- err = PTR_ERR(session->task);
- goto unlink;
- }
-
- if (!(session->flags & (1 << CMTP_LOOPBACK))) {
- err = cmtp_attach_device(session);
- if (err < 0) {
- atomic_inc(&session->terminate);
- wake_up_process(session->task);
- up_write(&cmtp_session_sem);
- return err;
- }
- }
-
- up_write(&cmtp_session_sem);
- return 0;
-
-unlink:
- __cmtp_unlink_session(session);
-
-failed:
- up_write(&cmtp_session_sem);
- kfree(session);
- return err;
-}
-
-int cmtp_del_connection(struct cmtp_conndel_req *req)
-{
- struct cmtp_session *session;
- int err = 0;
-
- BT_DBG("");
-
- down_read(&cmtp_session_sem);
-
- session = __cmtp_get_session(&req->bdaddr);
- if (session) {
- /* Flush the transmit queue */
- skb_queue_purge(&session->transmit);
-
- /* Stop session thread */
- atomic_inc(&session->terminate);
- wake_up_process(session->task);
- } else
- err = -ENOENT;
-
- up_read(&cmtp_session_sem);
- return err;
-}
-
-int cmtp_get_connlist(struct cmtp_connlist_req *req)
-{
- struct cmtp_session *session;
- int err = 0, n = 0;
-
- BT_DBG("");
-
- down_read(&cmtp_session_sem);
-
- list_for_each_entry(session, &cmtp_session_list, list) {
- struct cmtp_conninfo ci;
-
- __cmtp_copy_session(session, &ci);
-
- if (copy_to_user(req->ci, &ci, sizeof(ci))) {
- err = -EFAULT;
- break;
- }
-
- if (++n >= req->cnum)
- break;
-
- req->ci++;
- }
- req->cnum = n;
-
- up_read(&cmtp_session_sem);
- return err;
-}
-
-int cmtp_get_conninfo(struct cmtp_conninfo *ci)
-{
- struct cmtp_session *session;
- int err = 0;
-
- down_read(&cmtp_session_sem);
-
- session = __cmtp_get_session(&ci->bdaddr);
- if (session)
- __cmtp_copy_session(session, ci);
- else
- err = -ENOENT;
-
- up_read(&cmtp_session_sem);
- return err;
-}
-
-
-static int __init cmtp_init(void)
-{
- BT_INFO("CMTP (CAPI Emulation) ver %s", VERSION);
-
- cmtp_init_sockets();
-
- return 0;
-}
-
-static void __exit cmtp_exit(void)
-{
- cmtp_cleanup_sockets();
-}
-
-module_init(cmtp_init);
-module_exit(cmtp_exit);
-
-MODULE_AUTHOR("Marcel Holtmann <marcel@holtmann.org>");
-MODULE_DESCRIPTION("Bluetooth CMTP ver " VERSION);
-MODULE_VERSION(VERSION);
-MODULE_LICENSE("GPL");
-MODULE_ALIAS("bt-proto-5");
diff --git a/net/bluetooth_tizen/cmtp/sock.c b/net/bluetooth_tizen/cmtp/sock.c
deleted file mode 100644
index 1230faa..0000000
--- a/net/bluetooth_tizen/cmtp/sock.c
+++ /dev/null
@@ -1,253 +0,0 @@
-/*
- CMTP implementation for Linux Bluetooth stack (BlueZ).
- Copyright (C) 2002-2003 Marcel Holtmann <marcel@holtmann.org>
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License version 2 as
- published by the Free Software Foundation;
-
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
- OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS.
- IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY
- CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES
- WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
- OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
-
- ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS,
- COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS
- SOFTWARE IS DISCLAIMED.
-*/
-
-#include <linux/module.h>
-
-#include <linux/types.h>
-#include <linux/capability.h>
-#include <linux/errno.h>
-#include <linux/kernel.h>
-#include <linux/poll.h>
-#include <linux/fcntl.h>
-#include <linux/skbuff.h>
-#include <linux/socket.h>
-#include <linux/ioctl.h>
-#include <linux/file.h>
-#include <linux/compat.h>
-#include <linux/gfp.h>
-#include <linux/uaccess.h>
-#include <net/sock.h>
-
-#include <linux/isdn/capilli.h>
-
-#include <asm/system.h>
-
-#include "cmtp.h"
-
-static int cmtp_sock_release(struct socket *sock)
-{
- struct sock *sk = sock->sk;
-
- BT_DBG("sock %p sk %p", sock, sk);
-
- if (!sk)
- return 0;
-
- sock_orphan(sk);
- sock_put(sk);
-
- return 0;
-}
-
-static int cmtp_sock_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
-{
- struct cmtp_connadd_req ca;
- struct cmtp_conndel_req cd;
- struct cmtp_connlist_req cl;
- struct cmtp_conninfo ci;
- struct socket *nsock;
- void __user *argp = (void __user *)arg;
- int err;
-
- BT_DBG("cmd %x arg %lx", cmd, arg);
-
- switch (cmd) {
- case CMTPCONNADD:
- if (!capable(CAP_NET_ADMIN))
- return -EACCES;
-
- if (copy_from_user(&ca, argp, sizeof(ca)))
- return -EFAULT;
-
- nsock = sockfd_lookup(ca.sock, &err);
- if (!nsock)
- return err;
-
- if (nsock->sk->sk_state != BT_CONNECTED) {
- sockfd_put(nsock);
- return -EBADFD;
- }
-
- err = cmtp_add_connection(&ca, nsock);
- if (!err) {
- if (copy_to_user(argp, &ca, sizeof(ca)))
- err = -EFAULT;
- } else
- sockfd_put(nsock);
-
- return err;
-
- case CMTPCONNDEL:
- if (!capable(CAP_NET_ADMIN))
- return -EACCES;
-
- if (copy_from_user(&cd, argp, sizeof(cd)))
- return -EFAULT;
-
- return cmtp_del_connection(&cd);
-
- case CMTPGETCONNLIST:
- if (copy_from_user(&cl, argp, sizeof(cl)))
- return -EFAULT;
-
- if (cl.cnum <= 0)
- return -EINVAL;
-
- err = cmtp_get_connlist(&cl);
- if (!err && copy_to_user(argp, &cl, sizeof(cl)))
- return -EFAULT;
-
- return err;
-
- case CMTPGETCONNINFO:
- if (copy_from_user(&ci, argp, sizeof(ci)))
- return -EFAULT;
-
- err = cmtp_get_conninfo(&ci);
- if (!err && copy_to_user(argp, &ci, sizeof(ci)))
- return -EFAULT;
-
- return err;
- }
-
- return -EINVAL;
-}
-
-#ifdef CONFIG_COMPAT
-static int cmtp_sock_compat_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
-{
- if (cmd == CMTPGETCONNLIST) {
- struct cmtp_connlist_req cl;
- u32 uci;
- int err;
-
- if (get_user(cl.cnum, (u32 __user *) arg) ||
- get_user(uci, (u32 __user *) (arg + 4)))
- return -EFAULT;
-
- cl.ci = compat_ptr(uci);
-
- if (cl.cnum <= 0)
- return -EINVAL;
-
- err = cmtp_get_connlist(&cl);
-
- if (!err && put_user(cl.cnum, (u32 __user *) arg))
- err = -EFAULT;
-
- return err;
- }
-
- return cmtp_sock_ioctl(sock, cmd, arg);
-}
-#endif
-
-static const struct proto_ops cmtp_sock_ops = {
- .family = PF_BLUETOOTH,
- .owner = THIS_MODULE,
- .release = cmtp_sock_release,
- .ioctl = cmtp_sock_ioctl,
-#ifdef CONFIG_COMPAT
- .compat_ioctl = cmtp_sock_compat_ioctl,
-#endif
- .bind = sock_no_bind,
- .getname = sock_no_getname,
- .sendmsg = sock_no_sendmsg,
- .recvmsg = sock_no_recvmsg,
- .poll = sock_no_poll,
- .listen = sock_no_listen,
- .shutdown = sock_no_shutdown,
- .setsockopt = sock_no_setsockopt,
- .getsockopt = sock_no_getsockopt,
- .connect = sock_no_connect,
- .socketpair = sock_no_socketpair,
- .accept = sock_no_accept,
- .mmap = sock_no_mmap
-};
-
-static struct proto cmtp_proto = {
- .name = "CMTP",
- .owner = THIS_MODULE,
- .obj_size = sizeof(struct bt_sock)
-};
-
-static int cmtp_sock_create(struct net *net, struct socket *sock, int protocol,
- int kern)
-{
- struct sock *sk;
-
- BT_DBG("sock %p", sock);
-
- if (sock->type != SOCK_RAW)
- return -ESOCKTNOSUPPORT;
-
- sk = sk_alloc(net, PF_BLUETOOTH, GFP_ATOMIC, &cmtp_proto);
- if (!sk)
- return -ENOMEM;
-
- sock_init_data(sock, sk);
-
- sock->ops = &cmtp_sock_ops;
-
- sock->state = SS_UNCONNECTED;
-
- sock_reset_flag(sk, SOCK_ZAPPED);
-
- sk->sk_protocol = protocol;
- sk->sk_state = BT_OPEN;
-
- return 0;
-}
-
-static const struct net_proto_family cmtp_sock_family_ops = {
- .family = PF_BLUETOOTH,
- .owner = THIS_MODULE,
- .create = cmtp_sock_create
-};
-
-int cmtp_init_sockets(void)
-{
- int err;
-
- err = proto_register(&cmtp_proto, 0);
- if (err < 0)
- return err;
-
- err = bt_sock_register(BTPROTO_CMTP, &cmtp_sock_family_ops);
- if (err < 0)
- goto error;
-
- return 0;
-
-error:
- BT_ERR("Can't register CMTP socket");
- proto_unregister(&cmtp_proto);
- return err;
-}
-
-void cmtp_cleanup_sockets(void)
-{
- if (bt_sock_unregister(BTPROTO_CMTP) < 0)
- BT_ERR("Can't unregister CMTP socket");
-
- proto_unregister(&cmtp_proto);
-}
diff --git a/net/bluetooth_tizen/hci_conn.c b/net/bluetooth_tizen/hci_conn.c
deleted file mode 100644
index 459227d..0000000
--- a/net/bluetooth_tizen/hci_conn.c
+++ /dev/null
@@ -1,984 +0,0 @@
-/*
- BlueZ - Bluetooth protocol stack for Linux
- Copyright (c) 2000-2001, 2010, Code Aurora Forum. All rights reserved.
-
- Written 2000,2001 by Maxim Krasnyansky <maxk@qualcomm.com>
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License version 2 as
- published by the Free Software Foundation;
-
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
- OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS.
- IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY
- CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES
- WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
- OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
-
- ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS,
- COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS
- SOFTWARE IS DISCLAIMED.
-*/
-
-/* Bluetooth HCI connection handling. */
-
-#include <linux/module.h>
-
-#include <linux/types.h>
-#include <linux/errno.h>
-#include <linux/kernel.h>
-#include <linux/slab.h>
-#include <linux/poll.h>
-#include <linux/fcntl.h>
-#include <linux/init.h>
-#include <linux/skbuff.h>
-#include <linux/interrupt.h>
-#include <linux/notifier.h>
-#include <net/sock.h>
-
-#include <asm/system.h>
-#include <linux/uaccess.h>
-#include <asm/unaligned.h>
-
-#include <net/bluetooth/bluetooth.h>
-#include <net/bluetooth/hci_core.h>
-
-static void hci_le_connect(struct hci_conn *conn)
-{
- struct hci_dev *hdev = conn->hdev;
- struct hci_cp_le_create_conn cp;
-
- conn->state = BT_CONNECT;
- conn->out = true;
- conn->link_mode |= HCI_LM_MASTER;
- conn->sec_level = BT_SECURITY_LOW;
-
- memset(&cp, 0, sizeof(cp));
- cp.scan_interval = cpu_to_le16(0x0060);
- cp.scan_window = cpu_to_le16(0x0030);
- bacpy(&cp.peer_addr, &conn->dst);
- cp.peer_addr_type = conn->dst_type;
- cp.conn_interval_min = cpu_to_le16(0x0028);
- cp.conn_interval_max = cpu_to_le16(0x0038);
- cp.supervision_timeout = cpu_to_le16(0x002a);
- cp.min_ce_len = cpu_to_le16(0x0000);
- cp.max_ce_len = cpu_to_le16(0x0000);
-
- hci_send_cmd(hdev, HCI_OP_LE_CREATE_CONN, sizeof(cp), &cp);
-}
-
-static void hci_le_connect_cancel(struct hci_conn *conn)
-{
- hci_send_cmd(conn->hdev, HCI_OP_LE_CREATE_CONN_CANCEL, 0, NULL);
-}
-
-void hci_acl_connect(struct hci_conn *conn)
-{
- struct hci_dev *hdev = conn->hdev;
- struct inquiry_entry *ie;
- struct hci_cp_create_conn cp;
-
- BT_DBG("hcon %p", conn);
-
- conn->state = BT_CONNECT;
- conn->out = true;
-
- conn->link_mode = HCI_LM_MASTER;
-
- conn->attempt++;
-
- conn->link_policy = hdev->link_policy;
-
- memset(&cp, 0, sizeof(cp));
- bacpy(&cp.bdaddr, &conn->dst);
- cp.pscan_rep_mode = 0x02;
-
- ie = hci_inquiry_cache_lookup(hdev, &conn->dst);
- if (ie) {
- if (inquiry_entry_age(ie) <= INQUIRY_ENTRY_AGE_MAX) {
- cp.pscan_rep_mode = ie->data.pscan_rep_mode;
- cp.pscan_mode = ie->data.pscan_mode;
- cp.clock_offset = ie->data.clock_offset |
- cpu_to_le16(0x8000);
- }
-
- memcpy(conn->dev_class, ie->data.dev_class, 3);
- if (ie->data.ssp_mode > 0)
- set_bit(HCI_CONN_SSP_ENABLED, &conn->flags);
- }
-
- cp.pkt_type = cpu_to_le16(conn->pkt_type);
- if (lmp_rswitch_capable(hdev) && !(hdev->link_mode & HCI_LM_MASTER))
- cp.role_switch = 0x01;
- else
- cp.role_switch = 0x00;
-
- hci_send_cmd(hdev, HCI_OP_CREATE_CONN, sizeof(cp), &cp);
-}
-
-static void hci_acl_connect_cancel(struct hci_conn *conn)
-{
- struct hci_cp_create_conn_cancel cp;
-
- BT_DBG("%p", conn);
-
- if (conn->hdev->hci_ver < BLUETOOTH_VER_1_2)
- return;
-
- bacpy(&cp.bdaddr, &conn->dst);
- hci_send_cmd(conn->hdev, HCI_OP_CREATE_CONN_CANCEL, sizeof(cp), &cp);
-}
-
-void hci_acl_disconn(struct hci_conn *conn, __u8 reason)
-{
- struct hci_cp_disconnect cp;
-
- BT_DBG("%p", conn);
-
- conn->state = BT_DISCONN;
-
- cp.handle = cpu_to_le16(conn->handle);
- cp.reason = reason;
- hci_send_cmd(conn->hdev, HCI_OP_DISCONNECT, sizeof(cp), &cp);
-}
-
-void hci_add_sco(struct hci_conn *conn, __u16 handle)
-{
- struct hci_dev *hdev = conn->hdev;
- struct hci_cp_add_sco cp;
-
- BT_DBG("%p", conn);
-
- conn->state = BT_CONNECT;
- conn->out = true;
-
- conn->attempt++;
-
- cp.handle = cpu_to_le16(handle);
- cp.pkt_type = cpu_to_le16(conn->pkt_type);
-
- hci_send_cmd(hdev, HCI_OP_ADD_SCO, sizeof(cp), &cp);
-}
-
-void hci_setup_sync(struct hci_conn *conn, __u16 handle)
-{
- struct hci_dev *hdev = conn->hdev;
- struct hci_cp_setup_sync_conn cp;
-
- BT_DBG("%p", conn);
-
- conn->state = BT_CONNECT;
- conn->out = true;
-
- conn->attempt++;
-
- cp.handle = cpu_to_le16(handle);
- cp.pkt_type = cpu_to_le16(conn->pkt_type);
-
- cp.tx_bandwidth = cpu_to_le32(0x00001f40);
- cp.rx_bandwidth = cpu_to_le32(0x00001f40);
- cp.max_latency = cpu_to_le16(0xffff);
- cp.voice_setting = cpu_to_le16(hdev->voice_setting);
- cp.retrans_effort = 0xff;
-
- hci_send_cmd(hdev, HCI_OP_SETUP_SYNC_CONN, sizeof(cp), &cp);
-}
-
-void hci_le_conn_update(struct hci_conn *conn, u16 min, u16 max,
- u16 latency, u16 to_multiplier)
-{
- struct hci_cp_le_conn_update cp;
- struct hci_dev *hdev = conn->hdev;
-
- memset(&cp, 0, sizeof(cp));
-
- cp.handle = cpu_to_le16(conn->handle);
- cp.conn_interval_min = cpu_to_le16(min);
- cp.conn_interval_max = cpu_to_le16(max);
- cp.conn_latency = cpu_to_le16(latency);
- cp.supervision_timeout = cpu_to_le16(to_multiplier);
- cp.min_ce_len = cpu_to_le16(0x0001);
- cp.max_ce_len = cpu_to_le16(0x0001);
-
- hci_send_cmd(hdev, HCI_OP_LE_CONN_UPDATE, sizeof(cp), &cp);
-}
-EXPORT_SYMBOL(hci_le_conn_update);
-
-void hci_le_start_enc(struct hci_conn *conn, __le16 ediv, __u8 rand[8],
- __u8 ltk[16])
-{
- struct hci_dev *hdev = conn->hdev;
- struct hci_cp_le_start_enc cp;
-
- BT_DBG("%p", conn);
-
- memset(&cp, 0, sizeof(cp));
-
- cp.handle = cpu_to_le16(conn->handle);
- memcpy(cp.ltk, ltk, sizeof(cp.ltk));
- cp.ediv = ediv;
- memcpy(cp.rand, rand, sizeof(cp.rand));
-
- hci_send_cmd(hdev, HCI_OP_LE_START_ENC, sizeof(cp), &cp);
-}
-EXPORT_SYMBOL(hci_le_start_enc);
-
-void hci_le_ltk_reply(struct hci_conn *conn, u8 ltk[16])
-{
- struct hci_dev *hdev = conn->hdev;
- struct hci_cp_le_ltk_reply cp;
-
- BT_DBG("%p", conn);
-
- memset(&cp, 0, sizeof(cp));
-
- cp.handle = cpu_to_le16(conn->handle);
- memcpy(cp.ltk, ltk, sizeof(ltk));
-
- hci_send_cmd(hdev, HCI_OP_LE_LTK_REPLY, sizeof(cp), &cp);
-}
-EXPORT_SYMBOL(hci_le_ltk_reply);
-
-void hci_le_ltk_neg_reply(struct hci_conn *conn)
-{
- struct hci_dev *hdev = conn->hdev;
- struct hci_cp_le_ltk_neg_reply cp;
-
- BT_DBG("%p", conn);
-
- memset(&cp, 0, sizeof(cp));
-
- cp.handle = cpu_to_le16(conn->handle);
-
- hci_send_cmd(hdev, HCI_OP_LE_LTK_NEG_REPLY, sizeof(cp), &cp);
-}
-
-/* Device _must_ be locked */
-void hci_sco_setup(struct hci_conn *conn, __u8 status)
-{
- struct hci_conn *sco = conn->link;
-
- BT_DBG("%p", conn);
-
- if (!sco)
- return;
-
- if (!status) {
- if (lmp_esco_capable(conn->hdev))
- hci_setup_sync(sco, conn->handle);
- else
- hci_add_sco(sco, conn->handle);
- } else {
- hci_proto_connect_cfm(sco, status);
- hci_conn_del(sco);
- }
-}
-
-static void hci_conn_timeout(struct work_struct *work)
-{
- struct hci_conn *conn = container_of(work, struct hci_conn,
- disc_work.work);
- __u8 reason;
-
- BT_DBG("conn %p state %s", conn, state_to_string(conn->state));
-
- if (atomic_read(&conn->refcnt))
- return;
-
- switch (conn->state) {
- case BT_CONNECT:
- case BT_CONNECT2:
- if (conn->out) {
- if (conn->type == ACL_LINK)
- hci_acl_connect_cancel(conn);
- else if (conn->type == LE_LINK)
- hci_le_connect_cancel(conn);
- }
- break;
- case BT_CONFIG:
- case BT_CONNECTED:
- reason = hci_proto_disconn_ind(conn);
- hci_acl_disconn(conn, reason);
- break;
- default:
- conn->state = BT_CLOSED;
- break;
- }
-}
-
-/* Enter sniff mode */
-static void hci_conn_enter_sniff_mode(struct hci_conn *conn)
-{
- struct hci_dev *hdev = conn->hdev;
-
- BT_DBG("conn %p mode %d", conn, conn->mode);
-
- if (test_bit(HCI_RAW, &hdev->flags))
- return;
-
- if (!lmp_sniff_capable(hdev) || !lmp_sniff_capable(conn))
- return;
-
- if (conn->mode != HCI_CM_ACTIVE || !(conn->link_policy & HCI_LP_SNIFF))
- return;
-
- if (lmp_sniffsubr_capable(hdev) && lmp_sniffsubr_capable(conn)) {
- struct hci_cp_sniff_subrate cp;
- cp.handle = cpu_to_le16(conn->handle);
- cp.max_latency = cpu_to_le16(0);
- cp.min_remote_timeout = cpu_to_le16(0);
- cp.min_local_timeout = cpu_to_le16(0);
- hci_send_cmd(hdev, HCI_OP_SNIFF_SUBRATE, sizeof(cp), &cp);
- }
-
- if (!test_and_set_bit(HCI_CONN_MODE_CHANGE_PEND, &conn->flags)) {
- struct hci_cp_sniff_mode cp;
- cp.handle = cpu_to_le16(conn->handle);
- cp.max_interval = cpu_to_le16(hdev->sniff_max_interval);
- cp.min_interval = cpu_to_le16(hdev->sniff_min_interval);
- cp.attempt = cpu_to_le16(4);
- cp.timeout = cpu_to_le16(1);
- hci_send_cmd(hdev, HCI_OP_SNIFF_MODE, sizeof(cp), &cp);
- }
-}
-
-static void hci_conn_idle(unsigned long arg)
-{
- struct hci_conn *conn = (void *) arg;
-
- BT_DBG("conn %p mode %d", conn, conn->mode);
-
- hci_conn_enter_sniff_mode(conn);
-}
-
-static void hci_conn_auto_accept(unsigned long arg)
-{
- struct hci_conn *conn = (void *) arg;
- struct hci_dev *hdev = conn->hdev;
-
- hci_send_cmd(hdev, HCI_OP_USER_CONFIRM_REPLY, sizeof(conn->dst),
- &conn->dst);
-}
-
-struct hci_conn *hci_conn_add(struct hci_dev *hdev, int type, bdaddr_t *dst)
-{
- struct hci_conn *conn;
-
- BT_DBG("%s dst %s", hdev->name, batostr(dst));
-
- conn = kzalloc(sizeof(struct hci_conn), GFP_KERNEL);
- if (!conn)
- return NULL;
-
- bacpy(&conn->dst, dst);
- conn->hdev = hdev;
- conn->type = type;
- conn->mode = HCI_CM_ACTIVE;
- conn->state = BT_OPEN;
- conn->auth_type = HCI_AT_GENERAL_BONDING;
- conn->io_capability = hdev->io_capability;
- conn->remote_auth = 0xff;
- conn->key_type = 0xff;
-
- set_bit(HCI_CONN_POWER_SAVE, &conn->flags);
- conn->disc_timeout = HCI_DISCONN_TIMEOUT;
-
- switch (type) {
- case ACL_LINK:
- conn->pkt_type = hdev->pkt_type & ACL_PTYPE_MASK;
- break;
- case SCO_LINK:
- if (lmp_esco_capable(hdev))
- conn->pkt_type = (hdev->esco_type & SCO_ESCO_MASK) |
- (hdev->esco_type & EDR_ESCO_MASK);
- else
- conn->pkt_type = hdev->pkt_type & SCO_PTYPE_MASK;
- break;
- case ESCO_LINK:
- conn->pkt_type = hdev->esco_type & ~EDR_ESCO_MASK;
- break;
- }
-
- skb_queue_head_init(&conn->data_q);
-
- INIT_LIST_HEAD(&conn->chan_list);
-
- INIT_DELAYED_WORK(&conn->disc_work, hci_conn_timeout);
- setup_timer(&conn->idle_timer, hci_conn_idle, (unsigned long)conn);
- setup_timer(&conn->auto_accept_timer, hci_conn_auto_accept,
- (unsigned long) conn);
-
- atomic_set(&conn->refcnt, 0);
-
- hci_dev_hold(hdev);
-
- hci_conn_hash_add(hdev, conn);
- if (hdev->notify)
- hdev->notify(hdev, HCI_NOTIFY_CONN_ADD);
-
- atomic_set(&conn->devref, 0);
-
- hci_conn_init_sysfs(conn);
-
- return conn;
-}
-
-int hci_conn_del(struct hci_conn *conn)
-{
- struct hci_dev *hdev = conn->hdev;
-
- BT_DBG("%s conn %p handle %d", hdev->name, conn, conn->handle);
-
- del_timer(&conn->idle_timer);
-
- cancel_delayed_work_sync(&conn->disc_work);
-
- del_timer(&conn->auto_accept_timer);
-
- if (conn->type == ACL_LINK) {
- struct hci_conn *sco = conn->link;
- if (sco)
- sco->link = NULL;
-
- /* Unacked frames */
- hdev->acl_cnt += conn->sent;
- } else if (conn->type == LE_LINK) {
- if (hdev->le_pkts)
- hdev->le_cnt += conn->sent;
- else
- hdev->acl_cnt += conn->sent;
- } else {
- struct hci_conn *acl = conn->link;
- if (acl) {
- acl->link = NULL;
- hci_conn_put(acl);
- }
- }
-
-
- hci_chan_list_flush(conn);
-
- hci_conn_hash_del(hdev, conn);
- if (hdev->notify)
- hdev->notify(hdev, HCI_NOTIFY_CONN_DEL);
-
- skb_queue_purge(&conn->data_q);
-
- hci_conn_put_device(conn);
-
- hci_dev_put(hdev);
-
- if (conn->handle == 0)
- kfree(conn);
-
- return 0;
-}
-
-struct hci_dev *hci_get_route(bdaddr_t *dst, bdaddr_t *src)
-{
- int use_src = bacmp(src, BDADDR_ANY);
- struct hci_dev *hdev = NULL, *d;
-
- BT_DBG("%s -> %s", batostr(src), batostr(dst));
-
- read_lock(&hci_dev_list_lock);
-
- list_for_each_entry(d, &hci_dev_list, list) {
- if (!test_bit(HCI_UP, &d->flags) || test_bit(HCI_RAW, &d->flags))
- continue;
-
- /* Simple routing:
- * No source address - find interface with bdaddr != dst
- * Source address - find interface with bdaddr == src
- */
-
- if (use_src) {
- if (!bacmp(&d->bdaddr, src)) {
- hdev = d; break;
- }
- } else {
- if (bacmp(&d->bdaddr, dst)) {
- hdev = d; break;
- }
- }
- }
-
- if (hdev)
- hdev = hci_dev_hold(hdev);
-
- read_unlock(&hci_dev_list_lock);
- return hdev;
-}
-EXPORT_SYMBOL(hci_get_route);
-
-/* Create SCO, ACL or LE connection.
- * Device _must_ be locked */
-struct hci_conn *hci_connect(struct hci_dev *hdev, int type, bdaddr_t *dst, __u8 sec_level, __u8 auth_type)
-{
- struct hci_conn *acl;
- struct hci_conn *sco;
- struct hci_conn *le;
-
- BT_DBG("%s dst %s", hdev->name, batostr(dst));
-
- if (type == LE_LINK) {
- struct adv_entry *entry;
-
- le = hci_conn_hash_lookup_ba(hdev, LE_LINK, dst);
- if (le)
- return ERR_PTR(-EBUSY);
-
- entry = hci_find_adv_entry(hdev, dst);
- if (!entry)
- return ERR_PTR(-EHOSTUNREACH);
-
- le = hci_conn_add(hdev, LE_LINK, dst);
- if (!le)
- return ERR_PTR(-ENOMEM);
-
- le->dst_type = entry->bdaddr_type;
-
- hci_le_connect(le);
-
- hci_conn_hold(le);
-
- return le;
- }
-
- acl = hci_conn_hash_lookup_ba(hdev, ACL_LINK, dst);
- if (!acl) {
- acl = hci_conn_add(hdev, ACL_LINK, dst);
- if (!acl)
- return ERR_PTR(-ENOMEM);
- }
-
- hci_conn_hold(acl);
-
- if (acl->state == BT_OPEN || acl->state == BT_CLOSED) {
- acl->sec_level = BT_SECURITY_LOW;
- acl->pending_sec_level = sec_level;
- acl->auth_type = auth_type;
- hci_acl_connect(acl);
- }
-
- if (type == ACL_LINK)
- return acl;
-
- sco = hci_conn_hash_lookup_ba(hdev, type, dst);
- if (!sco) {
- sco = hci_conn_add(hdev, type, dst);
- if (!sco) {
- hci_conn_put(acl);
- return ERR_PTR(-ENOMEM);
- }
- }
-
- acl->link = sco;
- sco->link = acl;
-
- hci_conn_hold(sco);
-
- if (acl->state == BT_CONNECTED &&
- (sco->state == BT_OPEN || sco->state == BT_CLOSED)) {
- set_bit(HCI_CONN_POWER_SAVE, &acl->flags);
- hci_conn_enter_active_mode(acl, BT_POWER_FORCE_ACTIVE_ON);
-
- if (test_bit(HCI_CONN_MODE_CHANGE_PEND, &acl->flags)) {
- /* defer SCO setup until mode change completed */
- set_bit(HCI_CONN_SCO_SETUP_PEND, &acl->flags);
- return sco;
- }
-
- hci_sco_setup(acl, 0x00);
- }
-
- return sco;
-}
-EXPORT_SYMBOL(hci_connect);
-
-/* Check link security requirement */
-int hci_conn_check_link_mode(struct hci_conn *conn)
-{
- BT_DBG("conn %p", conn);
-
- if (hci_conn_ssp_enabled(conn) && !(conn->link_mode & HCI_LM_ENCRYPT))
- return 0;
-
- return 1;
-}
-EXPORT_SYMBOL(hci_conn_check_link_mode);
-
-/* Authenticate remote device */
-static int hci_conn_auth(struct hci_conn *conn, __u8 sec_level, __u8 auth_type)
-{
- BT_DBG("conn %p", conn);
-
- if (conn->pending_sec_level > sec_level)
- sec_level = conn->pending_sec_level;
-
- if (sec_level > conn->sec_level)
- conn->pending_sec_level = sec_level;
- else if (conn->link_mode & HCI_LM_AUTH)
- return 1;
-
- /* Make sure we preserve an existing MITM requirement*/
- auth_type |= (conn->auth_type & 0x01);
-
- conn->auth_type = auth_type;
-
- if (!test_and_set_bit(HCI_CONN_AUTH_PEND, &conn->flags)) {
- struct hci_cp_auth_requested cp;
-
- /* encrypt must be pending if auth is also pending */
- set_bit(HCI_CONN_ENCRYPT_PEND, &conn->flags);
-
- cp.handle = cpu_to_le16(conn->handle);
- hci_send_cmd(conn->hdev, HCI_OP_AUTH_REQUESTED,
- sizeof(cp), &cp);
- if (conn->key_type != 0xff)
- set_bit(HCI_CONN_REAUTH_PEND, &conn->flags);
- }
-
- return 0;
-}
-
-/* Encrypt the the link */
-static void hci_conn_encrypt(struct hci_conn *conn)
-{
- BT_DBG("conn %p", conn);
-
- if (!test_and_set_bit(HCI_CONN_ENCRYPT_PEND, &conn->flags)) {
- struct hci_cp_set_conn_encrypt cp;
- cp.handle = cpu_to_le16(conn->handle);
- cp.encrypt = 0x01;
- hci_send_cmd(conn->hdev, HCI_OP_SET_CONN_ENCRYPT, sizeof(cp),
- &cp);
- }
-}
-
-/* Enable security */
-int hci_conn_security(struct hci_conn *conn, __u8 sec_level, __u8 auth_type)
-{
- BT_DBG("conn %p", conn);
-
- /* For sdp we don't need the link key. */
- if (sec_level == BT_SECURITY_SDP)
- return 1;
-
- /* For non 2.1 devices and low security level we don't need the link
- key. */
- if (sec_level == BT_SECURITY_LOW && !hci_conn_ssp_enabled(conn))
- return 1;
-
- /* For other security levels we need the link key. */
- if (!(conn->link_mode & HCI_LM_AUTH))
- goto auth;
-
- /* An authenticated combination key has sufficient security for any
- security level. */
- if (conn->key_type == HCI_LK_AUTH_COMBINATION)
- goto encrypt;
-
- /* An unauthenticated combination key has sufficient security for
- security level 1 and 2. */
- if (conn->key_type == HCI_LK_UNAUTH_COMBINATION &&
- (sec_level == BT_SECURITY_MEDIUM ||
- sec_level == BT_SECURITY_LOW))
- goto encrypt;
-
- /* A combination key has always sufficient security for the security
- levels 1 or 2. High security level requires the combination key
- is generated using maximum PIN code length (16).
- For pre 2.1 units. */
- if (conn->key_type == HCI_LK_COMBINATION &&
- (sec_level != BT_SECURITY_HIGH ||
- conn->pin_length == 16))
- goto encrypt;
-
-auth:
- if (test_bit(HCI_CONN_ENCRYPT_PEND, &conn->flags))
- return 0;
-
- if (!hci_conn_auth(conn, sec_level, auth_type))
- return 0;
-
-encrypt:
- if (conn->link_mode & HCI_LM_ENCRYPT)
- return 1;
-
- hci_conn_encrypt(conn);
- return 0;
-}
-EXPORT_SYMBOL(hci_conn_security);
-
-/* Check secure link requirement */
-int hci_conn_check_secure(struct hci_conn *conn, __u8 sec_level)
-{
- BT_DBG("conn %p", conn);
-
- if (sec_level != BT_SECURITY_HIGH)
- return 1; /* Accept if non-secure is required */
-
- if (conn->sec_level == BT_SECURITY_HIGH)
- return 1;
-
- return 0; /* Reject not secure link */
-}
-EXPORT_SYMBOL(hci_conn_check_secure);
-
-/* Change link key */
-int hci_conn_change_link_key(struct hci_conn *conn)
-{
- BT_DBG("conn %p", conn);
-
- if (!test_and_set_bit(HCI_CONN_AUTH_PEND, &conn->flags)) {
- struct hci_cp_change_conn_link_key cp;
- cp.handle = cpu_to_le16(conn->handle);
- hci_send_cmd(conn->hdev, HCI_OP_CHANGE_CONN_LINK_KEY,
- sizeof(cp), &cp);
- }
-
- return 0;
-}
-EXPORT_SYMBOL(hci_conn_change_link_key);
-
-/* Switch role */
-int hci_conn_switch_role(struct hci_conn *conn, __u8 role)
-{
- BT_DBG("conn %p", conn);
-
- if (!role && conn->link_mode & HCI_LM_MASTER)
- return 1;
-
- if (!test_and_set_bit(HCI_CONN_RSWITCH_PEND, &conn->flags)) {
- struct hci_cp_switch_role cp;
- bacpy(&cp.bdaddr, &conn->dst);
- cp.role = role;
- hci_send_cmd(conn->hdev, HCI_OP_SWITCH_ROLE, sizeof(cp), &cp);
- }
-
- return 0;
-}
-EXPORT_SYMBOL(hci_conn_switch_role);
-
-/* Enter active mode */
-void hci_conn_enter_active_mode(struct hci_conn *conn, __u8 force_active)
-{
- struct hci_dev *hdev = conn->hdev;
-
- BT_DBG("conn %p mode %d", conn, conn->mode);
-
- if (test_bit(HCI_RAW, &hdev->flags))
- return;
-
- if (conn->mode != HCI_CM_SNIFF)
- goto timer;
-
- if (!test_bit(HCI_CONN_POWER_SAVE, &conn->flags) && !force_active)
- goto timer;
-
- if (!test_and_set_bit(HCI_CONN_MODE_CHANGE_PEND, &conn->flags)) {
- struct hci_cp_exit_sniff_mode cp;
- cp.handle = cpu_to_le16(conn->handle);
- hci_send_cmd(hdev, HCI_OP_EXIT_SNIFF_MODE, sizeof(cp), &cp);
- }
-
-timer:
- if (hdev->idle_timeout > 0)
- mod_timer(&conn->idle_timer,
- jiffies + msecs_to_jiffies(hdev->idle_timeout));
-}
-
-/* Drop all connection on the device */
-void hci_conn_hash_flush(struct hci_dev *hdev)
-{
- struct hci_conn_hash *h = &hdev->conn_hash;
- struct hci_conn *c, *n;
-
- BT_DBG("hdev %s", hdev->name);
-
- list_for_each_entry_safe(c, n, &h->list, list) {
- c->state = BT_CLOSED;
-
- hci_proto_disconn_cfm(c, HCI_ERROR_LOCAL_HOST_TERM);
- hci_conn_del(c);
- }
-}
-
-/* Check pending connect attempts */
-void hci_conn_check_pending(struct hci_dev *hdev)
-{
- struct hci_conn *conn;
-
- BT_DBG("hdev %s", hdev->name);
-
- hci_dev_lock(hdev);
-
- conn = hci_conn_hash_lookup_state(hdev, ACL_LINK, BT_CONNECT2);
- if (conn)
- hci_acl_connect(conn);
-
- hci_dev_unlock(hdev);
-}
-
-void hci_conn_hold_device(struct hci_conn *conn)
-{
- atomic_inc(&conn->devref);
-}
-EXPORT_SYMBOL(hci_conn_hold_device);
-
-void hci_conn_put_device(struct hci_conn *conn)
-{
- if (atomic_dec_and_test(&conn->devref))
- hci_conn_del_sysfs(conn);
-}
-EXPORT_SYMBOL(hci_conn_put_device);
-
-int hci_get_conn_list(void __user *arg)
-{
- register struct hci_conn *c;
- struct hci_conn_list_req req, *cl;
- struct hci_conn_info *ci;
- struct hci_dev *hdev;
- int n = 0, size, err;
-
- if (copy_from_user(&req, arg, sizeof(req)))
- return -EFAULT;
-
- if (!req.conn_num || req.conn_num > (PAGE_SIZE * 2) / sizeof(*ci))
- return -EINVAL;
-
- size = sizeof(req) + req.conn_num * sizeof(*ci);
-
- cl = kmalloc(size, GFP_KERNEL);
- if (!cl)
- return -ENOMEM;
-
- hdev = hci_dev_get(req.dev_id);
- if (!hdev) {
- kfree(cl);
- return -ENODEV;
- }
-
- ci = cl->conn_info;
-
- hci_dev_lock(hdev);
- list_for_each_entry(c, &hdev->conn_hash.list, list) {
- bacpy(&(ci + n)->bdaddr, &c->dst);
- (ci + n)->handle = c->handle;
- (ci + n)->type = c->type;
- (ci + n)->out = c->out;
- (ci + n)->state = c->state;
- (ci + n)->link_mode = c->link_mode;
- if (++n >= req.conn_num)
- break;
- }
- hci_dev_unlock(hdev);
-
- cl->dev_id = hdev->id;
- cl->conn_num = n;
- size = sizeof(req) + n * sizeof(*ci);
-
- hci_dev_put(hdev);
-
- err = copy_to_user(arg, cl, size);
- kfree(cl);
-
- return err ? -EFAULT : 0;
-}
-
-int hci_get_conn_info(struct hci_dev *hdev, void __user *arg)
-{
- struct hci_conn_info_req req;
- struct hci_conn_info ci;
- struct hci_conn *conn;
- char __user *ptr = arg + sizeof(req);
-
- if (copy_from_user(&req, arg, sizeof(req)))
- return -EFAULT;
-
- hci_dev_lock(hdev);
- conn = hci_conn_hash_lookup_ba(hdev, req.type, &req.bdaddr);
- if (conn) {
- bacpy(&ci.bdaddr, &conn->dst);
- ci.handle = conn->handle;
- ci.type = conn->type;
- ci.out = conn->out;
- ci.state = conn->state;
- ci.link_mode = conn->link_mode;
- }
- hci_dev_unlock(hdev);
-
- if (!conn)
- return -ENOENT;
-
- return copy_to_user(ptr, &ci, sizeof(ci)) ? -EFAULT : 0;
-}
-
-int hci_get_auth_info(struct hci_dev *hdev, void __user *arg)
-{
- struct hci_auth_info_req req;
- struct hci_conn *conn;
-
- if (copy_from_user(&req, arg, sizeof(req)))
- return -EFAULT;
-
- hci_dev_lock(hdev);
- conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &req.bdaddr);
- if (conn)
- req.type = conn->auth_type;
- hci_dev_unlock(hdev);
-
- if (!conn)
- return -ENOENT;
-
- return copy_to_user(arg, &req, sizeof(req)) ? -EFAULT : 0;
-}
-
-struct hci_chan *hci_chan_create(struct hci_conn *conn)
-{
- struct hci_dev *hdev = conn->hdev;
- struct hci_chan *chan;
-
- BT_DBG("%s conn %p", hdev->name, conn);
-
- chan = kzalloc(sizeof(struct hci_chan), GFP_KERNEL);
- if (!chan)
- return NULL;
-
- chan->conn = conn;
- skb_queue_head_init(&chan->data_q);
-
- list_add_rcu(&chan->list, &conn->chan_list);
-
- return chan;
-}
-
-int hci_chan_del(struct hci_chan *chan)
-{
- struct hci_conn *conn = chan->conn;
- struct hci_dev *hdev = conn->hdev;
-
- BT_DBG("%s conn %p chan %p", hdev->name, conn, chan);
-
- list_del_rcu(&chan->list);
-
- synchronize_rcu();
-
- skb_queue_purge(&chan->data_q);
- kfree(chan);
-
- return 0;
-}
-
-void hci_chan_list_flush(struct hci_conn *conn)
-{
- struct hci_chan *chan, *n;
-
- BT_DBG("conn %p", conn);
-
- list_for_each_entry_safe(chan, n, &conn->chan_list, list)
- hci_chan_del(chan);
-}
diff --git a/net/bluetooth_tizen/hci_core.c b/net/bluetooth_tizen/hci_core.c
deleted file mode 100644
index 1c69c54..0000000
--- a/net/bluetooth_tizen/hci_core.c
+++ /dev/null
@@ -1,2966 +0,0 @@
-/*
- BlueZ - Bluetooth protocol stack for Linux
- Copyright (C) 2000-2001 Qualcomm Incorporated
- Copyright (C) 2011 ProFUSION Embedded Systems
-
- Written 2000,2001 by Maxim Krasnyansky <maxk@qualcomm.com>
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License version 2 as
- published by the Free Software Foundation;
-
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
- OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS.
- IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY
- CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES
- WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
- OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
-
- ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS,
- COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS
- SOFTWARE IS DISCLAIMED.
-*/
-
-/* Bluetooth HCI core. */
-
-#include <linux/jiffies.h>
-#include <linux/module.h>
-#include <linux/kmod.h>
-
-#include <linux/types.h>
-#include <linux/errno.h>
-#include <linux/kernel.h>
-#include <linux/sched.h>
-#include <linux/slab.h>
-#include <linux/poll.h>
-#include <linux/fcntl.h>
-#include <linux/init.h>
-#include <linux/skbuff.h>
-#include <linux/workqueue.h>
-#include <linux/interrupt.h>
-#include <linux/notifier.h>
-#include <linux/rfkill.h>
-#include <linux/timer.h>
-#include <linux/crypto.h>
-#include <net/sock.h>
-
-#include <asm/system.h>
-#include <linux/uaccess.h>
-#include <asm/unaligned.h>
-
-#include <net/bluetooth/bluetooth.h>
-#include <net/bluetooth/hci_core.h>
-
-#define AUTO_OFF_TIMEOUT 2000
-
-static void hci_rx_work(struct work_struct *work);
-static void hci_cmd_work(struct work_struct *work);
-static void hci_tx_work(struct work_struct *work);
-
-/* HCI device list */
-LIST_HEAD(hci_dev_list);
-DEFINE_RWLOCK(hci_dev_list_lock);
-
-/* HCI callback list */
-LIST_HEAD(hci_cb_list);
-DEFINE_RWLOCK(hci_cb_list_lock);
-
-/* HCI notifiers list */
-static ATOMIC_NOTIFIER_HEAD(hci_notifier);
-
-/* ---- HCI notifications ---- */
-
-int hci_register_notifier(struct notifier_block *nb)
-{
- return atomic_notifier_chain_register(&hci_notifier, nb);
-}
-
-int hci_unregister_notifier(struct notifier_block *nb)
-{
- return atomic_notifier_chain_unregister(&hci_notifier, nb);
-}
-
-static void hci_notify(struct hci_dev *hdev, int event)
-{
- atomic_notifier_call_chain(&hci_notifier, event, hdev);
-}
-
-/* ---- HCI requests ---- */
-
-void hci_req_complete(struct hci_dev *hdev, __u16 cmd, int result)
-{
- BT_DBG("%s command 0x%04x result 0x%2.2x", hdev->name, cmd, result);
-
- /* If this is the init phase check if the completed command matches
- * the last init command, and if not just return.
- */
- if (test_bit(HCI_INIT, &hdev->flags) && hdev->init_last_cmd != cmd) {
- struct hci_command_hdr *sent = (void *) hdev->sent_cmd->data;
- struct sk_buff *skb;
-
- /* Some CSR based controllers generate a spontaneous
- * reset complete event during init and any pending
- * command will never be completed. In such a case we
- * need to resend whatever was the last sent
- * command.
- */
-
- if (cmd != HCI_OP_RESET || sent->opcode == HCI_OP_RESET)
- return;
-
- skb = skb_clone(hdev->sent_cmd, GFP_ATOMIC);
- if (skb) {
- skb_queue_head(&hdev->cmd_q, skb);
- queue_work(hdev->workqueue, &hdev->cmd_work);
- }
-
- return;
- }
-
- if (hdev->req_status == HCI_REQ_PEND) {
- hdev->req_result = result;
- hdev->req_status = HCI_REQ_DONE;
- wake_up_interruptible(&hdev->req_wait_q);
- }
-}
-
-static void hci_req_cancel(struct hci_dev *hdev, int err)
-{
- BT_DBG("%s err 0x%2.2x", hdev->name, err);
-
- if (hdev->req_status == HCI_REQ_PEND) {
- hdev->req_result = err;
- hdev->req_status = HCI_REQ_CANCELED;
- wake_up_interruptible(&hdev->req_wait_q);
- }
-}
-
-/* Execute request and wait for completion. */
-static int __hci_request(struct hci_dev *hdev, void (*req)(struct hci_dev *hdev, unsigned long opt),
- unsigned long opt, __u32 timeout)
-{
- DECLARE_WAITQUEUE(wait, current);
- int err = 0;
-
- BT_DBG("%s start", hdev->name);
-
- hdev->req_status = HCI_REQ_PEND;
-
- add_wait_queue(&hdev->req_wait_q, &wait);
- set_current_state(TASK_INTERRUPTIBLE);
-
- req(hdev, opt);
- schedule_timeout(timeout);
-
- remove_wait_queue(&hdev->req_wait_q, &wait);
-
- if (signal_pending(current))
- return -EINTR;
-
- switch (hdev->req_status) {
- case HCI_REQ_DONE:
- err = -bt_to_errno(hdev->req_result);
- break;
-
- case HCI_REQ_CANCELED:
- err = -hdev->req_result;
- break;
-
- default:
- err = -ETIMEDOUT;
- break;
- }
-
- hdev->req_status = hdev->req_result = 0;
-
- BT_DBG("%s end: err %d", hdev->name, err);
-
- return err;
-}
-
-static inline int hci_request(struct hci_dev *hdev, void (*req)(struct hci_dev *hdev, unsigned long opt),
- unsigned long opt, __u32 timeout)
-{
- int ret;
-
- if (!test_bit(HCI_UP, &hdev->flags))
- return -ENETDOWN;
-
- /* Serialize all requests */
- hci_req_lock(hdev);
- ret = __hci_request(hdev, req, opt, timeout);
- hci_req_unlock(hdev);
-
- return ret;
-}
-
-static void hci_reset_req(struct hci_dev *hdev, unsigned long opt)
-{
- BT_DBG("%s %ld", hdev->name, opt);
-
- /* Reset device */
- set_bit(HCI_RESET, &hdev->flags);
- hci_send_cmd(hdev, HCI_OP_RESET, 0, NULL);
-}
-
-static void bredr_init(struct hci_dev *hdev)
-{
- struct hci_cp_delete_stored_link_key cp;
- __le16 param;
- __u8 flt_type;
-
- hdev->flow_ctl_mode = HCI_FLOW_CTL_MODE_PACKET_BASED;
-
- /* Mandatory initialization */
-
- /* Reset */
- if (!test_bit(HCI_QUIRK_NO_RESET, &hdev->quirks)) {
- set_bit(HCI_RESET, &hdev->flags);
- hci_send_cmd(hdev, HCI_OP_RESET, 0, NULL);
- }
-
- /* Read Local Supported Features */
- hci_send_cmd(hdev, HCI_OP_READ_LOCAL_FEATURES, 0, NULL);
-
- /* Read Local Version */
- hci_send_cmd(hdev, HCI_OP_READ_LOCAL_VERSION, 0, NULL);
-
- /* Read Buffer Size (ACL mtu, max pkt, etc.) */
- hci_send_cmd(hdev, HCI_OP_READ_BUFFER_SIZE, 0, NULL);
-
- /* Read BD Address */
- hci_send_cmd(hdev, HCI_OP_READ_BD_ADDR, 0, NULL);
-
- /* Read Class of Device */
- hci_send_cmd(hdev, HCI_OP_READ_CLASS_OF_DEV, 0, NULL);
-
- /* Read Local Name */
- hci_send_cmd(hdev, HCI_OP_READ_LOCAL_NAME, 0, NULL);
-
- /* Read Voice Setting */
- hci_send_cmd(hdev, HCI_OP_READ_VOICE_SETTING, 0, NULL);
-
- /* Optional initialization */
-
- /* Clear Event Filters */
- flt_type = HCI_FLT_CLEAR_ALL;
- hci_send_cmd(hdev, HCI_OP_SET_EVENT_FLT, 1, &flt_type);
-
- /* Connection accept timeout ~20 secs */
- param = cpu_to_le16(0x7d00);
- hci_send_cmd(hdev, HCI_OP_WRITE_CA_TIMEOUT, 2, &param);
-
- bacpy(&cp.bdaddr, BDADDR_ANY);
- cp.delete_all = 1;
- hci_send_cmd(hdev, HCI_OP_DELETE_STORED_LINK_KEY, sizeof(cp), &cp);
-}
-
-static void amp_init(struct hci_dev *hdev)
-{
- hdev->flow_ctl_mode = HCI_FLOW_CTL_MODE_BLOCK_BASED;
-
- /* Reset */
- hci_send_cmd(hdev, HCI_OP_RESET, 0, NULL);
-
- /* Read Local Version */
- hci_send_cmd(hdev, HCI_OP_READ_LOCAL_VERSION, 0, NULL);
-}
-
-static void hci_init_req(struct hci_dev *hdev, unsigned long opt)
-{
- struct sk_buff *skb;
-
- BT_DBG("%s %ld", hdev->name, opt);
-
- /* Driver initialization */
-
- /* Special commands */
- while ((skb = skb_dequeue(&hdev->driver_init))) {
- bt_cb(skb)->pkt_type = HCI_COMMAND_PKT;
- skb->dev = (void *) hdev;
-
- skb_queue_tail(&hdev->cmd_q, skb);
- queue_work(hdev->workqueue, &hdev->cmd_work);
- }
- skb_queue_purge(&hdev->driver_init);
-
- switch (hdev->dev_type) {
- case HCI_BREDR:
- bredr_init(hdev);
- break;
-
- case HCI_AMP:
- amp_init(hdev);
- break;
-
- default:
- BT_ERR("Unknown device type %d", hdev->dev_type);
- break;
- }
-
-}
-
-static void hci_le_init_req(struct hci_dev *hdev, unsigned long opt)
-{
- BT_DBG("%s", hdev->name);
-
- /* Read LE buffer size */
- hci_send_cmd(hdev, HCI_OP_LE_READ_BUFFER_SIZE, 0, NULL);
-}
-
-static void hci_scan_req(struct hci_dev *hdev, unsigned long opt)
-{
- __u8 scan = opt;
-
- BT_DBG("%s %x", hdev->name, scan);
-
- /* Inquiry and Page scans */
- hci_send_cmd(hdev, HCI_OP_WRITE_SCAN_ENABLE, 1, &scan);
-}
-
-static void hci_auth_req(struct hci_dev *hdev, unsigned long opt)
-{
- __u8 auth = opt;
-
- BT_DBG("%s %x", hdev->name, auth);
-
- /* Authentication */
- hci_send_cmd(hdev, HCI_OP_WRITE_AUTH_ENABLE, 1, &auth);
-}
-
-static void hci_encrypt_req(struct hci_dev *hdev, unsigned long opt)
-{
- __u8 encrypt = opt;
-
- BT_DBG("%s %x", hdev->name, encrypt);
-
- /* Encryption */
- hci_send_cmd(hdev, HCI_OP_WRITE_ENCRYPT_MODE, 1, &encrypt);
-}
-
-static void hci_linkpol_req(struct hci_dev *hdev, unsigned long opt)
-{
- __le16 policy = cpu_to_le16(opt);
-
- BT_DBG("%s %x", hdev->name, policy);
-
- /* Default link policy */
- hci_send_cmd(hdev, HCI_OP_WRITE_DEF_LINK_POLICY, 2, &policy);
-}
-
-/* Get HCI device by index.
- * Device is held on return. */
-struct hci_dev *hci_dev_get(int index)
-{
- struct hci_dev *hdev = NULL, *d;
-
- BT_DBG("%d", index);
-
- if (index < 0)
- return NULL;
-
- read_lock(&hci_dev_list_lock);
- list_for_each_entry(d, &hci_dev_list, list) {
- if (d->id == index) {
- hdev = hci_dev_hold(d);
- break;
- }
- }
- read_unlock(&hci_dev_list_lock);
- return hdev;
-}
-
-/* ---- Inquiry support ---- */
-
-bool hci_discovery_active(struct hci_dev *hdev)
-{
- struct discovery_state *discov = &hdev->discovery;
-
- switch (discov->state) {
- case DISCOVERY_FINDING:
- case DISCOVERY_RESOLVING:
- return true;
-
- default:
- return false;
- }
-}
-
-void hci_discovery_set_state(struct hci_dev *hdev, int state)
-{
- BT_DBG("%s state %u -> %u", hdev->name, hdev->discovery.state, state);
-
- if (hdev->discovery.state == state)
- return;
-
- switch (state) {
- case DISCOVERY_STOPPED:
- if (hdev->discovery.state != DISCOVERY_STARTING)
- mgmt_discovering(hdev, 0);
- hdev->discovery.type = 0;
- break;
- case DISCOVERY_STARTING:
- break;
- case DISCOVERY_FINDING:
- mgmt_discovering(hdev, 1);
- break;
- case DISCOVERY_RESOLVING:
- break;
- case DISCOVERY_STOPPING:
- break;
- }
-
- hdev->discovery.state = state;
-}
-
-static void inquiry_cache_flush(struct hci_dev *hdev)
-{
- struct discovery_state *cache = &hdev->discovery;
- struct inquiry_entry *p, *n;
-
- list_for_each_entry_safe(p, n, &cache->all, all) {
- list_del(&p->all);
- kfree(p);
- }
-
- INIT_LIST_HEAD(&cache->unknown);
- INIT_LIST_HEAD(&cache->resolve);
-}
-
-struct inquiry_entry *hci_inquiry_cache_lookup(struct hci_dev *hdev, bdaddr_t *bdaddr)
-{
- struct discovery_state *cache = &hdev->discovery;
- struct inquiry_entry *e;
-
- BT_DBG("cache %p, %s", cache, batostr(bdaddr));
-
- list_for_each_entry(e, &cache->all, all) {
- if (!bacmp(&e->data.bdaddr, bdaddr))
- return e;
- }
-
- return NULL;
-}
-
-struct inquiry_entry *hci_inquiry_cache_lookup_unknown(struct hci_dev *hdev,
- bdaddr_t *bdaddr)
-{
- struct discovery_state *cache = &hdev->discovery;
- struct inquiry_entry *e;
-
- BT_DBG("cache %p, %s", cache, batostr(bdaddr));
-
- list_for_each_entry(e, &cache->unknown, list) {
- if (!bacmp(&e->data.bdaddr, bdaddr))
- return e;
- }
-
- return NULL;
-}
-
-struct inquiry_entry *hci_inquiry_cache_lookup_resolve(struct hci_dev *hdev,
- bdaddr_t *bdaddr,
- int state)
-{
- struct discovery_state *cache = &hdev->discovery;
- struct inquiry_entry *e;
-
- BT_DBG("cache %p bdaddr %s state %d", cache, batostr(bdaddr), state);
-
- list_for_each_entry(e, &cache->resolve, list) {
- if (!bacmp(bdaddr, BDADDR_ANY) && e->name_state == state)
- return e;
- if (!bacmp(&e->data.bdaddr, bdaddr))
- return e;
- }
-
- return NULL;
-}
-
-void hci_inquiry_cache_update_resolve(struct hci_dev *hdev,
- struct inquiry_entry *ie)
-{
- struct discovery_state *cache = &hdev->discovery;
- struct list_head *pos = &cache->resolve;
- struct inquiry_entry *p;
-
- list_del(&ie->list);
-
- list_for_each_entry(p, &cache->resolve, list) {
- if (p->name_state != NAME_PENDING &&
- abs(p->data.rssi) >= abs(ie->data.rssi))
- break;
- pos = &p->list;
- }
-
- list_add(&ie->list, pos);
-}
-
-bool hci_inquiry_cache_update(struct hci_dev *hdev, struct inquiry_data *data,
- bool name_known, bool *ssp)
-{
- struct discovery_state *cache = &hdev->discovery;
- struct inquiry_entry *ie;
-
- BT_DBG("cache %p, %s", cache, batostr(&data->bdaddr));
-
- if (ssp)
- *ssp = data->ssp_mode;
-
- ie = hci_inquiry_cache_lookup(hdev, &data->bdaddr);
- if (ie) {
- if (ie->data.ssp_mode && ssp)
- *ssp = true;
-
- if (ie->name_state == NAME_NEEDED &&
- data->rssi != ie->data.rssi) {
- ie->data.rssi = data->rssi;
- hci_inquiry_cache_update_resolve(hdev, ie);
- }
-
- goto update;
- }
-
- /* Entry not in the cache. Add new one. */
- ie = kzalloc(sizeof(struct inquiry_entry), GFP_ATOMIC);
- if (!ie)
- return false;
-
- list_add(&ie->all, &cache->all);
-
- if (name_known) {
- ie->name_state = NAME_KNOWN;
- } else {
- ie->name_state = NAME_NOT_KNOWN;
- list_add(&ie->list, &cache->unknown);
- }
-
-update:
- if (name_known && ie->name_state != NAME_KNOWN &&
- ie->name_state != NAME_PENDING) {
- ie->name_state = NAME_KNOWN;
- list_del(&ie->list);
- }
-
- memcpy(&ie->data, data, sizeof(*data));
- ie->timestamp = jiffies;
- cache->timestamp = jiffies;
-
- if (ie->name_state == NAME_NOT_KNOWN)
- return false;
-
- return true;
-}
-
-static int inquiry_cache_dump(struct hci_dev *hdev, int num, __u8 *buf)
-{
- struct discovery_state *cache = &hdev->discovery;
- struct inquiry_info *info = (struct inquiry_info *) buf;
- struct inquiry_entry *e;
- int copied = 0;
-
- list_for_each_entry(e, &cache->all, all) {
- struct inquiry_data *data = &e->data;
-
- if (copied >= num)
- break;
-
- bacpy(&info->bdaddr, &data->bdaddr);
- info->pscan_rep_mode = data->pscan_rep_mode;
- info->pscan_period_mode = data->pscan_period_mode;
- info->pscan_mode = data->pscan_mode;
- memcpy(info->dev_class, data->dev_class, 3);
- info->clock_offset = data->clock_offset;
-
- info++;
- copied++;
- }
-
- BT_DBG("cache %p, copied %d", cache, copied);
- return copied;
-}
-
-static void hci_inq_req(struct hci_dev *hdev, unsigned long opt)
-{
- struct hci_inquiry_req *ir = (struct hci_inquiry_req *) opt;
- struct hci_cp_inquiry cp;
-
- BT_DBG("%s", hdev->name);
-
- if (test_bit(HCI_INQUIRY, &hdev->flags))
- return;
-
- /* Start Inquiry */
- memcpy(&cp.lap, &ir->lap, 3);
- cp.length = ir->length;
- cp.num_rsp = ir->num_rsp;
- hci_send_cmd(hdev, HCI_OP_INQUIRY, sizeof(cp), &cp);
-}
-
-int hci_inquiry(void __user *arg)
-{
- __u8 __user *ptr = arg;
- struct hci_inquiry_req ir;
- struct hci_dev *hdev;
- int err = 0, do_inquiry = 0, max_rsp;
- long timeo;
- __u8 *buf;
-
- if (copy_from_user(&ir, ptr, sizeof(ir)))
- return -EFAULT;
-
- hdev = hci_dev_get(ir.dev_id);
- if (!hdev)
- return -ENODEV;
-
- hci_dev_lock(hdev);
- if (inquiry_cache_age(hdev) > INQUIRY_CACHE_AGE_MAX ||
- inquiry_cache_empty(hdev) ||
- ir.flags & IREQ_CACHE_FLUSH) {
- inquiry_cache_flush(hdev);
- do_inquiry = 1;
- }
- hci_dev_unlock(hdev);
-
- timeo = ir.length * msecs_to_jiffies(2000);
-
- if (do_inquiry) {
- err = hci_request(hdev, hci_inq_req, (unsigned long)&ir, timeo);
- if (err < 0)
- goto done;
- }
-
- /* for unlimited number of responses we will use buffer with 255 entries */
- max_rsp = (ir.num_rsp == 0) ? 255 : ir.num_rsp;
-
- /* cache_dump can't sleep. Therefore we allocate temp buffer and then
- * copy it to the user space.
- */
- buf = kmalloc(sizeof(struct inquiry_info) * max_rsp, GFP_KERNEL);
- if (!buf) {
- err = -ENOMEM;
- goto done;
- }
-
- hci_dev_lock(hdev);
- ir.num_rsp = inquiry_cache_dump(hdev, max_rsp, buf);
- hci_dev_unlock(hdev);
-
- BT_DBG("num_rsp %d", ir.num_rsp);
-
- if (!copy_to_user(ptr, &ir, sizeof(ir))) {
- ptr += sizeof(ir);
- if (copy_to_user(ptr, buf, sizeof(struct inquiry_info) *
- ir.num_rsp))
- err = -EFAULT;
- } else
- err = -EFAULT;
-
- kfree(buf);
-
-done:
- hci_dev_put(hdev);
- return err;
-}
-
-/* ---- HCI ioctl helpers ---- */
-
-int hci_dev_open(__u16 dev)
-{
- struct hci_dev *hdev;
- int ret = 0;
-
- hdev = hci_dev_get(dev);
- if (!hdev)
- return -ENODEV;
-
- BT_DBG("%s %p", hdev->name, hdev);
-
- hci_req_lock(hdev);
-
- if (test_bit(HCI_UNREGISTER, &hdev->dev_flags)) {
- ret = -ENODEV;
- goto done;
- }
-
- if (hdev->rfkill && rfkill_blocked(hdev->rfkill)) {
- ret = -ERFKILL;
- goto done;
- }
-
- if (test_bit(HCI_UP, &hdev->flags)) {
- ret = -EALREADY;
- goto done;
- }
-
- if (test_bit(HCI_QUIRK_RAW_DEVICE, &hdev->quirks))
- set_bit(HCI_RAW, &hdev->flags);
-
- /* Treat all non BR/EDR controllers as raw devices if
- enable_hs is not set */
- if (hdev->dev_type != HCI_BREDR && !enable_hs)
- set_bit(HCI_RAW, &hdev->flags);
-
- if (hdev->open(hdev)) {
- ret = -EIO;
- goto done;
- }
-
- if (!test_bit(HCI_RAW, &hdev->flags)) {
- atomic_set(&hdev->cmd_cnt, 1);
- set_bit(HCI_INIT, &hdev->flags);
- hdev->init_last_cmd = 0;
-
- ret = __hci_request(hdev, hci_init_req, 0,
- msecs_to_jiffies(HCI_INIT_TIMEOUT));
-
- if (lmp_host_le_capable(hdev))
- ret = __hci_request(hdev, hci_le_init_req, 0,
- msecs_to_jiffies(HCI_INIT_TIMEOUT));
-
- clear_bit(HCI_INIT, &hdev->flags);
- }
-
- if (!ret) {
- hci_dev_hold(hdev);
- set_bit(HCI_UP, &hdev->flags);
- hci_notify(hdev, HCI_DEV_UP);
- if (!test_bit(HCI_SETUP, &hdev->dev_flags)) {
- hci_dev_lock(hdev);
- mgmt_powered(hdev, 1);
- hci_dev_unlock(hdev);
- }
- } else {
- /* Init failed, cleanup */
- flush_work(&hdev->tx_work);
- flush_work(&hdev->cmd_work);
- flush_work(&hdev->rx_work);
-
- skb_queue_purge(&hdev->cmd_q);
- skb_queue_purge(&hdev->rx_q);
-
- if (hdev->flush)
- hdev->flush(hdev);
-
- if (hdev->sent_cmd) {
- kfree_skb(hdev->sent_cmd);
- hdev->sent_cmd = NULL;
- }
-
- hdev->close(hdev);
- hdev->flags = 0;
- }
-
-done:
- hci_req_unlock(hdev);
- hci_dev_put(hdev);
- return ret;
-}
-
-static int hci_dev_do_close(struct hci_dev *hdev)
-{
- BT_DBG("%s %p", hdev->name, hdev);
-
- cancel_work_sync(&hdev->le_scan);
-
- hci_req_cancel(hdev, ENODEV);
- hci_req_lock(hdev);
-
- if (!test_and_clear_bit(HCI_UP, &hdev->flags)) {
- del_timer_sync(&hdev->cmd_timer);
- hci_req_unlock(hdev);
- return 0;
- }
-
- /* Flush RX and TX works */
- flush_work(&hdev->tx_work);
- flush_work(&hdev->rx_work);
-
- if (hdev->discov_timeout > 0) {
- cancel_delayed_work(&hdev->discov_off);
- hdev->discov_timeout = 0;
- clear_bit(HCI_DISCOVERABLE, &hdev->dev_flags);
- }
-
- if (test_and_clear_bit(HCI_SERVICE_CACHE, &hdev->dev_flags))
- cancel_delayed_work(&hdev->service_cache);
-
- cancel_delayed_work_sync(&hdev->le_scan_disable);
-
- hci_dev_lock(hdev);
- inquiry_cache_flush(hdev);
- hci_conn_hash_flush(hdev);
- hci_dev_unlock(hdev);
-
- hci_notify(hdev, HCI_DEV_DOWN);
-
- if (hdev->flush)
- hdev->flush(hdev);
-
- /* Reset device */
- skb_queue_purge(&hdev->cmd_q);
- atomic_set(&hdev->cmd_cnt, 1);
- if (!test_bit(HCI_RAW, &hdev->flags) &&
- test_bit(HCI_QUIRK_NO_RESET, &hdev->quirks)) {
- set_bit(HCI_INIT, &hdev->flags);
- __hci_request(hdev, hci_reset_req, 0,
- msecs_to_jiffies(250));
- clear_bit(HCI_INIT, &hdev->flags);
- }
-
- /* flush cmd work */
- flush_work(&hdev->cmd_work);
-
- /* Drop queues */
- skb_queue_purge(&hdev->rx_q);
- skb_queue_purge(&hdev->cmd_q);
- skb_queue_purge(&hdev->raw_q);
-
- /* Drop last sent command */
- if (hdev->sent_cmd) {
- del_timer_sync(&hdev->cmd_timer);
- kfree_skb(hdev->sent_cmd);
- hdev->sent_cmd = NULL;
- }
-
- /* After this point our queues are empty
- * and no tasks are scheduled. */
- hdev->close(hdev);
-
- if (!test_and_clear_bit(HCI_AUTO_OFF, &hdev->dev_flags)) {
- hci_dev_lock(hdev);
- mgmt_powered(hdev, 0);
- hci_dev_unlock(hdev);
- }
-
- /* Clear flags */
- hdev->flags = 0;
-
- memset(hdev->eir, 0, sizeof(hdev->eir));
- memset(hdev->dev_class, 0, sizeof(hdev->dev_class));
-
- hci_req_unlock(hdev);
-
- hci_dev_put(hdev);
- return 0;
-}
-
-int hci_dev_close(__u16 dev)
-{
- struct hci_dev *hdev;
- int err;
-
- hdev = hci_dev_get(dev);
- if (!hdev)
- return -ENODEV;
-
- if (test_and_clear_bit(HCI_AUTO_OFF, &hdev->dev_flags))
- cancel_delayed_work(&hdev->power_off);
-
- err = hci_dev_do_close(hdev);
-
- hci_dev_put(hdev);
- return err;
-}
-
-int hci_dev_reset(__u16 dev)
-{
- struct hci_dev *hdev;
- int ret = 0;
-
- hdev = hci_dev_get(dev);
- if (!hdev)
- return -ENODEV;
-
- hci_req_lock(hdev);
-
- if (!test_bit(HCI_UP, &hdev->flags))
- goto done;
-
- /* Drop queues */
- skb_queue_purge(&hdev->rx_q);
- skb_queue_purge(&hdev->cmd_q);
-
- hci_dev_lock(hdev);
- inquiry_cache_flush(hdev);
- hci_conn_hash_flush(hdev);
- hci_dev_unlock(hdev);
-
- if (hdev->flush)
- hdev->flush(hdev);
-
- atomic_set(&hdev->cmd_cnt, 1);
- hdev->acl_cnt = 0; hdev->sco_cnt = 0; hdev->le_cnt = 0;
-
- if (!test_bit(HCI_RAW, &hdev->flags))
- ret = __hci_request(hdev, hci_reset_req, 0,
- msecs_to_jiffies(HCI_INIT_TIMEOUT));
-
-done:
- hci_req_unlock(hdev);
- hci_dev_put(hdev);
- return ret;
-}
-
-int hci_dev_reset_stat(__u16 dev)
-{
- struct hci_dev *hdev;
- int ret = 0;
-
- hdev = hci_dev_get(dev);
- if (!hdev)
- return -ENODEV;
-
- memset(&hdev->stat, 0, sizeof(struct hci_dev_stats));
-
- hci_dev_put(hdev);
-
- return ret;
-}
-
-int hci_dev_cmd(unsigned int cmd, void __user *arg)
-{
- struct hci_dev *hdev;
- struct hci_dev_req dr;
- int err = 0;
-
- if (copy_from_user(&dr, arg, sizeof(dr)))
- return -EFAULT;
-
- hdev = hci_dev_get(dr.dev_id);
- if (!hdev)
- return -ENODEV;
-
- switch (cmd) {
- case HCISETAUTH:
- err = hci_request(hdev, hci_auth_req, dr.dev_opt,
- msecs_to_jiffies(HCI_INIT_TIMEOUT));
- break;
-
- case HCISETENCRYPT:
- if (!lmp_encrypt_capable(hdev)) {
- err = -EOPNOTSUPP;
- break;
- }
-
- if (!test_bit(HCI_AUTH, &hdev->flags)) {
- /* Auth must be enabled first */
- err = hci_request(hdev, hci_auth_req, dr.dev_opt,
- msecs_to_jiffies(HCI_INIT_TIMEOUT));
- if (err)
- break;
- }
-
- err = hci_request(hdev, hci_encrypt_req, dr.dev_opt,
- msecs_to_jiffies(HCI_INIT_TIMEOUT));
- break;
-
- case HCISETSCAN:
- err = hci_request(hdev, hci_scan_req, dr.dev_opt,
- msecs_to_jiffies(HCI_INIT_TIMEOUT));
- break;
-
- case HCISETLINKPOL:
- err = hci_request(hdev, hci_linkpol_req, dr.dev_opt,
- msecs_to_jiffies(HCI_INIT_TIMEOUT));
- break;
-
- case HCISETLINKMODE:
- hdev->link_mode = ((__u16) dr.dev_opt) &
- (HCI_LM_MASTER | HCI_LM_ACCEPT);
- break;
-
- case HCISETPTYPE:
- hdev->pkt_type = (__u16) dr.dev_opt;
- break;
-
- case HCISETACLMTU:
- hdev->acl_mtu = *((__u16 *) &dr.dev_opt + 1);
- hdev->acl_pkts = *((__u16 *) &dr.dev_opt + 0);
- break;
-
- case HCISETSCOMTU:
- hdev->sco_mtu = *((__u16 *) &dr.dev_opt + 1);
- hdev->sco_pkts = *((__u16 *) &dr.dev_opt + 0);
- break;
-
- default:
- err = -EINVAL;
- break;
- }
-
- hci_dev_put(hdev);
- return err;
-}
-
-int hci_get_dev_list(void __user *arg)
-{
- struct hci_dev *hdev;
- struct hci_dev_list_req *dl;
- struct hci_dev_req *dr;
- int n = 0, size, err;
- __u16 dev_num;
-
- if (get_user(dev_num, (__u16 __user *) arg))
- return -EFAULT;
-
- if (!dev_num || dev_num > (PAGE_SIZE * 2) / sizeof(*dr))
- return -EINVAL;
-
- size = sizeof(*dl) + dev_num * sizeof(*dr);
-
- dl = kzalloc(size, GFP_KERNEL);
- if (!dl)
- return -ENOMEM;
-
- dr = dl->dev_req;
-
- read_lock(&hci_dev_list_lock);
- list_for_each_entry(hdev, &hci_dev_list, list) {
- if (test_and_clear_bit(HCI_AUTO_OFF, &hdev->dev_flags))
- cancel_delayed_work(&hdev->power_off);
-
- if (!test_bit(HCI_MGMT, &hdev->dev_flags))
- set_bit(HCI_PAIRABLE, &hdev->dev_flags);
-
- (dr + n)->dev_id = hdev->id;
- (dr + n)->dev_opt = hdev->flags;
-
- if (++n >= dev_num)
- break;
- }
- read_unlock(&hci_dev_list_lock);
-
- dl->dev_num = n;
- size = sizeof(*dl) + n * sizeof(*dr);
-
- err = copy_to_user(arg, dl, size);
- kfree(dl);
-
- return err ? -EFAULT : 0;
-}
-
-int hci_get_dev_info(void __user *arg)
-{
- struct hci_dev *hdev;
- struct hci_dev_info di;
- int err = 0;
-
- if (copy_from_user(&di, arg, sizeof(di)))
- return -EFAULT;
-
- hdev = hci_dev_get(di.dev_id);
- if (!hdev)
- return -ENODEV;
-
- if (test_and_clear_bit(HCI_AUTO_OFF, &hdev->dev_flags))
- cancel_delayed_work_sync(&hdev->power_off);
-
- if (!test_bit(HCI_MGMT, &hdev->dev_flags))
- set_bit(HCI_PAIRABLE, &hdev->dev_flags);
-
- strcpy(di.name, hdev->name);
- di.bdaddr = hdev->bdaddr;
- di.type = (hdev->bus & 0x0f) | (hdev->dev_type << 4);
- di.flags = hdev->flags;
- di.pkt_type = hdev->pkt_type;
- di.acl_mtu = hdev->acl_mtu;
- di.acl_pkts = hdev->acl_pkts;
- di.sco_mtu = hdev->sco_mtu;
- di.sco_pkts = hdev->sco_pkts;
- di.link_policy = hdev->link_policy;
- di.link_mode = hdev->link_mode;
-
- memcpy(&di.stat, &hdev->stat, sizeof(di.stat));
- memcpy(&di.features, &hdev->features, sizeof(di.features));
-
- if (copy_to_user(arg, &di, sizeof(di)))
- err = -EFAULT;
-
- hci_dev_put(hdev);
-
- return err;
-}
-
-/* ---- Interface to HCI drivers ---- */
-
-static int hci_rfkill_set_block(void *data, bool blocked)
-{
- struct hci_dev *hdev = data;
-
- BT_DBG("%p name %s blocked %d", hdev, hdev->name, blocked);
-
- if (!blocked)
- return 0;
-
- hci_dev_do_close(hdev);
-
- return 0;
-}
-
-static const struct rfkill_ops hci_rfkill_ops = {
- .set_block = hci_rfkill_set_block,
-};
-
-/* Alloc HCI device */
-struct hci_dev *hci_alloc_dev(void)
-{
- struct hci_dev *hdev;
-
- hdev = kzalloc(sizeof(struct hci_dev), GFP_KERNEL);
- if (!hdev)
- return NULL;
-
- hci_init_sysfs(hdev);
- skb_queue_head_init(&hdev->driver_init);
-
- return hdev;
-}
-EXPORT_SYMBOL(hci_alloc_dev);
-
-/* Free HCI device */
-void hci_free_dev(struct hci_dev *hdev)
-{
- skb_queue_purge(&hdev->driver_init);
-
- /* will free via device release */
- put_device(&hdev->dev);
-}
-EXPORT_SYMBOL(hci_free_dev);
-
-static void hci_power_on(struct work_struct *work)
-{
- struct hci_dev *hdev = container_of(work, struct hci_dev, power_on);
-
- BT_DBG("%s", hdev->name);
-
- if (hci_dev_open(hdev->id) < 0)
- return;
-
- if (test_bit(HCI_AUTO_OFF, &hdev->dev_flags))
- schedule_delayed_work(&hdev->power_off,
- msecs_to_jiffies(AUTO_OFF_TIMEOUT));
-
- if (test_and_clear_bit(HCI_SETUP, &hdev->dev_flags))
- mgmt_index_added(hdev);
-}
-
-static void hci_power_off(struct work_struct *work)
-{
- struct hci_dev *hdev = container_of(work, struct hci_dev,
- power_off.work);
-
- BT_DBG("%s", hdev->name);
-
- hci_dev_do_close(hdev);
-}
-
-static void hci_discov_off(struct work_struct *work)
-{
- struct hci_dev *hdev;
- u8 scan = SCAN_PAGE;
-
- hdev = container_of(work, struct hci_dev, discov_off.work);
-
- BT_DBG("%s", hdev->name);
-
- hci_dev_lock(hdev);
-
- hci_send_cmd(hdev, HCI_OP_WRITE_SCAN_ENABLE, sizeof(scan), &scan);
-
- hdev->discov_timeout = 0;
-
- hci_dev_unlock(hdev);
-}
-
-int hci_uuids_clear(struct hci_dev *hdev)
-{
- struct list_head *p, *n;
-
- list_for_each_safe(p, n, &hdev->uuids) {
- struct bt_uuid *uuid;
-
- uuid = list_entry(p, struct bt_uuid, list);
-
- list_del(p);
- kfree(uuid);
- }
-
- return 0;
-}
-
-int hci_link_keys_clear(struct hci_dev *hdev)
-{
- struct list_head *p, *n;
-
- list_for_each_safe(p, n, &hdev->link_keys) {
- struct link_key *key;
-
- key = list_entry(p, struct link_key, list);
-
- list_del(p);
- kfree(key);
- }
-
- return 0;
-}
-
-int hci_smp_ltks_clear(struct hci_dev *hdev)
-{
- struct smp_ltk *k, *tmp;
-
- list_for_each_entry_safe(k, tmp, &hdev->long_term_keys, list) {
- list_del(&k->list);
- kfree(k);
- }
-
- return 0;
-}
-
-struct link_key *hci_find_link_key(struct hci_dev *hdev, bdaddr_t *bdaddr)
-{
- struct link_key *k;
-
- list_for_each_entry(k, &hdev->link_keys, list)
- if (bacmp(bdaddr, &k->bdaddr) == 0)
- return k;
-
- return NULL;
-}
-
-static bool hci_persistent_key(struct hci_dev *hdev, struct hci_conn *conn,
- u8 key_type, u8 old_key_type)
-{
- /* Legacy key */
- if (key_type < 0x03)
- return true;
-
- /* Debug keys are insecure so don't store them persistently */
- if (key_type == HCI_LK_DEBUG_COMBINATION)
- return false;
-
- /* Changed combination key and there's no previous one */
- if (key_type == HCI_LK_CHANGED_COMBINATION && old_key_type == 0xff)
- return false;
-
- /* Security mode 3 case */
- if (!conn)
- return true;
-
- /* Neither local nor remote side had no-bonding as requirement */
- if (conn->auth_type > 0x01 && conn->remote_auth > 0x01)
- return true;
-
- /* Local side had dedicated bonding as requirement */
- if (conn->auth_type == 0x02 || conn->auth_type == 0x03)
- return true;
-
- /* Remote side had dedicated bonding as requirement */
- if (conn->remote_auth == 0x02 || conn->remote_auth == 0x03)
- return true;
-
- /* If none of the above criteria match, then don't store the key
- * persistently */
- return false;
-}
-
-struct smp_ltk *hci_find_ltk(struct hci_dev *hdev, __le16 ediv, u8 rand[8])
-{
- struct smp_ltk *k;
-
- list_for_each_entry(k, &hdev->long_term_keys, list) {
- if (k->ediv != ediv ||
- memcmp(rand, k->rand, sizeof(k->rand)))
- continue;
-
- return k;
- }
-
- return NULL;
-}
-EXPORT_SYMBOL(hci_find_ltk);
-
-struct smp_ltk *hci_find_ltk_by_addr(struct hci_dev *hdev, bdaddr_t *bdaddr,
- u8 addr_type)
-{
- struct smp_ltk *k;
-
- list_for_each_entry(k, &hdev->long_term_keys, list)
- if (addr_type == k->bdaddr_type &&
- bacmp(bdaddr, &k->bdaddr) == 0)
- return k;
-
- return NULL;
-}
-EXPORT_SYMBOL(hci_find_ltk_by_addr);
-
-int hci_add_link_key(struct hci_dev *hdev, struct hci_conn *conn, int new_key,
- bdaddr_t *bdaddr, u8 *val, u8 type, u8 pin_len)
-{
- struct link_key *key, *old_key;
- u8 old_key_type;
- bool persistent;
-
- old_key = hci_find_link_key(hdev, bdaddr);
- if (old_key) {
- old_key_type = old_key->type;
- key = old_key;
- } else {
- old_key_type = conn ? conn->key_type : 0xff;
- key = kzalloc(sizeof(*key), GFP_ATOMIC);
- if (!key)
- return -ENOMEM;
- list_add(&key->list, &hdev->link_keys);
- }
-
- BT_DBG("%s key for %s type %u", hdev->name, batostr(bdaddr), type);
-
- /* Some buggy controller combinations generate a changed
- * combination key for legacy pairing even when there's no
- * previous key */
- if (type == HCI_LK_CHANGED_COMBINATION &&
- (!conn || conn->remote_auth == 0xff) &&
- old_key_type == 0xff) {
- type = HCI_LK_COMBINATION;
- if (conn)
- conn->key_type = type;
- }
-
- bacpy(&key->bdaddr, bdaddr);
- memcpy(key->val, val, 16);
- key->pin_len = pin_len;
-
- if (type == HCI_LK_CHANGED_COMBINATION)
- key->type = old_key_type;
- else
- key->type = type;
-
- if (!new_key)
- return 0;
-
- persistent = hci_persistent_key(hdev, conn, type, old_key_type);
-
- mgmt_new_link_key(hdev, key, persistent);
-
- if (conn)
- conn->flush_key = !persistent;
-
- return 0;
-}
-
-int hci_add_ltk(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 addr_type, u8 type,
- int new_key, u8 authenticated, u8 tk[16], u8 enc_size, u16
- ediv, u8 rand[8])
-{
- struct smp_ltk *key, *old_key;
-
- if (!(type & HCI_SMP_STK) && !(type & HCI_SMP_LTK))
- return 0;
-
- old_key = hci_find_ltk_by_addr(hdev, bdaddr, addr_type);
- if (old_key)
- key = old_key;
- else {
- key = kzalloc(sizeof(*key), GFP_ATOMIC);
- if (!key)
- return -ENOMEM;
- list_add(&key->list, &hdev->long_term_keys);
- }
-
- bacpy(&key->bdaddr, bdaddr);
- key->bdaddr_type = addr_type;
- memcpy(key->val, tk, sizeof(key->val));
- key->authenticated = authenticated;
- key->ediv = ediv;
- key->enc_size = enc_size;
- key->type = type;
- memcpy(key->rand, rand, sizeof(key->rand));
-
- if (!new_key)
- return 0;
-
- if (type & HCI_SMP_LTK)
- mgmt_new_ltk(hdev, key, 1);
-
- return 0;
-}
-
-int hci_remove_link_key(struct hci_dev *hdev, bdaddr_t *bdaddr)
-{
- struct link_key *key;
-
- key = hci_find_link_key(hdev, bdaddr);
- if (!key)
- return -ENOENT;
-
- BT_DBG("%s removing %s", hdev->name, batostr(bdaddr));
-
- list_del(&key->list);
- kfree(key);
-
- return 0;
-}
-
-int hci_remove_ltk(struct hci_dev *hdev, bdaddr_t *bdaddr)
-{
- struct smp_ltk *k, *tmp;
-
- list_for_each_entry_safe(k, tmp, &hdev->long_term_keys, list) {
- if (bacmp(bdaddr, &k->bdaddr))
- continue;
-
- BT_DBG("%s removing %s", hdev->name, batostr(bdaddr));
-
- list_del(&k->list);
- kfree(k);
- }
-
- return 0;
-}
-
-/* HCI command timer function */
-static void hci_cmd_timer(unsigned long arg)
-{
- struct hci_dev *hdev = (void *) arg;
-
- BT_ERR("%s command tx timeout", hdev->name);
- atomic_set(&hdev->cmd_cnt, 1);
- queue_work(hdev->workqueue, &hdev->cmd_work);
-}
-
-struct oob_data *hci_find_remote_oob_data(struct hci_dev *hdev,
- bdaddr_t *bdaddr)
-{
- struct oob_data *data;
-
- list_for_each_entry(data, &hdev->remote_oob_data, list)
- if (bacmp(bdaddr, &data->bdaddr) == 0)
- return data;
-
- return NULL;
-}
-
-int hci_remove_remote_oob_data(struct hci_dev *hdev, bdaddr_t *bdaddr)
-{
- struct oob_data *data;
-
- data = hci_find_remote_oob_data(hdev, bdaddr);
- if (!data)
- return -ENOENT;
-
- BT_DBG("%s removing %s", hdev->name, batostr(bdaddr));
-
- list_del(&data->list);
- kfree(data);
-
- return 0;
-}
-
-int hci_remote_oob_data_clear(struct hci_dev *hdev)
-{
- struct oob_data *data, *n;
-
- list_for_each_entry_safe(data, n, &hdev->remote_oob_data, list) {
- list_del(&data->list);
- kfree(data);
- }
-
- return 0;
-}
-
-int hci_add_remote_oob_data(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 *hash,
- u8 *randomizer)
-{
- struct oob_data *data;
-
- data = hci_find_remote_oob_data(hdev, bdaddr);
-
- if (!data) {
- data = kmalloc(sizeof(*data), GFP_ATOMIC);
- if (!data)
- return -ENOMEM;
-
- bacpy(&data->bdaddr, bdaddr);
- list_add(&data->list, &hdev->remote_oob_data);
- }
-
- memcpy(data->hash, hash, sizeof(data->hash));
- memcpy(data->randomizer, randomizer, sizeof(data->randomizer));
-
- BT_DBG("%s for %s", hdev->name, batostr(bdaddr));
-
- return 0;
-}
-
-struct bdaddr_list *hci_blacklist_lookup(struct hci_dev *hdev, bdaddr_t *bdaddr)
-{
- struct bdaddr_list *b;
-
- list_for_each_entry(b, &hdev->blacklist, list)
- if (bacmp(bdaddr, &b->bdaddr) == 0)
- return b;
-
- return NULL;
-}
-
-int hci_blacklist_clear(struct hci_dev *hdev)
-{
- struct list_head *p, *n;
-
- list_for_each_safe(p, n, &hdev->blacklist) {
- struct bdaddr_list *b;
-
- b = list_entry(p, struct bdaddr_list, list);
-
- list_del(p);
- kfree(b);
- }
-
- return 0;
-}
-
-int hci_blacklist_add(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 type)
-{
- struct bdaddr_list *entry;
-
- if (bacmp(bdaddr, BDADDR_ANY) == 0)
- return -EBADF;
-
- if (hci_blacklist_lookup(hdev, bdaddr))
- return -EEXIST;
-
- entry = kzalloc(sizeof(struct bdaddr_list), GFP_KERNEL);
- if (!entry)
- return -ENOMEM;
-
- bacpy(&entry->bdaddr, bdaddr);
-
- list_add(&entry->list, &hdev->blacklist);
-
- return mgmt_device_blocked(hdev, bdaddr, type);
-}
-
-int hci_blacklist_del(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 type)
-{
- struct bdaddr_list *entry;
-
- if (bacmp(bdaddr, BDADDR_ANY) == 0)
- return hci_blacklist_clear(hdev);
-
- entry = hci_blacklist_lookup(hdev, bdaddr);
- if (!entry)
- return -ENOENT;
-
- list_del(&entry->list);
- kfree(entry);
-
- return mgmt_device_unblocked(hdev, bdaddr, type);
-}
-
-static void hci_clear_adv_cache(struct work_struct *work)
-{
- struct hci_dev *hdev = container_of(work, struct hci_dev,
- adv_work.work);
-
- hci_dev_lock(hdev);
-
- hci_adv_entries_clear(hdev);
-
- hci_dev_unlock(hdev);
-}
-
-int hci_adv_entries_clear(struct hci_dev *hdev)
-{
- struct adv_entry *entry, *tmp;
-
- list_for_each_entry_safe(entry, tmp, &hdev->adv_entries, list) {
- list_del(&entry->list);
- kfree(entry);
- }
-
- BT_DBG("%s adv cache cleared", hdev->name);
-
- return 0;
-}
-
-struct adv_entry *hci_find_adv_entry(struct hci_dev *hdev, bdaddr_t *bdaddr)
-{
- struct adv_entry *entry;
-
- list_for_each_entry(entry, &hdev->adv_entries, list)
- if (bacmp(bdaddr, &entry->bdaddr) == 0)
- return entry;
-
- return NULL;
-}
-
-static inline int is_connectable_adv(u8 evt_type)
-{
- if (evt_type == ADV_IND || evt_type == ADV_DIRECT_IND)
- return 1;
-
- return 0;
-}
-
-int hci_add_adv_entry(struct hci_dev *hdev,
- struct hci_ev_le_advertising_info *ev) { struct adv_entry *entry; if (!is_connectable_adv(ev->evt_type))
- return -EINVAL;
-
- /* Only new entries should be added to adv_entries. So, if
- * bdaddr was found, don't add it. */
- if (hci_find_adv_entry(hdev, &ev->bdaddr))
- return 0;
-
- entry = kzalloc(sizeof(*entry), GFP_KERNEL);
- if (!entry)
- return -ENOMEM;
-
- bacpy(&entry->bdaddr, &ev->bdaddr);
- entry->bdaddr_type = ev->bdaddr_type;
-
- list_add(&entry->list, &hdev->adv_entries);
-
- BT_DBG("%s adv entry added: address %s type %u", hdev->name,
- batostr(&entry->bdaddr), entry->bdaddr_type);
-
- return 0;
-}
-
-static void le_scan_param_req(struct hci_dev *hdev, unsigned long opt)
-{
- struct le_scan_params *param = (struct le_scan_params *) opt;
- struct hci_cp_le_set_scan_param cp;
-
- memset(&cp, 0, sizeof(cp));
- cp.type = param->type;
- cp.interval = cpu_to_le16(param->interval);
- cp.window = cpu_to_le16(param->window);
-
- hci_send_cmd(hdev, HCI_OP_LE_SET_SCAN_PARAM, sizeof(cp), &cp);
-}
-
-static void le_scan_enable_req(struct hci_dev *hdev, unsigned long opt)
-{
- struct hci_cp_le_set_scan_enable cp;
-
- memset(&cp, 0, sizeof(cp));
- cp.enable = 1;
-
- hci_send_cmd(hdev, HCI_OP_LE_SET_SCAN_ENABLE, sizeof(cp), &cp);
-}
-
-static int hci_do_le_scan(struct hci_dev *hdev, u8 type, u16 interval,
- u16 window, int timeout)
-{
- long timeo = msecs_to_jiffies(3000);
- struct le_scan_params param;
- int err;
-
- BT_DBG("%s", hdev->name);
-
- if (test_bit(HCI_LE_SCAN, &hdev->dev_flags))
- return -EINPROGRESS;
-
- param.type = type;
- param.interval = interval;
- param.window = window;
-
- hci_req_lock(hdev);
-
- err = __hci_request(hdev, le_scan_param_req, (unsigned long) &param,
- timeo);
- if (!err)
- err = __hci_request(hdev, le_scan_enable_req, 0, timeo);
-
- hci_req_unlock(hdev);
-
- if (err < 0)
- return err;
-
- schedule_delayed_work(&hdev->le_scan_disable,
- msecs_to_jiffies(timeout));
-
- return 0;
-}
-
-static void le_scan_disable_work(struct work_struct *work)
-{
- struct hci_dev *hdev = container_of(work, struct hci_dev,
- le_scan_disable.work);
- struct hci_cp_le_set_scan_enable cp;
-
- BT_DBG("%s", hdev->name);
-
- memset(&cp, 0, sizeof(cp));
-
- hci_send_cmd(hdev, HCI_OP_LE_SET_SCAN_ENABLE, sizeof(cp), &cp);
-}
-
-static void le_scan_work(struct work_struct *work)
-{
- struct hci_dev *hdev = container_of(work, struct hci_dev, le_scan);
- struct le_scan_params *param = &hdev->le_scan_params;
-
- BT_DBG("%s", hdev->name);
-
- hci_do_le_scan(hdev, param->type, param->interval, param->window,
- param->timeout);
-}
-
-int hci_le_scan(struct hci_dev *hdev, u8 type, u16 interval, u16 window,
- int timeout)
-{
- struct le_scan_params *param = &hdev->le_scan_params;
-
- BT_DBG("%s", hdev->name);
-
- if (work_busy(&hdev->le_scan))
- return -EINPROGRESS;
-
- param->type = type;
- param->interval = interval;
- param->window = window;
- param->timeout = timeout;
-
- queue_work(system_long_wq, &hdev->le_scan);
-
- return 0;
-}
-
-/* Register HCI device */
-int hci_register_dev(struct hci_dev *hdev)
-{
- struct list_head *head = &hci_dev_list, *p;
- int i, id, error;
-
- BT_DBG("%p name %s bus %d", hdev, hdev->name, hdev->bus);
-
- if (!hdev->open || !hdev->close)
- return -EINVAL;
-
- /* Do not allow HCI_AMP devices to register at index 0,
- * so the index can be used as the AMP controller ID.
- */
- id = (hdev->dev_type == HCI_BREDR) ? 0 : 1;
-
- write_lock(&hci_dev_list_lock);
-
- /* Find first available device id */
- list_for_each(p, &hci_dev_list) {
- if (list_entry(p, struct hci_dev, list)->id != id)
- break;
- head = p; id++;
- }
-
- sprintf(hdev->name, "hci%d", id);
- hdev->id = id;
- list_add_tail(&hdev->list, head);
-
- mutex_init(&hdev->lock);
-
- hdev->flags = 0;
- hdev->dev_flags = 0;
- hdev->pkt_type = (HCI_DM1 | HCI_DH1 | HCI_HV1);
- hdev->esco_type = (ESCO_HV1);
- hdev->link_mode = (HCI_LM_ACCEPT);
- hdev->io_capability = 0x03; /* No Input No Output */
-
- hdev->idle_timeout = 0;
- hdev->sniff_max_interval = 800;
- hdev->sniff_min_interval = 80;
-
- INIT_WORK(&hdev->rx_work, hci_rx_work);
- INIT_WORK(&hdev->cmd_work, hci_cmd_work);
- INIT_WORK(&hdev->tx_work, hci_tx_work);
-
-
- skb_queue_head_init(&hdev->rx_q);
- skb_queue_head_init(&hdev->cmd_q);
- skb_queue_head_init(&hdev->raw_q);
-
- setup_timer(&hdev->cmd_timer, hci_cmd_timer, (unsigned long) hdev);
-
- for (i = 0; i < NUM_REASSEMBLY; i++)
- hdev->reassembly[i] = NULL;
-
- init_waitqueue_head(&hdev->req_wait_q);
- mutex_init(&hdev->req_lock);
-
- discovery_init(hdev);
-
- hci_conn_hash_init(hdev);
-
- INIT_LIST_HEAD(&hdev->mgmt_pending);
-
- INIT_LIST_HEAD(&hdev->blacklist);
-
- INIT_LIST_HEAD(&hdev->uuids);
-
- INIT_LIST_HEAD(&hdev->link_keys);
- INIT_LIST_HEAD(&hdev->long_term_keys);
-
- INIT_LIST_HEAD(&hdev->remote_oob_data);
-
- INIT_LIST_HEAD(&hdev->adv_entries);
-
- INIT_DELAYED_WORK(&hdev->adv_work, hci_clear_adv_cache);
- INIT_WORK(&hdev->power_on, hci_power_on);
- INIT_DELAYED_WORK(&hdev->power_off, hci_power_off);
-
- INIT_DELAYED_WORK(&hdev->discov_off, hci_discov_off);
-
- memset(&hdev->stat, 0, sizeof(struct hci_dev_stats));
-
- atomic_set(&hdev->promisc, 0);
-
- INIT_WORK(&hdev->le_scan, le_scan_work);
-
- INIT_DELAYED_WORK(&hdev->le_scan_disable, le_scan_disable_work);
-
- write_unlock(&hci_dev_list_lock);
-
- hdev->workqueue = alloc_workqueue(hdev->name, WQ_HIGHPRI | WQ_UNBOUND |
- WQ_MEM_RECLAIM, 1);
- if (!hdev->workqueue) {
- error = -ENOMEM;
- goto err;
- }
-
- error = hci_add_sysfs(hdev);
- if (error < 0)
- goto err_wqueue;
-
- hdev->rfkill = rfkill_alloc(hdev->name, &hdev->dev,
- RFKILL_TYPE_BLUETOOTH, &hci_rfkill_ops, hdev);
- if (hdev->rfkill) {
- if (rfkill_register(hdev->rfkill) < 0) {
- rfkill_destroy(hdev->rfkill);
- hdev->rfkill = NULL;
- }
- }
-
- set_bit(HCI_AUTO_OFF, &hdev->dev_flags);
- set_bit(HCI_SETUP, &hdev->dev_flags);
- schedule_work(&hdev->power_on);
-
- hci_notify(hdev, HCI_DEV_REG);
- hci_dev_hold(hdev);
-
- return id;
-
-err_wqueue:
- destroy_workqueue(hdev->workqueue);
-err:
- write_lock(&hci_dev_list_lock);
- list_del(&hdev->list);
- write_unlock(&hci_dev_list_lock);
-
- return error;
-}
-EXPORT_SYMBOL(hci_register_dev);
-
-/* Unregister HCI device */
-void hci_unregister_dev(struct hci_dev *hdev)
-{
- int i;
-
- BT_DBG("%p name %s bus %d", hdev, hdev->name, hdev->bus);
-
- set_bit(HCI_UNREGISTER, &hdev->dev_flags);
-
- write_lock(&hci_dev_list_lock);
- list_del(&hdev->list);
- write_unlock(&hci_dev_list_lock);
-
- hci_dev_do_close(hdev);
-
- for (i = 0; i < NUM_REASSEMBLY; i++)
- kfree_skb(hdev->reassembly[i]);
-
- if (!test_bit(HCI_INIT, &hdev->flags) &&
- !test_bit(HCI_SETUP, &hdev->dev_flags)) {
- hci_dev_lock(hdev);
- mgmt_index_removed(hdev);
- hci_dev_unlock(hdev);
- }
-
- /* mgmt_index_removed should take care of emptying the
- * pending list */
- BUG_ON(!list_empty(&hdev->mgmt_pending));
-
- hci_notify(hdev, HCI_DEV_UNREG);
-
- if (hdev->rfkill) {
- rfkill_unregister(hdev->rfkill);
- rfkill_destroy(hdev->rfkill);
- }
-
- hci_del_sysfs(hdev);
-
- cancel_delayed_work_sync(&hdev->adv_work);
-
- destroy_workqueue(hdev->workqueue);
-
- hci_dev_lock(hdev);
- hci_blacklist_clear(hdev);
- hci_uuids_clear(hdev);
- hci_link_keys_clear(hdev);
- hci_smp_ltks_clear(hdev);
- hci_remote_oob_data_clear(hdev);
- hci_adv_entries_clear(hdev);
- hci_dev_unlock(hdev);
-
- hci_dev_put(hdev);
-}
-EXPORT_SYMBOL(hci_unregister_dev);
-
-/* Suspend HCI device */
-int hci_suspend_dev(struct hci_dev *hdev)
-{
- hci_notify(hdev, HCI_DEV_SUSPEND);
- return 0;
-}
-EXPORT_SYMBOL(hci_suspend_dev);
-
-/* Resume HCI device */
-int hci_resume_dev(struct hci_dev *hdev)
-{
- hci_notify(hdev, HCI_DEV_RESUME);
- return 0;
-}
-EXPORT_SYMBOL(hci_resume_dev);
-
-/* Receive frame from HCI drivers */
-int hci_recv_frame(struct sk_buff *skb)
-{
- struct hci_dev *hdev = (struct hci_dev *) skb->dev;
- if (!hdev || (!test_bit(HCI_UP, &hdev->flags)
- && !test_bit(HCI_INIT, &hdev->flags))) {
- kfree_skb(skb);
- return -ENXIO;
- }
-
- /* Incomming skb */
- bt_cb(skb)->incoming = 1;
-
- /* Time stamp */
- __net_timestamp(skb);
-
- skb_queue_tail(&hdev->rx_q, skb);
- queue_work(hdev->workqueue, &hdev->rx_work);
-
- return 0;
-}
-EXPORT_SYMBOL(hci_recv_frame);
-
-static int hci_reassembly(struct hci_dev *hdev, int type, void *data,
- int count, __u8 index)
-{
- int len = 0;
- int hlen = 0;
- int remain = count;
- struct sk_buff *skb;
- struct bt_skb_cb *scb;
-
- if ((type < HCI_ACLDATA_PKT || type > HCI_EVENT_PKT) ||
- index >= NUM_REASSEMBLY)
- return -EILSEQ;
-
- skb = hdev->reassembly[index];
-
- if (!skb) {
- switch (type) {
- case HCI_ACLDATA_PKT:
- len = HCI_MAX_FRAME_SIZE;
- hlen = HCI_ACL_HDR_SIZE;
- break;
- case HCI_EVENT_PKT:
- len = HCI_MAX_EVENT_SIZE;
- hlen = HCI_EVENT_HDR_SIZE;
- break;
- case HCI_SCODATA_PKT:
- len = HCI_MAX_SCO_SIZE;
- hlen = HCI_SCO_HDR_SIZE;
- break;
- }
-
- skb = bt_skb_alloc(len, GFP_ATOMIC);
- if (!skb)
- return -ENOMEM;
-
- scb = (void *) skb->cb;
- scb->expect = hlen;
- scb->pkt_type = type;
-
- skb->dev = (void *) hdev;
- hdev->reassembly[index] = skb;
- }
-
- while (count) {
- scb = (void *) skb->cb;
- len = min_t(uint, scb->expect, count);
-
- memcpy(skb_put(skb, len), data, len);
-
- count -= len;
- data += len;
- scb->expect -= len;
- remain = count;
-
- switch (type) {
- case HCI_EVENT_PKT:
- if (skb->len == HCI_EVENT_HDR_SIZE) {
- struct hci_event_hdr *h = hci_event_hdr(skb);
- scb->expect = h->plen;
-
- if (skb_tailroom(skb) < scb->expect) {
- kfree_skb(skb);
- hdev->reassembly[index] = NULL;
- return -ENOMEM;
- }
- }
- break;
-
- case HCI_ACLDATA_PKT:
- if (skb->len == HCI_ACL_HDR_SIZE) {
- struct hci_acl_hdr *h = hci_acl_hdr(skb);
- scb->expect = __le16_to_cpu(h->dlen);
-
- if (skb_tailroom(skb) < scb->expect) {
- kfree_skb(skb);
- hdev->reassembly[index] = NULL;
- return -ENOMEM;
- }
- }
- break;
-
- case HCI_SCODATA_PKT:
- if (skb->len == HCI_SCO_HDR_SIZE) {
- struct hci_sco_hdr *h = hci_sco_hdr(skb);
- scb->expect = h->dlen;
-
- if (skb_tailroom(skb) < scb->expect) {
- kfree_skb(skb);
- hdev->reassembly[index] = NULL;
- return -ENOMEM;
- }
- }
- break;
- }
-
- if (scb->expect == 0) {
- /* Complete frame */
-
- bt_cb(skb)->pkt_type = type;
- hci_recv_frame(skb);
-
- hdev->reassembly[index] = NULL;
- return remain;
- }
- }
-
- return remain;
-}
-
-int hci_recv_fragment(struct hci_dev *hdev, int type, void *data, int count)
-{
- int rem = 0;
-
- if (type < HCI_ACLDATA_PKT || type > HCI_EVENT_PKT)
- return -EILSEQ;
-
- while (count) {
- rem = hci_reassembly(hdev, type, data, count, type - 1);
- if (rem < 0)
- return rem;
-
- data += (count - rem);
- count = rem;
- }
-
- return rem;
-}
-EXPORT_SYMBOL(hci_recv_fragment);
-
-#define STREAM_REASSEMBLY 0
-
-int hci_recv_stream_fragment(struct hci_dev *hdev, void *data, int count)
-{
- int type;
- int rem = 0;
-
- while (count) {
- struct sk_buff *skb = hdev->reassembly[STREAM_REASSEMBLY];
-
- if (!skb) {
- struct { char type; } *pkt;
-
- /* Start of the frame */
- pkt = data;
- type = pkt->type;
-
- data++;
- count--;
- } else
- type = bt_cb(skb)->pkt_type;
-
- rem = hci_reassembly(hdev, type, data, count,
- STREAM_REASSEMBLY);
- if (rem < 0)
- return rem;
-
- data += (count - rem);
- count = rem;
- }
-
- return rem;
-}
-EXPORT_SYMBOL(hci_recv_stream_fragment);
-
-/* ---- Interface to upper protocols ---- */
-
-int hci_register_cb(struct hci_cb *cb)
-{
- BT_DBG("%p name %s", cb, cb->name);
-
- write_lock(&hci_cb_list_lock);
- list_add(&cb->list, &hci_cb_list);
- write_unlock(&hci_cb_list_lock);
-
- return 0;
-}
-EXPORT_SYMBOL(hci_register_cb);
-
-int hci_unregister_cb(struct hci_cb *cb)
-{
- BT_DBG("%p name %s", cb, cb->name);
-
- write_lock(&hci_cb_list_lock);
- list_del(&cb->list);
- write_unlock(&hci_cb_list_lock);
-
- return 0;
-}
-EXPORT_SYMBOL(hci_unregister_cb);
-
-static int hci_send_frame(struct sk_buff *skb)
-{
- struct hci_dev *hdev = (struct hci_dev *) skb->dev;
-
- if (!hdev) {
- kfree_skb(skb);
- return -ENODEV;
- }
-
- BT_DBG("%s type %d len %d", hdev->name, bt_cb(skb)->pkt_type, skb->len);
-
- /* Time stamp */
- __net_timestamp(skb);
-
- /* Send copy to monitor */
- hci_send_to_monitor(hdev, skb);
-
- if (atomic_read(&hdev->promisc)) {
- /* Send copy to the sockets */
- hci_send_to_sock(hdev, skb);
- }
-
- /* Get rid of skb owner, prior to sending to the driver. */
- skb_orphan(skb);
-
- return hdev->send(skb);
-}
-
-/* Send HCI command */
-int hci_send_cmd(struct hci_dev *hdev, __u16 opcode, __u32 plen, void *param)
-{
- int len = HCI_COMMAND_HDR_SIZE + plen;
- struct hci_command_hdr *hdr;
- struct sk_buff *skb;
-
- BT_DBG("%s opcode 0x%x plen %d", hdev->name, opcode, plen);
-
- skb = bt_skb_alloc(len, GFP_ATOMIC);
- if (!skb) {
- BT_ERR("%s no memory for command", hdev->name);
- return -ENOMEM;
- }
-
- hdr = (struct hci_command_hdr *) skb_put(skb, HCI_COMMAND_HDR_SIZE);
- hdr->opcode = cpu_to_le16(opcode);
- hdr->plen = plen;
-
- if (plen)
- memcpy(skb_put(skb, plen), param, plen);
-
- BT_DBG("skb len %d", skb->len);
-
- bt_cb(skb)->pkt_type = HCI_COMMAND_PKT;
- skb->dev = (void *) hdev;
-
- if (test_bit(HCI_INIT, &hdev->flags))
- hdev->init_last_cmd = opcode;
-
- skb_queue_tail(&hdev->cmd_q, skb);
- queue_work(hdev->workqueue, &hdev->cmd_work);
-
- return 0;
-}
-
-/* Get data from the previously sent command */
-void *hci_sent_cmd_data(struct hci_dev *hdev, __u16 opcode)
-{
- struct hci_command_hdr *hdr;
-
- if (!hdev->sent_cmd)
- return NULL;
-
- hdr = (void *) hdev->sent_cmd->data;
-
- if (hdr->opcode != cpu_to_le16(opcode))
- return NULL;
-
- BT_DBG("%s opcode 0x%x", hdev->name, opcode);
-
- return hdev->sent_cmd->data + HCI_COMMAND_HDR_SIZE;
-}
-
-/* Send ACL data */
-static void hci_add_acl_hdr(struct sk_buff *skb, __u16 handle, __u16 flags)
-{
- struct hci_acl_hdr *hdr;
- int len = skb->len;
-
- skb_push(skb, HCI_ACL_HDR_SIZE);
- skb_reset_transport_header(skb);
- hdr = (struct hci_acl_hdr *)skb_transport_header(skb);
- hdr->handle = cpu_to_le16(hci_handle_pack(handle, flags));
- hdr->dlen = cpu_to_le16(len);
-}
-
-static void hci_queue_acl(struct hci_conn *conn, struct sk_buff_head *queue,
- struct sk_buff *skb, __u16 flags)
-{
- struct hci_dev *hdev = conn->hdev;
- struct sk_buff *list;
-
- list = skb_shinfo(skb)->frag_list;
- if (!list) {
- /* Non fragmented */
- BT_DBG("%s nonfrag skb %p len %d", hdev->name, skb, skb->len);
-
- skb_queue_tail(queue, skb);
- } else {
- /* Fragmented */
- BT_DBG("%s frag %p len %d", hdev->name, skb, skb->len);
-
- skb_shinfo(skb)->frag_list = NULL;
-
- /* Queue all fragments atomically */
- spin_lock(&queue->lock);
-
- __skb_queue_tail(queue, skb);
-
- flags &= ~ACL_START;
- flags |= ACL_CONT;
- do {
- skb = list; list = list->next;
-
- skb->dev = (void *) hdev;
- bt_cb(skb)->pkt_type = HCI_ACLDATA_PKT;
- hci_add_acl_hdr(skb, conn->handle, flags);
-
- BT_DBG("%s frag %p len %d", hdev->name, skb, skb->len);
-
- __skb_queue_tail(queue, skb);
- } while (list);
-
- spin_unlock(&queue->lock);
- }
-}
-
-void hci_send_acl(struct hci_chan *chan, struct sk_buff *skb, __u16 flags)
-{
- struct hci_conn *conn = chan->conn;
- struct hci_dev *hdev = conn->hdev;
-
- BT_DBG("%s chan %p flags 0x%x", hdev->name, chan, flags);
-
- skb->dev = (void *) hdev;
- bt_cb(skb)->pkt_type = HCI_ACLDATA_PKT;
- hci_add_acl_hdr(skb, conn->handle, flags);
-
- hci_queue_acl(conn, &chan->data_q, skb, flags);
-
- queue_work(hdev->workqueue, &hdev->tx_work);
-}
-EXPORT_SYMBOL(hci_send_acl);
-
-/* Send SCO data */
-void hci_send_sco(struct hci_conn *conn, struct sk_buff *skb)
-{
- struct hci_dev *hdev = conn->hdev;
- struct hci_sco_hdr hdr;
-
- BT_DBG("%s len %d", hdev->name, skb->len);
-
- hdr.handle = cpu_to_le16(conn->handle);
- hdr.dlen = skb->len;
-
- skb_push(skb, HCI_SCO_HDR_SIZE);
- skb_reset_transport_header(skb);
- memcpy(skb_transport_header(skb), &hdr, HCI_SCO_HDR_SIZE);
-
- skb->dev = (void *) hdev;
- bt_cb(skb)->pkt_type = HCI_SCODATA_PKT;
-
- skb_queue_tail(&conn->data_q, skb);
- queue_work(hdev->workqueue, &hdev->tx_work);
-}
-EXPORT_SYMBOL(hci_send_sco);
-
-/* ---- HCI TX task (outgoing data) ---- */
-
-/* HCI Connection scheduler */
-static inline struct hci_conn *hci_low_sent(struct hci_dev *hdev, __u8 type, int *quote)
-{
- struct hci_conn_hash *h = &hdev->conn_hash;
- struct hci_conn *conn = NULL, *c;
- int num = 0, min = ~0;
-
- /* We don't have to lock device here. Connections are always
- * added and removed with TX task disabled. */
-
- rcu_read_lock();
-
- list_for_each_entry_rcu(c, &h->list, list) {
- if (c->type != type || skb_queue_empty(&c->data_q))
- continue;
-
- if (c->state != BT_CONNECTED && c->state != BT_CONFIG)
- continue;
-
- num++;
-
- if (c->sent < min) {
- min = c->sent;
- conn = c;
- }
-
- if (hci_conn_num(hdev, type) == num)
- break;
- }
-
- rcu_read_unlock();
-
- if (conn) {
- int cnt, q;
-
- switch (conn->type) {
- case ACL_LINK:
- cnt = hdev->acl_cnt;
- break;
- case SCO_LINK:
- case ESCO_LINK:
- cnt = hdev->sco_cnt;
- break;
- case LE_LINK:
- cnt = hdev->le_mtu ? hdev->le_cnt : hdev->acl_cnt;
- break;
- default:
- cnt = 0;
- BT_ERR("Unknown link type");
- }
-
- q = cnt / num;
- *quote = q ? q : 1;
- } else
- *quote = 0;
-
- BT_DBG("conn %p quote %d", conn, *quote);
- return conn;
-}
-
-static inline void hci_link_tx_to(struct hci_dev *hdev, __u8 type)
-{
- struct hci_conn_hash *h = &hdev->conn_hash;
- struct hci_conn *c;
-
- BT_ERR("%s link tx timeout", hdev->name);
-
- rcu_read_lock();
-
- /* Kill stalled connections */
- list_for_each_entry_rcu(c, &h->list, list) {
- if (c->type == type && c->sent) {
- BT_ERR("%s killing stalled connection %s",
- hdev->name, batostr(&c->dst));
- hci_acl_disconn(c, 0x13);
- }
- }
-
- rcu_read_unlock();
-}
-
-static inline struct hci_chan *hci_chan_sent(struct hci_dev *hdev, __u8 type,
- int *quote)
-{
- struct hci_conn_hash *h = &hdev->conn_hash;
- struct hci_chan *chan = NULL;
- int num = 0, min = ~0, cur_prio = 0;
- struct hci_conn *conn;
- int cnt, q, conn_num = 0;
-
- BT_DBG("%s", hdev->name);
-
- rcu_read_lock();
-
- list_for_each_entry_rcu(conn, &h->list, list) {
- struct hci_chan *tmp;
-
- if (conn->type != type)
- continue;
-
- if (conn->state != BT_CONNECTED && conn->state != BT_CONFIG)
- continue;
-
- conn_num++;
-
- list_for_each_entry_rcu(tmp, &conn->chan_list, list) {
- struct sk_buff *skb;
-
- if (skb_queue_empty(&tmp->data_q))
- continue;
-
- skb = skb_peek(&tmp->data_q);
- if (skb->priority < cur_prio)
- continue;
-
- if (skb->priority > cur_prio) {
- num = 0;
- min = ~0;
- cur_prio = skb->priority;
- }
-
- num++;
-
- if (conn->sent < min) {
- min = conn->sent;
- chan = tmp;
- }
- }
-
- if (hci_conn_num(hdev, type) == conn_num)
- break;
- }
-
- rcu_read_unlock();
-
- if (!chan)
- return NULL;
-
- switch (chan->conn->type) {
- case ACL_LINK:
- cnt = hdev->acl_cnt;
- break;
- case SCO_LINK:
- case ESCO_LINK:
- cnt = hdev->sco_cnt;
- break;
- case LE_LINK:
- cnt = hdev->le_mtu ? hdev->le_cnt : hdev->acl_cnt;
- break;
- default:
- cnt = 0;
- BT_ERR("Unknown link type");
- }
-
- q = cnt / num;
- *quote = q ? q : 1;
- BT_DBG("chan %p quote %d", chan, *quote);
- return chan;
-}
-
-static void hci_prio_recalculate(struct hci_dev *hdev, __u8 type)
-{
- struct hci_conn_hash *h = &hdev->conn_hash;
- struct hci_conn *conn;
- int num = 0;
-
- BT_DBG("%s", hdev->name);
-
- rcu_read_lock();
-
- list_for_each_entry_rcu(conn, &h->list, list) {
- struct hci_chan *chan;
-
- if (conn->type != type)
- continue;
-
- if (conn->state != BT_CONNECTED && conn->state != BT_CONFIG)
- continue;
-
- num++;
-
- list_for_each_entry_rcu(chan, &conn->chan_list, list) {
- struct sk_buff *skb;
-
- if (chan->sent) {
- chan->sent = 0;
- continue;
- }
-
- if (skb_queue_empty(&chan->data_q))
- continue;
-
- skb = skb_peek(&chan->data_q);
- if (skb->priority >= HCI_PRIO_MAX - 1)
- continue;
-
- skb->priority = HCI_PRIO_MAX - 1;
-
- BT_DBG("chan %p skb %p promoted to %d", chan, skb,
- skb->priority);
- }
-
- if (hci_conn_num(hdev, type) == num)
- break;
- }
-
- rcu_read_unlock();
-
-}
-
-static inline int __get_blocks(struct hci_dev *hdev, struct sk_buff *skb)
-{
- /* Calculate count of blocks used by this packet */
- return DIV_ROUND_UP(skb->len - HCI_ACL_HDR_SIZE, hdev->block_len);
-}
-
-static inline void __check_timeout(struct hci_dev *hdev, unsigned int cnt)
-{
- if (!test_bit(HCI_RAW, &hdev->flags)) {
- /* ACL tx timeout must be longer than maximum
- * link supervision timeout (40.9 seconds) */
- if (!cnt && time_after(jiffies, hdev->acl_last_tx +
- msecs_to_jiffies(HCI_ACL_TX_TIMEOUT)))
- hci_link_tx_to(hdev, ACL_LINK);
- }
-}
-
-static inline void hci_sched_acl_pkt(struct hci_dev *hdev)
-{
- unsigned int cnt = hdev->acl_cnt;
- struct hci_chan *chan;
- struct sk_buff *skb;
- int quote;
-
- __check_timeout(hdev, cnt);
-
- while (hdev->acl_cnt &&
- (chan = hci_chan_sent(hdev, ACL_LINK, &quote))) {
- u32 priority = (skb_peek(&chan->data_q))->priority;
- while (quote-- && (skb = skb_peek(&chan->data_q))) {
- BT_DBG("chan %p skb %p len %d priority %u", chan, skb,
- skb->len, skb->priority);
-
- /* Stop if priority has changed */
- if (skb->priority < priority)
- break;
-
- skb = skb_dequeue(&chan->data_q);
-
- hci_conn_enter_active_mode(chan->conn,
- bt_cb(skb)->force_active);
-
- hci_send_frame(skb);
- hdev->acl_last_tx = jiffies;
-
- hdev->acl_cnt--;
- chan->sent++;
- chan->conn->sent++;
- }
- }
-
- if (cnt != hdev->acl_cnt)
- hci_prio_recalculate(hdev, ACL_LINK);
-}
-
-static inline void hci_sched_acl_blk(struct hci_dev *hdev)
-{
- unsigned int cnt = hdev->block_cnt;
- struct hci_chan *chan;
- struct sk_buff *skb;
- int quote;
-
- __check_timeout(hdev, cnt);
-
- while (hdev->block_cnt > 0 &&
- (chan = hci_chan_sent(hdev, ACL_LINK, &quote))) {
- u32 priority = (skb_peek(&chan->data_q))->priority;
- while (quote > 0 && (skb = skb_peek(&chan->data_q))) {
- int blocks;
-
- BT_DBG("chan %p skb %p len %d priority %u", chan, skb,
- skb->len, skb->priority);
-
- /* Stop if priority has changed */
- if (skb->priority < priority)
- break;
-
- skb = skb_dequeue(&chan->data_q);
-
- blocks = __get_blocks(hdev, skb);
- if (blocks > hdev->block_cnt)
- return;
-
- hci_conn_enter_active_mode(chan->conn,
- bt_cb(skb)->force_active);
-
- hci_send_frame(skb);
- hdev->acl_last_tx = jiffies;
-
- hdev->block_cnt -= blocks;
- quote -= blocks;
-
- chan->sent += blocks;
- chan->conn->sent += blocks;
- }
- }
-
- if (cnt != hdev->block_cnt)
- hci_prio_recalculate(hdev, ACL_LINK);
-}
-
-static inline void hci_sched_acl(struct hci_dev *hdev)
-{
- BT_DBG("%s", hdev->name);
-
- if (!hci_conn_num(hdev, ACL_LINK))
- return;
-
- switch (hdev->flow_ctl_mode) {
- case HCI_FLOW_CTL_MODE_PACKET_BASED:
- hci_sched_acl_pkt(hdev);
- break;
-
- case HCI_FLOW_CTL_MODE_BLOCK_BASED:
- hci_sched_acl_blk(hdev);
- break;
- }
-}
-
-/* Schedule SCO */
-static inline void hci_sched_sco(struct hci_dev *hdev)
-{
- struct hci_conn *conn;
- struct sk_buff *skb;
- int quote;
-
- BT_DBG("%s", hdev->name);
-
- if (!hci_conn_num(hdev, SCO_LINK))
- return;
-
- while (hdev->sco_cnt && (conn = hci_low_sent(hdev, SCO_LINK, &quote))) {
- while (quote-- && (skb = skb_dequeue(&conn->data_q))) {
- BT_DBG("skb %p len %d", skb, skb->len);
- hci_send_frame(skb);
-
- conn->sent++;
- if (conn->sent == ~0)
- conn->sent = 0;
- }
- }
-}
-
-static inline void hci_sched_esco(struct hci_dev *hdev)
-{
- struct hci_conn *conn;
- struct sk_buff *skb;
- int quote;
-
- BT_DBG("%s", hdev->name);
-
- if (!hci_conn_num(hdev, ESCO_LINK))
- return;
-
- while (hdev->sco_cnt && (conn = hci_low_sent(hdev, ESCO_LINK, &quote))) {
- while (quote-- && (skb = skb_dequeue(&conn->data_q))) {
- BT_DBG("skb %p len %d", skb, skb->len);
- hci_send_frame(skb);
-
- conn->sent++;
- if (conn->sent == ~0)
- conn->sent = 0;
- }
- }
-}
-
-static inline void hci_sched_le(struct hci_dev *hdev)
-{
- struct hci_chan *chan;
- struct sk_buff *skb;
- int quote, cnt, tmp;
-
- BT_DBG("%s", hdev->name);
-
- if (!hci_conn_num(hdev, LE_LINK))
- return;
-
- if (!test_bit(HCI_RAW, &hdev->flags)) {
- /* LE tx timeout must be longer than maximum
- * link supervision timeout (40.9 seconds) */
- if (!hdev->le_cnt && hdev->le_pkts &&
- time_after(jiffies, hdev->le_last_tx + HZ * 45))
- hci_link_tx_to(hdev, LE_LINK);
- }
-
- cnt = hdev->le_pkts ? hdev->le_cnt : hdev->acl_cnt;
- tmp = cnt;
- while (cnt && (chan = hci_chan_sent(hdev, LE_LINK, &quote))) {
- u32 priority = (skb_peek(&chan->data_q))->priority;
- while (quote-- && (skb = skb_peek(&chan->data_q))) {
- BT_DBG("chan %p skb %p len %d priority %u", chan, skb,
- skb->len, skb->priority);
-
- /* Stop if priority has changed */
- if (skb->priority < priority)
- break;
-
- skb = skb_dequeue(&chan->data_q);
-
- hci_send_frame(skb);
- hdev->le_last_tx = jiffies;
-
- cnt--;
- chan->sent++;
- chan->conn->sent++;
- }
- }
-
- if (hdev->le_pkts)
- hdev->le_cnt = cnt;
- else
- hdev->acl_cnt = cnt;
-
- if (cnt != tmp)
- hci_prio_recalculate(hdev, LE_LINK);
-}
-
-static void hci_tx_work(struct work_struct *work)
-{
- struct hci_dev *hdev = container_of(work, struct hci_dev, tx_work);
- struct sk_buff *skb;
-
- BT_DBG("%s acl %d sco %d le %d", hdev->name, hdev->acl_cnt,
- hdev->sco_cnt, hdev->le_cnt);
-
- /* Schedule queues and send stuff to HCI driver */
-
- hci_sched_acl(hdev);
-
- hci_sched_sco(hdev);
-
- hci_sched_esco(hdev);
-
- hci_sched_le(hdev);
-
- /* Send next queued raw (unknown type) packet */
- while ((skb = skb_dequeue(&hdev->raw_q)))
- hci_send_frame(skb);
-}
-
-/* ----- HCI RX task (incoming data processing) ----- */
-
-/* ACL data packet */
-static inline void hci_acldata_packet(struct hci_dev *hdev, struct sk_buff *skb)
-{
- struct hci_acl_hdr *hdr = (void *) skb->data;
- struct hci_conn *conn;
- __u16 handle, flags;
-
- skb_pull(skb, HCI_ACL_HDR_SIZE);
-
- handle = __le16_to_cpu(hdr->handle);
- flags = hci_flags(handle);
- handle = hci_handle(handle);
-
- BT_DBG("%s len %d handle 0x%x flags 0x%x", hdev->name, skb->len, handle, flags);
-
- hdev->stat.acl_rx++;
-
- hci_dev_lock(hdev);
- conn = hci_conn_hash_lookup_handle(hdev, handle);
- hci_dev_unlock(hdev);
-
- if (conn) {
- hci_conn_enter_active_mode(conn, BT_POWER_FORCE_ACTIVE_OFF);
-
- hci_dev_lock(hdev);
- if (test_bit(HCI_MGMT, &hdev->dev_flags) &&
- !test_and_set_bit(HCI_CONN_MGMT_CONNECTED, &conn->flags))
- mgmt_device_connected(hdev, &conn->dst, conn->type,
- conn->dst_type, 0, NULL, 0,
- conn->dev_class);
- hci_dev_unlock(hdev);
-
- /* Send to upper protocol */
- l2cap_recv_acldata(conn, skb, flags);
- return;
- } else {
- BT_ERR("%s ACL packet for unknown connection handle %d",
- hdev->name, handle);
- }
-
- kfree_skb(skb);
-}
-
-/* SCO data packet */
-static inline void hci_scodata_packet(struct hci_dev *hdev, struct sk_buff *skb)
-{
- struct hci_sco_hdr *hdr = (void *) skb->data;
- struct hci_conn *conn;
- __u16 handle;
-
- skb_pull(skb, HCI_SCO_HDR_SIZE);
-
- handle = __le16_to_cpu(hdr->handle);
-
- BT_DBG("%s len %d handle 0x%x", hdev->name, skb->len, handle);
-
- hdev->stat.sco_rx++;
-
- hci_dev_lock(hdev);
- conn = hci_conn_hash_lookup_handle(hdev, handle);
- hci_dev_unlock(hdev);
-
- if (conn) {
- /* Send to upper protocol */
- sco_recv_scodata(conn, skb);
- return;
- } else {
- BT_ERR("%s SCO packet for unknown connection handle %d",
- hdev->name, handle);
- }
-
- kfree_skb(skb);
-}
-
-static void hci_rx_work(struct work_struct *work)
-{
- struct hci_dev *hdev = container_of(work, struct hci_dev, rx_work);
- struct sk_buff *skb;
-
- BT_DBG("%s", hdev->name);
-
- while ((skb = skb_dequeue(&hdev->rx_q))) {
- /* Send copy to monitor */
- hci_send_to_monitor(hdev, skb);
-
- if (atomic_read(&hdev->promisc)) {
- /* Send copy to the sockets */
- hci_send_to_sock(hdev, skb);
- }
-
- if (test_bit(HCI_RAW, &hdev->flags)) {
- kfree_skb(skb);
- continue;
- }
-
- if (test_bit(HCI_INIT, &hdev->flags)) {
- /* Don't process data packets in this states. */
- switch (bt_cb(skb)->pkt_type) {
- case HCI_ACLDATA_PKT:
- case HCI_SCODATA_PKT:
- kfree_skb(skb);
- continue;
- }
- }
-
- /* Process frame */
- switch (bt_cb(skb)->pkt_type) {
- case HCI_EVENT_PKT:
- BT_DBG("%s Event packet", hdev->name);
- hci_event_packet(hdev, skb);
- break;
-
- case HCI_ACLDATA_PKT:
- BT_DBG("%s ACL data packet", hdev->name);
- hci_acldata_packet(hdev, skb);
- break;
-
- case HCI_SCODATA_PKT:
- BT_DBG("%s SCO data packet", hdev->name);
- hci_scodata_packet(hdev, skb);
- break;
-
- default:
- kfree_skb(skb);
- break;
- }
- }
-}
-
-static void hci_cmd_work(struct work_struct *work)
-{
- struct hci_dev *hdev = container_of(work, struct hci_dev, cmd_work);
- struct sk_buff *skb;
-
- BT_DBG("%s cmd %d", hdev->name, atomic_read(&hdev->cmd_cnt));
-
- /* Send queued commands */
- if (atomic_read(&hdev->cmd_cnt)) {
- skb = skb_dequeue(&hdev->cmd_q);
- if (!skb)
- return;
-
- kfree_skb(hdev->sent_cmd);
-
- hdev->sent_cmd = skb_clone(skb, GFP_ATOMIC);
- if (hdev->sent_cmd) {
- atomic_dec(&hdev->cmd_cnt);
- hci_send_frame(skb);
- if (test_bit(HCI_RESET, &hdev->flags))
- del_timer(&hdev->cmd_timer);
- else
- mod_timer(&hdev->cmd_timer,
- jiffies + msecs_to_jiffies(HCI_CMD_TIMEOUT));
- } else {
- skb_queue_head(&hdev->cmd_q, skb);
- queue_work(hdev->workqueue, &hdev->cmd_work);
- }
- }
-}
-
-int hci_do_inquiry(struct hci_dev *hdev, u8 length)
-{
- /* General inquiry access code (GIAC) */
- u8 lap[3] = { 0x33, 0x8b, 0x9e };
- struct hci_cp_inquiry cp;
-
- BT_DBG("%s", hdev->name);
-
- if (test_bit(HCI_INQUIRY, &hdev->flags))
- return -EINPROGRESS;
-
- inquiry_cache_flush(hdev);
-
- memset(&cp, 0, sizeof(cp));
- memcpy(&cp.lap, lap, sizeof(cp.lap));
- cp.length = length;
-
- return hci_send_cmd(hdev, HCI_OP_INQUIRY, sizeof(cp), &cp);
-}
-
-int hci_cancel_inquiry(struct hci_dev *hdev)
-{
- BT_DBG("%s", hdev->name);
-
- if (!test_bit(HCI_INQUIRY, &hdev->flags))
- return -EPERM;
-
- return hci_send_cmd(hdev, HCI_OP_INQUIRY_CANCEL, 0, NULL);
-}
diff --git a/net/bluetooth_tizen/hci_event.c b/net/bluetooth_tizen/hci_event.c
deleted file mode 100644
index 17aaa11..0000000
--- a/net/bluetooth_tizen/hci_event.c
+++ /dev/null
@@ -1,3604 +0,0 @@
-/*
- BlueZ - Bluetooth protocol stack for Linux
- Copyright (c) 2000-2001, 2010, Code Aurora Forum. All rights reserved.
-
- Written 2000,2001 by Maxim Krasnyansky <maxk@qualcomm.com>
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License version 2 as
- published by the Free Software Foundation;
-
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
- OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS.
- IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY
- CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES
- WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
- OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
-
- ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS,
- COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS
- SOFTWARE IS DISCLAIMED.
-*/
-
-/* Bluetooth HCI event handling. */
-
-#include <linux/module.h>
-
-#include <linux/types.h>
-#include <linux/errno.h>
-#include <linux/kernel.h>
-#include <linux/slab.h>
-#include <linux/poll.h>
-#include <linux/fcntl.h>
-#include <linux/init.h>
-#include <linux/skbuff.h>
-#include <linux/interrupt.h>
-#include <linux/notifier.h>
-#include <net/sock.h>
-
-#include <asm/system.h>
-#include <linux/uaccess.h>
-#include <asm/unaligned.h>
-
-#include <net/bluetooth/bluetooth.h>
-#include <net/bluetooth/hci_core.h>
-
-/* Handle HCI Event packets */
-
-static void hci_cc_inquiry_cancel(struct hci_dev *hdev, struct sk_buff *skb)
-{
- __u8 status = *((__u8 *) skb->data);
-
- BT_DBG("%s status 0x%x", hdev->name, status);
-
- if (status) {
- hci_dev_lock(hdev);
- mgmt_stop_discovery_failed(hdev, status);
- hci_dev_unlock(hdev);
- return;
- }
-
- clear_bit(HCI_INQUIRY, &hdev->flags);
-
- hci_dev_lock(hdev);
- hci_discovery_set_state(hdev, DISCOVERY_STOPPED);
- hci_dev_unlock(hdev);
-
- hci_req_complete(hdev, HCI_OP_INQUIRY_CANCEL, status);
-
- hci_conn_check_pending(hdev);
-}
-
-static void hci_cc_exit_periodic_inq(struct hci_dev *hdev, struct sk_buff *skb)
-{
- __u8 status = *((__u8 *) skb->data);
-
- BT_DBG("%s status 0x%x", hdev->name, status);
-
- if (status)
- return;
-
- hci_conn_check_pending(hdev);
-}
-
-static void hci_cc_remote_name_req_cancel(struct hci_dev *hdev, struct sk_buff *skb)
-{
- BT_DBG("%s", hdev->name);
-}
-
-static void hci_cc_role_discovery(struct hci_dev *hdev, struct sk_buff *skb)
-{
- struct hci_rp_role_discovery *rp = (void *) skb->data;
- struct hci_conn *conn;
-
- BT_DBG("%s status 0x%x", hdev->name, rp->status);
-
- if (rp->status)
- return;
-
- hci_dev_lock(hdev);
-
- conn = hci_conn_hash_lookup_handle(hdev, __le16_to_cpu(rp->handle));
- if (conn) {
- if (rp->role)
- conn->link_mode &= ~HCI_LM_MASTER;
- else
- conn->link_mode |= HCI_LM_MASTER;
- }
-
- hci_dev_unlock(hdev);
-}
-
-static void hci_cc_read_link_policy(struct hci_dev *hdev, struct sk_buff *skb)
-{
- struct hci_rp_read_link_policy *rp = (void *) skb->data;
- struct hci_conn *conn;
-
- BT_DBG("%s status 0x%x", hdev->name, rp->status);
-
- if (rp->status)
- return;
-
- hci_dev_lock(hdev);
-
- conn = hci_conn_hash_lookup_handle(hdev, __le16_to_cpu(rp->handle));
- if (conn)
- conn->link_policy = __le16_to_cpu(rp->policy);
-
- hci_dev_unlock(hdev);
-}
-
-static void hci_cc_write_link_policy(struct hci_dev *hdev, struct sk_buff *skb)
-{
- struct hci_rp_write_link_policy *rp = (void *) skb->data;
- struct hci_conn *conn;
- void *sent;
-
- BT_DBG("%s status 0x%x", hdev->name, rp->status);
-
- if (rp->status)
- return;
-
- sent = hci_sent_cmd_data(hdev, HCI_OP_WRITE_LINK_POLICY);
- if (!sent)
- return;
-
- hci_dev_lock(hdev);
-
- conn = hci_conn_hash_lookup_handle(hdev, __le16_to_cpu(rp->handle));
- if (conn)
- conn->link_policy = get_unaligned_le16(sent + 2);
-
- hci_dev_unlock(hdev);
-}
-
-static void hci_cc_read_def_link_policy(struct hci_dev *hdev, struct sk_buff *skb)
-{
- struct hci_rp_read_def_link_policy *rp = (void *) skb->data;
-
- BT_DBG("%s status 0x%x", hdev->name, rp->status);
-
- if (rp->status)
- return;
-
- hdev->link_policy = __le16_to_cpu(rp->policy);
-}
-
-static void hci_cc_write_def_link_policy(struct hci_dev *hdev, struct sk_buff *skb)
-{
- __u8 status = *((__u8 *) skb->data);
- void *sent;
-
- BT_DBG("%s status 0x%x", hdev->name, status);
-
- sent = hci_sent_cmd_data(hdev, HCI_OP_WRITE_DEF_LINK_POLICY);
- if (!sent)
- return;
-
- if (!status)
- hdev->link_policy = get_unaligned_le16(sent);
-
- hci_req_complete(hdev, HCI_OP_WRITE_DEF_LINK_POLICY, status);
-}
-
-static void hci_cc_reset(struct hci_dev *hdev, struct sk_buff *skb)
-{
- __u8 status = *((__u8 *) skb->data);
-
- BT_DBG("%s status 0x%x", hdev->name, status);
-
- clear_bit(HCI_RESET, &hdev->flags);
-
- hci_req_complete(hdev, HCI_OP_RESET, status);
-
- /* Reset all non-persistent flags */
- hdev->dev_flags &= ~(BIT(HCI_LE_SCAN) | BIT(HCI_PENDING_CLASS));
-
- hdev->discovery.state = DISCOVERY_STOPPED;
-}
-
-static void hci_cc_write_local_name(struct hci_dev *hdev, struct sk_buff *skb)
-{
- __u8 status = *((__u8 *) skb->data);
- void *sent;
-
- BT_DBG("%s status 0x%x", hdev->name, status);
-
- sent = hci_sent_cmd_data(hdev, HCI_OP_WRITE_LOCAL_NAME);
- if (!sent)
- return;
-
- hci_dev_lock(hdev);
-
- if (test_bit(HCI_MGMT, &hdev->dev_flags))
- mgmt_set_local_name_complete(hdev, sent, status);
- else if (!status)
- memcpy(hdev->dev_name, sent, HCI_MAX_NAME_LENGTH);
-
- hci_dev_unlock(hdev);
-
- hci_req_complete(hdev, HCI_OP_WRITE_LOCAL_NAME, status);
-}
-
-static void hci_cc_read_local_name(struct hci_dev *hdev, struct sk_buff *skb)
-{
- struct hci_rp_read_local_name *rp = (void *) skb->data;
-
- BT_DBG("%s status 0x%x", hdev->name, rp->status);
-
- if (rp->status)
- return;
-
- if (test_bit(HCI_SETUP, &hdev->dev_flags))
- memcpy(hdev->dev_name, rp->name, HCI_MAX_NAME_LENGTH);
-}
-
-static void hci_cc_write_auth_enable(struct hci_dev *hdev, struct sk_buff *skb)
-{
- __u8 status = *((__u8 *) skb->data);
- void *sent;
-
- BT_DBG("%s status 0x%x", hdev->name, status);
-
- sent = hci_sent_cmd_data(hdev, HCI_OP_WRITE_AUTH_ENABLE);
- if (!sent)
- return;
-
- if (!status) {
- __u8 param = *((__u8 *) sent);
-
- if (param == AUTH_ENABLED)
- set_bit(HCI_AUTH, &hdev->flags);
- else
- clear_bit(HCI_AUTH, &hdev->flags);
- }
-
- if (test_bit(HCI_MGMT, &hdev->dev_flags))
- mgmt_auth_enable_complete(hdev, status);
-
- hci_req_complete(hdev, HCI_OP_WRITE_AUTH_ENABLE, status);
-}
-
-static void hci_cc_write_encrypt_mode(struct hci_dev *hdev, struct sk_buff *skb)
-{
- __u8 status = *((__u8 *) skb->data);
- void *sent;
-
- BT_DBG("%s status 0x%x", hdev->name, status);
-
- sent = hci_sent_cmd_data(hdev, HCI_OP_WRITE_ENCRYPT_MODE);
- if (!sent)
- return;
-
- if (!status) {
- __u8 param = *((__u8 *) sent);
-
- if (param)
- set_bit(HCI_ENCRYPT, &hdev->flags);
- else
- clear_bit(HCI_ENCRYPT, &hdev->flags);
- }
-
- hci_req_complete(hdev, HCI_OP_WRITE_ENCRYPT_MODE, status);
-}
-
-static void hci_cc_write_scan_enable(struct hci_dev *hdev, struct sk_buff *skb)
-{
- __u8 param, status = *((__u8 *) skb->data);
- int old_pscan, old_iscan;
- void *sent;
-
- BT_DBG("%s status 0x%x", hdev->name, status);
-
- sent = hci_sent_cmd_data(hdev, HCI_OP_WRITE_SCAN_ENABLE);
- if (!sent)
- return;
-
- param = *((__u8 *) sent);
-
- hci_dev_lock(hdev);
-
- if (status != 0) {
- mgmt_write_scan_failed(hdev, param, status);
- hdev->discov_timeout = 0;
- goto done;
- }
-
- old_pscan = test_and_clear_bit(HCI_PSCAN, &hdev->flags);
- old_iscan = test_and_clear_bit(HCI_ISCAN, &hdev->flags);
-
- if (param & SCAN_INQUIRY) {
- set_bit(HCI_ISCAN, &hdev->flags);
- if (!old_iscan)
- mgmt_discoverable(hdev, 1);
- if (hdev->discov_timeout > 0) {
- int to = msecs_to_jiffies(hdev->discov_timeout * 1000);
- queue_delayed_work(hdev->workqueue, &hdev->discov_off,
- to);
- }
- } else if (old_iscan)
- mgmt_discoverable(hdev, 0);
-
- if (param & SCAN_PAGE) {
- set_bit(HCI_PSCAN, &hdev->flags);
- if (!old_pscan)
- mgmt_connectable(hdev, 1);
- } else if (old_pscan)
- mgmt_connectable(hdev, 0);
-
-done:
- hci_dev_unlock(hdev);
- hci_req_complete(hdev, HCI_OP_WRITE_SCAN_ENABLE, status);
-}
-
-static void hci_cc_read_class_of_dev(struct hci_dev *hdev, struct sk_buff *skb)
-{
- struct hci_rp_read_class_of_dev *rp = (void *) skb->data;
-
- BT_DBG("%s status 0x%x", hdev->name, rp->status);
-
- if (rp->status)
- return;
-
- memcpy(hdev->dev_class, rp->dev_class, 3);
-
- BT_DBG("%s class 0x%.2x%.2x%.2x", hdev->name,
- hdev->dev_class[2], hdev->dev_class[1], hdev->dev_class[0]);
-}
-
-static void hci_cc_write_class_of_dev(struct hci_dev *hdev, struct sk_buff *skb)
-{
- __u8 status = *((__u8 *) skb->data);
- void *sent;
-
- BT_DBG("%s status 0x%x", hdev->name, status);
-
- sent = hci_sent_cmd_data(hdev, HCI_OP_WRITE_CLASS_OF_DEV);
- if (!sent)
- return;
-
- hci_dev_lock(hdev);
-
- if (status == 0)
- memcpy(hdev->dev_class, sent, 3);
-
- if (test_bit(HCI_MGMT, &hdev->dev_flags))
- mgmt_set_class_of_dev_complete(hdev, sent, status);
-
- hci_dev_unlock(hdev);
-}
-
-static void hci_cc_read_voice_setting(struct hci_dev *hdev, struct sk_buff *skb)
-{
- struct hci_rp_read_voice_setting *rp = (void *) skb->data;
- __u16 setting;
-
- BT_DBG("%s status 0x%x", hdev->name, rp->status);
-
- if (rp->status)
- return;
-
- setting = __le16_to_cpu(rp->voice_setting);
-
- if (hdev->voice_setting == setting)
- return;
-
- hdev->voice_setting = setting;
-
- BT_DBG("%s voice setting 0x%04x", hdev->name, setting);
-
- if (hdev->notify)
- hdev->notify(hdev, HCI_NOTIFY_VOICE_SETTING);
-}
-
-static void hci_cc_write_voice_setting(struct hci_dev *hdev, struct sk_buff *skb)
-{
- __u8 status = *((__u8 *) skb->data);
- __u16 setting;
- void *sent;
-
- BT_DBG("%s status 0x%x", hdev->name, status);
-
- if (status)
- return;
-
- sent = hci_sent_cmd_data(hdev, HCI_OP_WRITE_VOICE_SETTING);
- if (!sent)
- return;
-
- setting = get_unaligned_le16(sent);
-
- if (hdev->voice_setting == setting)
- return;
-
- hdev->voice_setting = setting;
-
- BT_DBG("%s voice setting 0x%04x", hdev->name, setting);
-
- if (hdev->notify)
- hdev->notify(hdev, HCI_NOTIFY_VOICE_SETTING);
-}
-
-static void hci_cc_host_buffer_size(struct hci_dev *hdev, struct sk_buff *skb)
-{
- __u8 status = *((__u8 *) skb->data);
-
- BT_DBG("%s status 0x%x", hdev->name, status);
-
- hci_req_complete(hdev, HCI_OP_HOST_BUFFER_SIZE, status);
-}
-
-static void hci_cc_write_ssp_mode(struct hci_dev *hdev, struct sk_buff *skb)
-{
- __u8 status = *((__u8 *) skb->data);
- void *sent;
-
- BT_DBG("%s status 0x%x", hdev->name, status);
-
- sent = hci_sent_cmd_data(hdev, HCI_OP_WRITE_SSP_MODE);
- if (!sent)
- return;
-
- if (test_bit(HCI_MGMT, &hdev->dev_flags))
- mgmt_ssp_enable_complete(hdev, *((u8 *) sent), status);
- else if (!status) {
- if (*((u8 *) sent))
- set_bit(HCI_SSP_ENABLED, &hdev->dev_flags);
- else
- clear_bit(HCI_SSP_ENABLED, &hdev->dev_flags);
- }
-}
-
-static u8 hci_get_inquiry_mode(struct hci_dev *hdev)
-{
- if (hdev->features[6] & LMP_EXT_INQ)
- return 2;
-
- if (hdev->features[3] & LMP_RSSI_INQ)
- return 1;
-
- if (hdev->manufacturer == 11 && hdev->hci_rev == 0x00 &&
- hdev->lmp_subver == 0x0757)
- return 1;
-
- if (hdev->manufacturer == 15) {
- if (hdev->hci_rev == 0x03 && hdev->lmp_subver == 0x6963)
- return 1;
- if (hdev->hci_rev == 0x09 && hdev->lmp_subver == 0x6963)
- return 1;
- if (hdev->hci_rev == 0x00 && hdev->lmp_subver == 0x6965)
- return 1;
- }
-
- if (hdev->manufacturer == 31 && hdev->hci_rev == 0x2005 &&
- hdev->lmp_subver == 0x1805)
- return 1;
-
- return 0;
-}
-
-static void hci_setup_inquiry_mode(struct hci_dev *hdev)
-{
- u8 mode;
-
- mode = hci_get_inquiry_mode(hdev);
-
- hci_send_cmd(hdev, HCI_OP_WRITE_INQUIRY_MODE, 1, &mode);
-}
-
-static void hci_setup_event_mask(struct hci_dev *hdev)
-{
- /* The second byte is 0xff instead of 0x9f (two reserved bits
- * disabled) since a Broadcom 1.2 dongle doesn't respond to the
- * command otherwise */
- u8 events[8] = { 0xff, 0xff, 0xfb, 0xff, 0x00, 0x00, 0x00, 0x00 };
-
- /* CSR 1.1 dongles does not accept any bitfield so don't try to set
- * any event mask for pre 1.2 devices */
- if (hdev->hci_ver < BLUETOOTH_VER_1_2)
- return;
-
- events[4] |= 0x01; /* Flow Specification Complete */
- events[4] |= 0x02; /* Inquiry Result with RSSI */
- events[4] |= 0x04; /* Read Remote Extended Features Complete */
- events[5] |= 0x08; /* Synchronous Connection Complete */
- events[5] |= 0x10; /* Synchronous Connection Changed */
-
- if (hdev->features[3] & LMP_RSSI_INQ)
- events[4] |= 0x02; /* Inquiry Result with RSSI */
-
- if (hdev->features[5] & LMP_SNIFF_SUBR)
- events[5] |= 0x20; /* Sniff Subrating */
-
- if (hdev->features[5] & LMP_PAUSE_ENC)
- events[5] |= 0x80; /* Encryption Key Refresh Complete */
-
- if (hdev->features[6] & LMP_EXT_INQ)
- events[5] |= 0x40; /* Extended Inquiry Result */
-
- if (hdev->features[6] & LMP_NO_FLUSH)
- events[7] |= 0x01; /* Enhanced Flush Complete */
-
- if (hdev->features[7] & LMP_LSTO)
- events[6] |= 0x80; /* Link Supervision Timeout Changed */
-
- if (hdev->features[6] & LMP_SIMPLE_PAIR) {
- events[6] |= 0x01; /* IO Capability Request */
- events[6] |= 0x02; /* IO Capability Response */
- events[6] |= 0x04; /* User Confirmation Request */
- events[6] |= 0x08; /* User Passkey Request */
- events[6] |= 0x10; /* Remote OOB Data Request */
- events[6] |= 0x20; /* Simple Pairing Complete */
- events[7] |= 0x04; /* User Passkey Notification */
- events[7] |= 0x08; /* Keypress Notification */
- events[7] |= 0x10; /* Remote Host Supported
- * Features Notification */
- }
-
- if (hdev->features[4] & LMP_LE)
- events[7] |= 0x20; /* LE Meta-Event */
-
- hci_send_cmd(hdev, HCI_OP_SET_EVENT_MASK, sizeof(events), events);
-}
-
-static void hci_setup(struct hci_dev *hdev)
-{
- if (hdev->dev_type != HCI_BREDR)
- return;
-
- hci_setup_event_mask(hdev);
-
- if (hdev->hci_ver > BLUETOOTH_VER_1_1)
- hci_send_cmd(hdev, HCI_OP_READ_LOCAL_COMMANDS, 0, NULL);
-
- if (hdev->features[6] & LMP_SIMPLE_PAIR) {
- if (test_bit(HCI_SSP_ENABLED, &hdev->dev_flags)) {
- u8 mode = 0x01;
- hci_send_cmd(hdev, HCI_OP_WRITE_SSP_MODE,
- sizeof(mode), &mode);
- } else {
- struct hci_cp_write_eir cp;
-
- memset(hdev->eir, 0, sizeof(hdev->eir));
- memset(&cp, 0, sizeof(cp));
-
- hci_send_cmd(hdev, HCI_OP_WRITE_EIR, sizeof(cp), &cp);
- }
- }
-
- if (hdev->features[3] & LMP_RSSI_INQ)
- hci_setup_inquiry_mode(hdev);
-
- if (hdev->features[7] & LMP_INQ_TX_PWR)
- hci_send_cmd(hdev, HCI_OP_READ_INQ_RSP_TX_POWER, 0, NULL);
-
- if (hdev->features[7] & LMP_EXTFEATURES) {
- struct hci_cp_read_local_ext_features cp;
-
- cp.page = 0x01;
- hci_send_cmd(hdev, HCI_OP_READ_LOCAL_EXT_FEATURES, sizeof(cp),
- &cp);
- }
-
- if (test_bit(HCI_LINK_SECURITY, &hdev->dev_flags)) {
- u8 enable = 1;
- hci_send_cmd(hdev, HCI_OP_WRITE_AUTH_ENABLE, sizeof(enable),
- &enable);
- }
-}
-
-static void hci_cc_read_local_version(struct hci_dev *hdev, struct sk_buff *skb)
-{
- struct hci_rp_read_local_version *rp = (void *) skb->data;
-
- BT_DBG("%s status 0x%x", hdev->name, rp->status);
-
- if (rp->status)
- goto done;
-
- hdev->hci_ver = rp->hci_ver;
- hdev->hci_rev = __le16_to_cpu(rp->hci_rev);
- hdev->lmp_ver = rp->lmp_ver;
- hdev->manufacturer = __le16_to_cpu(rp->manufacturer);
- hdev->lmp_subver = __le16_to_cpu(rp->lmp_subver);
-
- BT_DBG("%s manufacturer %d hci ver %d:%d", hdev->name,
- hdev->manufacturer,
- hdev->hci_ver, hdev->hci_rev);
-
- if (test_bit(HCI_INIT, &hdev->flags))
- hci_setup(hdev);
-
-done:
- hci_req_complete(hdev, HCI_OP_READ_LOCAL_VERSION, rp->status);
-}
-
-static void hci_setup_link_policy(struct hci_dev *hdev)
-{
- u16 link_policy = 0;
-
- if (hdev->features[0] & LMP_RSWITCH)
- link_policy |= HCI_LP_RSWITCH;
- if (hdev->features[0] & LMP_HOLD)
- link_policy |= HCI_LP_HOLD;
- if (hdev->features[0] & LMP_SNIFF)
- link_policy |= HCI_LP_SNIFF;
- if (hdev->features[1] & LMP_PARK)
- link_policy |= HCI_LP_PARK;
-
- link_policy = cpu_to_le16(link_policy);
- hci_send_cmd(hdev, HCI_OP_WRITE_DEF_LINK_POLICY, sizeof(link_policy),
- &link_policy);
-}
-
-static void hci_cc_read_local_commands(struct hci_dev *hdev, struct sk_buff *skb)
-{
- struct hci_rp_read_local_commands *rp = (void *) skb->data;
-
- BT_DBG("%s status 0x%x", hdev->name, rp->status);
-
- if (rp->status)
- goto done;
-
- memcpy(hdev->commands, rp->commands, sizeof(hdev->commands));
-
- if (test_bit(HCI_INIT, &hdev->flags) && (hdev->commands[5] & 0x10))
- hci_setup_link_policy(hdev);
-
-done:
- hci_req_complete(hdev, HCI_OP_READ_LOCAL_COMMANDS, rp->status);
-}
-
-static void hci_cc_read_local_features(struct hci_dev *hdev, struct sk_buff *skb)
-{
- struct hci_rp_read_local_features *rp = (void *) skb->data;
-
- BT_DBG("%s status 0x%x", hdev->name, rp->status);
-
- if (rp->status)
- return;
-
- memcpy(hdev->features, rp->features, 8);
-
- /* Adjust default settings according to features
- * supported by device. */
-
- if (hdev->features[0] & LMP_3SLOT)
- hdev->pkt_type |= (HCI_DM3 | HCI_DH3);
-
- if (hdev->features[0] & LMP_5SLOT)
- hdev->pkt_type |= (HCI_DM5 | HCI_DH5);
-
- if (hdev->features[1] & LMP_HV2) {
- hdev->pkt_type |= (HCI_HV2);
- hdev->esco_type |= (ESCO_HV2);
- }
-
- if (hdev->features[1] & LMP_HV3) {
- hdev->pkt_type |= (HCI_HV3);
- hdev->esco_type |= (ESCO_HV3);
- }
-
- if (hdev->features[3] & LMP_ESCO)
- hdev->esco_type |= (ESCO_EV3);
-
- if (hdev->features[4] & LMP_EV4)
- hdev->esco_type |= (ESCO_EV4);
-
- if (hdev->features[4] & LMP_EV5)
- hdev->esco_type |= (ESCO_EV5);
-
- if (hdev->features[5] & LMP_EDR_ESCO_2M)
- hdev->esco_type |= (ESCO_2EV3);
-
- if (hdev->features[5] & LMP_EDR_ESCO_3M)
- hdev->esco_type |= (ESCO_3EV3);
-
- if (hdev->features[5] & LMP_EDR_3S_ESCO)
- hdev->esco_type |= (ESCO_2EV5 | ESCO_3EV5);
-
- BT_DBG("%s features 0x%.2x%.2x%.2x%.2x%.2x%.2x%.2x%.2x", hdev->name,
- hdev->features[0], hdev->features[1],
- hdev->features[2], hdev->features[3],
- hdev->features[4], hdev->features[5],
- hdev->features[6], hdev->features[7]);
-}
-
-static void hci_set_le_support(struct hci_dev *hdev)
-{
- struct hci_cp_write_le_host_supported cp;
-
- memset(&cp, 0, sizeof(cp));
-
- if (enable_le && test_bit(HCI_LE_ENABLED, &hdev->dev_flags)) {
- cp.le = 1;
- cp.simul = !!(hdev->features[6] & LMP_SIMUL_LE_BR);
- }
-
- if (cp.le != !!(hdev->host_features[0] & LMP_HOST_LE))
- hci_send_cmd(hdev, HCI_OP_WRITE_LE_HOST_SUPPORTED, sizeof(cp),
- &cp);
-}
-
-static void hci_cc_read_local_ext_features(struct hci_dev *hdev,
- struct sk_buff *skb)
-{
- struct hci_rp_read_local_ext_features *rp = (void *) skb->data;
-
- BT_DBG("%s status 0x%x", hdev->name, rp->status);
-
- if (rp->status)
- goto done;
-
- switch (rp->page) {
- case 0:
- memcpy(hdev->features, rp->features, 8);
- break;
- case 1:
- memcpy(hdev->host_features, rp->features, 8);
- break;
- }
-
- if (test_bit(HCI_INIT, &hdev->flags) && hdev->features[4] & LMP_LE)
- hci_set_le_support(hdev);
-
-done:
- hci_req_complete(hdev, HCI_OP_READ_LOCAL_EXT_FEATURES, rp->status);
-}
-
-static void hci_cc_read_flow_control_mode(struct hci_dev *hdev,
- struct sk_buff *skb)
-{
- struct hci_rp_read_flow_control_mode *rp = (void *) skb->data;
-
- BT_DBG("%s status 0x%x", hdev->name, rp->status);
-
- if (rp->status)
- return;
-
- hdev->flow_ctl_mode = rp->mode;
-
- hci_req_complete(hdev, HCI_OP_READ_FLOW_CONTROL_MODE, rp->status);
-}
-
-static void hci_cc_read_buffer_size(struct hci_dev *hdev, struct sk_buff *skb)
-{
- struct hci_rp_read_buffer_size *rp = (void *) skb->data;
-
- BT_DBG("%s status 0x%x", hdev->name, rp->status);
-
- if (rp->status)
- return;
-
- hdev->acl_mtu = __le16_to_cpu(rp->acl_mtu);
- hdev->sco_mtu = rp->sco_mtu;
- hdev->acl_pkts = __le16_to_cpu(rp->acl_max_pkt);
- hdev->sco_pkts = __le16_to_cpu(rp->sco_max_pkt);
-
- if (test_bit(HCI_QUIRK_FIXUP_BUFFER_SIZE, &hdev->quirks)) {
- hdev->sco_mtu = 64;
- hdev->sco_pkts = 8;
- }
-
- hdev->acl_cnt = hdev->acl_pkts;
- hdev->sco_cnt = hdev->sco_pkts;
-
- BT_DBG("%s acl mtu %d:%d sco mtu %d:%d", hdev->name,
- hdev->acl_mtu, hdev->acl_pkts,
- hdev->sco_mtu, hdev->sco_pkts);
-}
-
-static void hci_cc_read_bd_addr(struct hci_dev *hdev, struct sk_buff *skb)
-{
- struct hci_rp_read_bd_addr *rp = (void *) skb->data;
-
- BT_DBG("%s status 0x%x", hdev->name, rp->status);
-
- if (!rp->status)
- bacpy(&hdev->bdaddr, &rp->bdaddr);
-
- hci_req_complete(hdev, HCI_OP_READ_BD_ADDR, rp->status);
-}
-
-static void hci_cc_read_data_block_size(struct hci_dev *hdev,
- struct sk_buff *skb)
-{
- struct hci_rp_read_data_block_size *rp = (void *) skb->data;
-
- BT_DBG("%s status 0x%x", hdev->name, rp->status);
-
- if (rp->status)
- return;
-
- hdev->block_mtu = __le16_to_cpu(rp->max_acl_len);
- hdev->block_len = __le16_to_cpu(rp->block_len);
- hdev->num_blocks = __le16_to_cpu(rp->num_blocks);
-
- hdev->block_cnt = hdev->num_blocks;
-
- BT_DBG("%s blk mtu %d cnt %d len %d", hdev->name, hdev->block_mtu,
- hdev->block_cnt, hdev->block_len);
-
- hci_req_complete(hdev, HCI_OP_READ_DATA_BLOCK_SIZE, rp->status);
-}
-
-static void hci_cc_write_ca_timeout(struct hci_dev *hdev, struct sk_buff *skb)
-{
- __u8 status = *((__u8 *) skb->data);
-
- BT_DBG("%s status 0x%x", hdev->name, status);
-
- hci_req_complete(hdev, HCI_OP_WRITE_CA_TIMEOUT, status);
-}
-
-static void hci_cc_read_local_amp_info(struct hci_dev *hdev,
- struct sk_buff *skb)
-{
- struct hci_rp_read_local_amp_info *rp = (void *) skb->data;
-
- BT_DBG("%s status 0x%x", hdev->name, rp->status);
-
- if (rp->status)
- return;
-
- hdev->amp_status = rp->amp_status;
- hdev->amp_total_bw = __le32_to_cpu(rp->total_bw);
- hdev->amp_max_bw = __le32_to_cpu(rp->max_bw);
- hdev->amp_min_latency = __le32_to_cpu(rp->min_latency);
- hdev->amp_max_pdu = __le32_to_cpu(rp->max_pdu);
- hdev->amp_type = rp->amp_type;
- hdev->amp_pal_cap = __le16_to_cpu(rp->pal_cap);
- hdev->amp_assoc_size = __le16_to_cpu(rp->max_assoc_size);
- hdev->amp_be_flush_to = __le32_to_cpu(rp->be_flush_to);
- hdev->amp_max_flush_to = __le32_to_cpu(rp->max_flush_to);
-
- hci_req_complete(hdev, HCI_OP_READ_LOCAL_AMP_INFO, rp->status);
-}
-
-static void hci_cc_delete_stored_link_key(struct hci_dev *hdev,
- struct sk_buff *skb)
-{
- __u8 status = *((__u8 *) skb->data);
-
- BT_DBG("%s status 0x%x", hdev->name, status);
-
- hci_req_complete(hdev, HCI_OP_DELETE_STORED_LINK_KEY, status);
-}
-
-static void hci_cc_set_event_mask(struct hci_dev *hdev, struct sk_buff *skb)
-{
- __u8 status = *((__u8 *) skb->data);
-
- BT_DBG("%s status 0x%x", hdev->name, status);
-
- hci_req_complete(hdev, HCI_OP_SET_EVENT_MASK, status);
-}
-
-static void hci_cc_write_inquiry_mode(struct hci_dev *hdev,
- struct sk_buff *skb)
-{
- __u8 status = *((__u8 *) skb->data);
-
- BT_DBG("%s status 0x%x", hdev->name, status);
-
- hci_req_complete(hdev, HCI_OP_WRITE_INQUIRY_MODE, status);
-}
-
-static void hci_cc_read_inq_rsp_tx_power(struct hci_dev *hdev,
- struct sk_buff *skb)
-{
- __u8 status = *((__u8 *) skb->data);
-
- BT_DBG("%s status 0x%x", hdev->name, status);
-
- hci_req_complete(hdev, HCI_OP_READ_INQ_RSP_TX_POWER, status);
-}
-
-static void hci_cc_set_event_flt(struct hci_dev *hdev, struct sk_buff *skb)
-{
- __u8 status = *((__u8 *) skb->data);
-
- BT_DBG("%s status 0x%x", hdev->name, status);
-
- hci_req_complete(hdev, HCI_OP_SET_EVENT_FLT, status);
-}
-
-static void hci_cc_pin_code_reply(struct hci_dev *hdev, struct sk_buff *skb)
-{
- struct hci_rp_pin_code_reply *rp = (void *) skb->data;
- struct hci_cp_pin_code_reply *cp;
- struct hci_conn *conn;
-
- BT_DBG("%s status 0x%x", hdev->name, rp->status);
-
- hci_dev_lock(hdev);
-
- if (test_bit(HCI_MGMT, &hdev->dev_flags))
- mgmt_pin_code_reply_complete(hdev, &rp->bdaddr, rp->status);
-
- if (rp->status != 0)
- goto unlock;
-
- cp = hci_sent_cmd_data(hdev, HCI_OP_PIN_CODE_REPLY);
- if (!cp)
- goto unlock;
-
- conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &cp->bdaddr);
- if (conn)
- conn->pin_length = cp->pin_len;
-
-unlock:
- hci_dev_unlock(hdev);
-}
-
-static void hci_cc_pin_code_neg_reply(struct hci_dev *hdev, struct sk_buff *skb)
-{
- struct hci_rp_pin_code_neg_reply *rp = (void *) skb->data;
-
- BT_DBG("%s status 0x%x", hdev->name, rp->status);
-
- hci_dev_lock(hdev);
-
- if (test_bit(HCI_MGMT, &hdev->dev_flags))
- mgmt_pin_code_neg_reply_complete(hdev, &rp->bdaddr,
- rp->status);
-
- hci_dev_unlock(hdev);
-}
-
-static void hci_cc_le_read_buffer_size(struct hci_dev *hdev,
- struct sk_buff *skb)
-{
- struct hci_rp_le_read_buffer_size *rp = (void *) skb->data;
-
- BT_DBG("%s status 0x%x", hdev->name, rp->status);
-
- if (rp->status)
- return;
-
- hdev->le_mtu = __le16_to_cpu(rp->le_mtu);
- hdev->le_pkts = rp->le_max_pkt;
-
- hdev->le_cnt = hdev->le_pkts;
-
- BT_DBG("%s le mtu %d:%d", hdev->name, hdev->le_mtu, hdev->le_pkts);
-
- hci_req_complete(hdev, HCI_OP_LE_READ_BUFFER_SIZE, rp->status);
-}
-
-static void hci_cc_user_confirm_reply(struct hci_dev *hdev, struct sk_buff *skb)
-{
- struct hci_rp_user_confirm_reply *rp = (void *) skb->data;
-
- BT_DBG("%s status 0x%x", hdev->name, rp->status);
-
- hci_dev_lock(hdev);
-
- if (test_bit(HCI_MGMT, &hdev->dev_flags))
- mgmt_user_confirm_reply_complete(hdev, &rp->bdaddr, ACL_LINK, 0,
- rp->status);
-
- hci_dev_unlock(hdev);
-}
-
-static void hci_cc_user_confirm_neg_reply(struct hci_dev *hdev,
- struct sk_buff *skb)
-{
- struct hci_rp_user_confirm_reply *rp = (void *) skb->data;
-
- BT_DBG("%s status 0x%x", hdev->name, rp->status);
-
- hci_dev_lock(hdev);
-
- if (test_bit(HCI_MGMT, &hdev->dev_flags))
- mgmt_user_confirm_neg_reply_complete(hdev, &rp->bdaddr,
- ACL_LINK, 0, rp->status);
-
- hci_dev_unlock(hdev);
-}
-
-static void hci_cc_user_passkey_reply(struct hci_dev *hdev, struct sk_buff *skb)
-{
- struct hci_rp_user_confirm_reply *rp = (void *) skb->data;
-
- BT_DBG("%s status 0x%x", hdev->name, rp->status);
-
- hci_dev_lock(hdev);
-
- if (test_bit(HCI_MGMT, &hdev->dev_flags))
- mgmt_user_passkey_reply_complete(hdev, &rp->bdaddr, ACL_LINK,
- 0, rp->status);
-
- hci_dev_unlock(hdev);
-}
-
-static void hci_cc_user_passkey_neg_reply(struct hci_dev *hdev,
- struct sk_buff *skb)
-{
- struct hci_rp_user_confirm_reply *rp = (void *) skb->data;
-
- BT_DBG("%s status 0x%x", hdev->name, rp->status);
-
- hci_dev_lock(hdev);
-
- if (test_bit(HCI_MGMT, &hdev->dev_flags))
- mgmt_user_passkey_neg_reply_complete(hdev, &rp->bdaddr,
- ACL_LINK, 0, rp->status);
-
- hci_dev_unlock(hdev);
-}
-
-static void hci_cc_read_local_oob_data_reply(struct hci_dev *hdev,
- struct sk_buff *skb)
-{
- struct hci_rp_read_local_oob_data *rp = (void *) skb->data;
-
- BT_DBG("%s status 0x%x", hdev->name, rp->status);
-
- hci_dev_lock(hdev);
- mgmt_read_local_oob_data_reply_complete(hdev, rp->hash,
- rp->randomizer, rp->status);
- hci_dev_unlock(hdev);
-}
-
-static void hci_cc_le_set_scan_param(struct hci_dev *hdev, struct sk_buff *skb)
-{
- __u8 status = *((__u8 *) skb->data);
-
- BT_DBG("%s status 0x%x", hdev->name, status);
-
- hci_req_complete(hdev, HCI_OP_LE_SET_SCAN_PARAM, status);
-
- if (status) {
- hci_dev_lock(hdev);
- mgmt_start_discovery_failed(hdev, status);
- hci_dev_unlock(hdev);
- return;
- }
-}
-
-static void hci_cc_le_set_scan_enable(struct hci_dev *hdev,
- struct sk_buff *skb)
-{
- struct hci_cp_le_set_scan_enable *cp;
- __u8 status = *((__u8 *) skb->data);
-
- BT_DBG("%s status 0x%x", hdev->name, status);
-
- cp = hci_sent_cmd_data(hdev, HCI_OP_LE_SET_SCAN_ENABLE);
- if (!cp)
- return;
-
- switch (cp->enable) {
- case LE_SCANNING_ENABLED:
- hci_req_complete(hdev, HCI_OP_LE_SET_SCAN_ENABLE, status);
-
- if (status) {
- hci_dev_lock(hdev);
- mgmt_start_discovery_failed(hdev, status);
- hci_dev_unlock(hdev);
- return;
- }
-
- set_bit(HCI_LE_SCAN, &hdev->dev_flags);
-
- cancel_delayed_work_sync(&hdev->adv_work);
-
- hci_dev_lock(hdev);
- hci_adv_entries_clear(hdev);
- hci_discovery_set_state(hdev, DISCOVERY_FINDING);
- hci_dev_unlock(hdev);
- break;
-
- case LE_SCANNING_DISABLED:
- if (status)
- return;
-
- clear_bit(HCI_LE_SCAN, &hdev->dev_flags);
-
- schedule_delayed_work(&hdev->adv_work, ADV_CLEAR_TIMEOUT);
-
- if (hdev->discovery.type == DISCOV_TYPE_INTERLEAVED) {
- mgmt_interleaved_discovery(hdev);
- } else {
- hci_dev_lock(hdev);
- hci_discovery_set_state(hdev, DISCOVERY_STOPPED);
- hci_dev_unlock(hdev);
- }
-
- break;
-
- default:
- BT_ERR("Used reserved LE_Scan_Enable param %d", cp->enable);
- break;
- }
-}
-
-static void hci_cc_le_ltk_reply(struct hci_dev *hdev, struct sk_buff *skb)
-{
- struct hci_rp_le_ltk_reply *rp = (void *) skb->data;
-
- BT_DBG("%s status 0x%x", hdev->name, rp->status);
-
- if (rp->status)
- return;
-
- hci_req_complete(hdev, HCI_OP_LE_LTK_REPLY, rp->status);
-}
-
-static void hci_cc_le_ltk_neg_reply(struct hci_dev *hdev, struct sk_buff *skb)
-{
- struct hci_rp_le_ltk_neg_reply *rp = (void *) skb->data;
-
- BT_DBG("%s status 0x%x", hdev->name, rp->status);
-
- if (rp->status)
- return;
-
- hci_req_complete(hdev, HCI_OP_LE_LTK_NEG_REPLY, rp->status);
-}
-
-static inline void hci_cc_write_le_host_supported(struct hci_dev *hdev,
- struct sk_buff *skb)
-{
- struct hci_cp_write_le_host_supported *sent;
- __u8 status = *((__u8 *) skb->data);
-
- BT_DBG("%s status 0x%x", hdev->name, status);
-
- sent = hci_sent_cmd_data(hdev, HCI_OP_WRITE_LE_HOST_SUPPORTED);
- if (!sent)
- return;
-
- if (!status) {
- if (sent->le)
- hdev->host_features[0] |= LMP_HOST_LE;
- else
- hdev->host_features[0] &= ~LMP_HOST_LE;
- }
-
- if (test_bit(HCI_MGMT, &hdev->dev_flags) &&
- !test_bit(HCI_INIT, &hdev->flags))
- mgmt_le_enable_complete(hdev, sent->le, status);
-
- hci_req_complete(hdev, HCI_OP_WRITE_LE_HOST_SUPPORTED, status);
-}
-
-static inline void hci_cs_inquiry(struct hci_dev *hdev, __u8 status)
-{
- BT_DBG("%s status 0x%x", hdev->name, status);
-
- if (status) {
- hci_req_complete(hdev, HCI_OP_INQUIRY, status);
- hci_conn_check_pending(hdev);
- hci_dev_lock(hdev);
- if (test_bit(HCI_MGMT, &hdev->dev_flags))
- mgmt_start_discovery_failed(hdev, status);
- hci_dev_unlock(hdev);
- return;
- }
-
- set_bit(HCI_INQUIRY, &hdev->flags);
-
- hci_dev_lock(hdev);
- hci_discovery_set_state(hdev, DISCOVERY_FINDING);
- hci_dev_unlock(hdev);
-}
-
-static inline void hci_cs_create_conn(struct hci_dev *hdev, __u8 status)
-{
- struct hci_cp_create_conn *cp;
- struct hci_conn *conn;
-
- BT_DBG("%s status 0x%x", hdev->name, status);
-
- cp = hci_sent_cmd_data(hdev, HCI_OP_CREATE_CONN);
- if (!cp)
- return;
-
- hci_dev_lock(hdev);
-
- conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &cp->bdaddr);
-
- BT_DBG("%s bdaddr %s conn %p", hdev->name, batostr(&cp->bdaddr), conn);
-
- if (status) {
- if (conn && conn->state == BT_CONNECT) {
- if (status != 0x0c || conn->attempt > 2) {
- conn->state = BT_CLOSED;
- hci_proto_connect_cfm(conn, status);
- hci_conn_del(conn);
- } else
- conn->state = BT_CONNECT2;
- }
- } else {
- if (!conn) {
- conn = hci_conn_add(hdev, ACL_LINK, &cp->bdaddr);
- if (conn) {
- conn->out = true;
- conn->link_mode |= HCI_LM_MASTER;
- } else
- BT_ERR("No memory for new connection");
- }
- }
-
- hci_dev_unlock(hdev);
-}
-
-static void hci_cs_add_sco(struct hci_dev *hdev, __u8 status)
-{
- struct hci_cp_add_sco *cp;
- struct hci_conn *acl, *sco;
- __u16 handle;
-
- BT_DBG("%s status 0x%x", hdev->name, status);
-
- if (!status)
- return;
-
- cp = hci_sent_cmd_data(hdev, HCI_OP_ADD_SCO);
- if (!cp)
- return;
-
- handle = __le16_to_cpu(cp->handle);
-
- BT_DBG("%s handle %d", hdev->name, handle);
-
- hci_dev_lock(hdev);
-
- acl = hci_conn_hash_lookup_handle(hdev, handle);
- if (acl) {
- sco = acl->link;
- if (sco) {
- sco->state = BT_CLOSED;
-
- hci_proto_connect_cfm(sco, status);
- hci_conn_del(sco);
- }
- }
-
- hci_dev_unlock(hdev);
-}
-
-static void hci_cs_auth_requested(struct hci_dev *hdev, __u8 status)
-{
- struct hci_cp_auth_requested *cp;
- struct hci_conn *conn;
-
- BT_DBG("%s status 0x%x", hdev->name, status);
-
- if (!status)
- return;
-
- cp = hci_sent_cmd_data(hdev, HCI_OP_AUTH_REQUESTED);
- if (!cp)
- return;
-
- hci_dev_lock(hdev);
-
- conn = hci_conn_hash_lookup_handle(hdev, __le16_to_cpu(cp->handle));
- if (conn) {
- if (conn->state == BT_CONFIG) {
- hci_proto_connect_cfm(conn, status);
- hci_conn_put(conn);
- }
- }
-
- hci_dev_unlock(hdev);
-}
-
-static void hci_cs_set_conn_encrypt(struct hci_dev *hdev, __u8 status)
-{
- struct hci_cp_set_conn_encrypt *cp;
- struct hci_conn *conn;
-
- BT_DBG("%s status 0x%x", hdev->name, status);
-
- if (!status)
- return;
-
- cp = hci_sent_cmd_data(hdev, HCI_OP_SET_CONN_ENCRYPT);
- if (!cp)
- return;
-
- hci_dev_lock(hdev);
-
- conn = hci_conn_hash_lookup_handle(hdev, __le16_to_cpu(cp->handle));
- if (conn) {
- if (conn->state == BT_CONFIG) {
- hci_proto_connect_cfm(conn, status);
- hci_conn_put(conn);
- }
- }
-
- hci_dev_unlock(hdev);
-}
-
-static int hci_outgoing_auth_needed(struct hci_dev *hdev,
- struct hci_conn *conn)
-{
- if (conn->state != BT_CONFIG || !conn->out)
- return 0;
-
- if (conn->pending_sec_level == BT_SECURITY_SDP)
- return 0;
-
- /* Only request authentication for SSP connections or non-SSP
- * devices with sec_level HIGH or if MITM protection is requested */
- if (!hci_conn_ssp_enabled(conn) &&
- conn->pending_sec_level != BT_SECURITY_HIGH &&
- !(conn->auth_type & 0x01))
- return 0;
-
- return 1;
-}
-
-static inline int hci_resolve_name(struct hci_dev *hdev,
- struct inquiry_entry *e)
-{
- struct hci_cp_remote_name_req cp;
-
- memset(&cp, 0, sizeof(cp));
-
- bacpy(&cp.bdaddr, &e->data.bdaddr);
- cp.pscan_rep_mode = e->data.pscan_rep_mode;
- cp.pscan_mode = e->data.pscan_mode;
- cp.clock_offset = e->data.clock_offset;
-
- return hci_send_cmd(hdev, HCI_OP_REMOTE_NAME_REQ, sizeof(cp), &cp);
-}
-
-static bool hci_resolve_next_name(struct hci_dev *hdev)
-{
- struct discovery_state *discov = &hdev->discovery;
- struct inquiry_entry *e;
-
- if (list_empty(&discov->resolve))
- return false;
-
- e = hci_inquiry_cache_lookup_resolve(hdev, BDADDR_ANY, NAME_NEEDED);
- if (hci_resolve_name(hdev, e) == 0) {
- e->name_state = NAME_PENDING;
- return true;
- }
-
- return false;
-}
-
-static void hci_check_pending_name(struct hci_dev *hdev, struct hci_conn *conn,
- bdaddr_t *bdaddr, u8 *name, u8 name_len)
-{
- struct discovery_state *discov = &hdev->discovery;
- struct inquiry_entry *e;
-
- if (conn && !test_and_set_bit(HCI_CONN_MGMT_CONNECTED, &conn->flags))
- mgmt_device_connected(hdev, bdaddr, ACL_LINK, 0x00, 0, name,
- name_len, conn->dev_class);
-
- if (discov->state == DISCOVERY_STOPPED)
- return;
-
- if (discov->state == DISCOVERY_STOPPING)
- goto discov_complete;
-
- if (discov->state != DISCOVERY_RESOLVING)
- return;
-
- e = hci_inquiry_cache_lookup_resolve(hdev, bdaddr, NAME_PENDING);
- if (e) {
- e->name_state = NAME_KNOWN;
- list_del(&e->list);
- if (name)
- mgmt_remote_name(hdev, bdaddr, ACL_LINK, 0x00,
- e->data.rssi, name, name_len);
- }
-
- if (hci_resolve_next_name(hdev))
- return;
-
-discov_complete:
- hci_discovery_set_state(hdev, DISCOVERY_STOPPED);
-}
-
-static void hci_cs_remote_name_req(struct hci_dev *hdev, __u8 status)
-{
- struct hci_cp_remote_name_req *cp;
- struct hci_conn *conn;
-
- BT_DBG("%s status 0x%x", hdev->name, status);
-
- /* If successful wait for the name req complete event before
- * checking for the need to do authentication */
- if (!status)
- return;
-
- cp = hci_sent_cmd_data(hdev, HCI_OP_REMOTE_NAME_REQ);
- if (!cp)
- return;
-
- hci_dev_lock(hdev);
-
- conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &cp->bdaddr);
-
- if (test_bit(HCI_MGMT, &hdev->dev_flags))
- hci_check_pending_name(hdev, conn, &cp->bdaddr, NULL, 0);
-
- if (!conn)
- goto unlock;
-
- if (!hci_outgoing_auth_needed(hdev, conn))
- goto unlock;
-
- if (!test_and_set_bit(HCI_CONN_AUTH_PEND, &conn->flags)) {
- struct hci_cp_auth_requested cp;
- cp.handle = __cpu_to_le16(conn->handle);
- hci_send_cmd(hdev, HCI_OP_AUTH_REQUESTED, sizeof(cp), &cp);
- }
-
-unlock:
- hci_dev_unlock(hdev);
-}
-
-static void hci_cs_read_remote_features(struct hci_dev *hdev, __u8 status)
-{
- struct hci_cp_read_remote_features *cp;
- struct hci_conn *conn;
-
- BT_DBG("%s status 0x%x", hdev->name, status);
-
- if (!status)
- return;
-
- cp = hci_sent_cmd_data(hdev, HCI_OP_READ_REMOTE_FEATURES);
- if (!cp)
- return;
-
- hci_dev_lock(hdev);
-
- conn = hci_conn_hash_lookup_handle(hdev, __le16_to_cpu(cp->handle));
- if (conn) {
- if (conn->state == BT_CONFIG) {
- hci_proto_connect_cfm(conn, status);
- hci_conn_put(conn);
- }
- }
-
- hci_dev_unlock(hdev);
-}
-
-static void hci_cs_read_remote_ext_features(struct hci_dev *hdev, __u8 status)
-{
- struct hci_cp_read_remote_ext_features *cp;
- struct hci_conn *conn;
-
- BT_DBG("%s status 0x%x", hdev->name, status);
-
- if (!status)
- return;
-
- cp = hci_sent_cmd_data(hdev, HCI_OP_READ_REMOTE_EXT_FEATURES);
- if (!cp)
- return;
-
- hci_dev_lock(hdev);
-
- conn = hci_conn_hash_lookup_handle(hdev, __le16_to_cpu(cp->handle));
- if (conn) {
- if (conn->state == BT_CONFIG) {
- hci_proto_connect_cfm(conn, status);
- hci_conn_put(conn);
- }
- }
-
- hci_dev_unlock(hdev);
-}
-
-static void hci_cs_setup_sync_conn(struct hci_dev *hdev, __u8 status)
-{
- struct hci_cp_setup_sync_conn *cp;
- struct hci_conn *acl, *sco;
- __u16 handle;
-
- BT_DBG("%s status 0x%x", hdev->name, status);
-
- if (!status)
- return;
-
- cp = hci_sent_cmd_data(hdev, HCI_OP_SETUP_SYNC_CONN);
- if (!cp)
- return;
-
- handle = __le16_to_cpu(cp->handle);
-
- BT_DBG("%s handle %d", hdev->name, handle);
-
- hci_dev_lock(hdev);
-
- acl = hci_conn_hash_lookup_handle(hdev, handle);
- if (acl) {
- sco = acl->link;
- if (sco) {
- sco->state = BT_CLOSED;
-
- hci_proto_connect_cfm(sco, status);
- hci_conn_del(sco);
- }
- }
-
- hci_dev_unlock(hdev);
-}
-
-static void hci_cs_sniff_mode(struct hci_dev *hdev, __u8 status)
-{
- struct hci_cp_sniff_mode *cp;
- struct hci_conn *conn;
-
- BT_DBG("%s status 0x%x", hdev->name, status);
-
- if (!status)
- return;
-
- cp = hci_sent_cmd_data(hdev, HCI_OP_SNIFF_MODE);
- if (!cp)
- return;
-
- hci_dev_lock(hdev);
-
- conn = hci_conn_hash_lookup_handle(hdev, __le16_to_cpu(cp->handle));
- if (conn) {
- clear_bit(HCI_CONN_MODE_CHANGE_PEND, &conn->flags);
-
- if (test_and_clear_bit(HCI_CONN_SCO_SETUP_PEND, &conn->flags))
- hci_sco_setup(conn, status);
- }
-
- hci_dev_unlock(hdev);
-}
-
-static void hci_cs_exit_sniff_mode(struct hci_dev *hdev, __u8 status)
-{
- struct hci_cp_exit_sniff_mode *cp;
- struct hci_conn *conn;
-
- BT_DBG("%s status 0x%x", hdev->name, status);
-
- if (!status)
- return;
-
- cp = hci_sent_cmd_data(hdev, HCI_OP_EXIT_SNIFF_MODE);
- if (!cp)
- return;
-
- hci_dev_lock(hdev);
-
- conn = hci_conn_hash_lookup_handle(hdev, __le16_to_cpu(cp->handle));
- if (conn) {
- clear_bit(HCI_CONN_MODE_CHANGE_PEND, &conn->flags);
-
- if (test_and_clear_bit(HCI_CONN_SCO_SETUP_PEND, &conn->flags))
- hci_sco_setup(conn, status);
- }
-
- hci_dev_unlock(hdev);
-}
-
-static void hci_cs_disconnect(struct hci_dev *hdev, u8 status)
-{
- struct hci_cp_disconnect *cp;
- struct hci_conn *conn;
-
- if (!status)
- return;
-
- cp = hci_sent_cmd_data(hdev, HCI_OP_DISCONNECT);
- if (!cp)
- return;
-
- hci_dev_lock(hdev);
-
- conn = hci_conn_hash_lookup_handle(hdev, __le16_to_cpu(cp->handle));
- if (conn)
- mgmt_disconnect_failed(hdev, &conn->dst, conn->type,
- conn->dst_type, status);
-
- hci_dev_unlock(hdev);
-}
-
-static void hci_cs_le_create_conn(struct hci_dev *hdev, __u8 status)
-{
- struct hci_cp_le_create_conn *cp;
- struct hci_conn *conn;
-
- BT_DBG("%s status 0x%x", hdev->name, status);
-
- cp = hci_sent_cmd_data(hdev, HCI_OP_LE_CREATE_CONN);
- if (!cp)
- return;
-
- hci_dev_lock(hdev);
-
- conn = hci_conn_hash_lookup_ba(hdev, LE_LINK, &cp->peer_addr);
-
- BT_DBG("%s bdaddr %s conn %p", hdev->name, batostr(&cp->peer_addr),
- conn);
-
- if (status) {
- if (conn && conn->state == BT_CONNECT) {
- conn->state = BT_CLOSED;
- hci_proto_connect_cfm(conn, status);
- hci_conn_del(conn);
- }
- } else {
- if (!conn) {
- conn = hci_conn_add(hdev, LE_LINK, &cp->peer_addr);
- if (conn) {
- conn->dst_type = cp->peer_addr_type;
- conn->out = true;
- } else {
- BT_ERR("No memory for new connection");
- }
- }
- }
-
- hci_dev_unlock(hdev);
-}
-
-static void hci_cs_le_start_enc(struct hci_dev *hdev, u8 status)
-{
- BT_DBG("%s status 0x%x", hdev->name, status);
-}
-
-static inline void hci_inquiry_complete_evt(struct hci_dev *hdev, struct sk_buff *skb)
-{
- __u8 status = *((__u8 *) skb->data);
- struct discovery_state *discov = &hdev->discovery;
- struct inquiry_entry *e;
-
- BT_DBG("%s status %d", hdev->name, status);
-
- hci_req_complete(hdev, HCI_OP_INQUIRY, status);
-
- hci_conn_check_pending(hdev);
-
- if (!test_and_clear_bit(HCI_INQUIRY, &hdev->flags))
- return;
-
- if (!test_bit(HCI_MGMT, &hdev->dev_flags))
- return;
-
- hci_dev_lock(hdev);
-
- if (discov->state != DISCOVERY_FINDING)
- goto unlock;
-
- if (list_empty(&discov->resolve)) {
- hci_discovery_set_state(hdev, DISCOVERY_STOPPED);
- goto unlock;
- }
-
- e = hci_inquiry_cache_lookup_resolve(hdev, BDADDR_ANY, NAME_NEEDED);
- if (e && hci_resolve_name(hdev, e) == 0) {
- e->name_state = NAME_PENDING;
- hci_discovery_set_state(hdev, DISCOVERY_RESOLVING);
- } else {
- hci_discovery_set_state(hdev, DISCOVERY_STOPPED);
- }
-
-unlock:
- hci_dev_unlock(hdev);
-}
-
-static inline void hci_inquiry_result_evt(struct hci_dev *hdev, struct sk_buff *skb)
-{
- struct inquiry_data data;
- struct inquiry_info *info = (void *) (skb->data + 1);
- int num_rsp = *((__u8 *) skb->data);
-
- BT_DBG("%s num_rsp %d", hdev->name, num_rsp);
-
- if (!num_rsp)
- return;
-
- hci_dev_lock(hdev);
-
- for (; num_rsp; num_rsp--, info++) {
- bool name_known, ssp;
-
- bacpy(&data.bdaddr, &info->bdaddr);
- data.pscan_rep_mode = info->pscan_rep_mode;
- data.pscan_period_mode = info->pscan_period_mode;
- data.pscan_mode = info->pscan_mode;
- memcpy(data.dev_class, info->dev_class, 3);
- data.clock_offset = info->clock_offset;
- data.rssi = 0x00;
- data.ssp_mode = 0x00;
-
- name_known = hci_inquiry_cache_update(hdev, &data, false, &ssp);
- mgmt_device_found(hdev, &info->bdaddr, ACL_LINK, 0x00,
- info->dev_class, 0, !name_known, ssp, NULL,
- 0);
- }
-
- hci_dev_unlock(hdev);
-}
-
-static inline void hci_conn_complete_evt(struct hci_dev *hdev, struct sk_buff *skb)
-{
- struct hci_ev_conn_complete *ev = (void *) skb->data;
- struct hci_conn *conn;
-
- BT_DBG("%s", hdev->name);
-
- hci_dev_lock(hdev);
-
- conn = hci_conn_hash_lookup_ba(hdev, ev->link_type, &ev->bdaddr);
- if (!conn) {
- if (ev->link_type != SCO_LINK)
- goto unlock;
-
- conn = hci_conn_hash_lookup_ba(hdev, ESCO_LINK, &ev->bdaddr);
- if (!conn)
- goto unlock;
-
- conn->type = SCO_LINK;
- }
-
- if (!ev->status) {
- conn->handle = __le16_to_cpu(ev->handle);
-
- if (conn->type == ACL_LINK) {
- conn->state = BT_CONFIG;
- hci_conn_hold(conn);
- conn->disc_timeout = HCI_DISCONN_TIMEOUT;
- } else
- conn->state = BT_CONNECTED;
-
- hci_conn_hold_device(conn);
- hci_conn_add_sysfs(conn);
-
- if (test_bit(HCI_AUTH, &hdev->flags))
- conn->link_mode |= HCI_LM_AUTH;
-
- if (test_bit(HCI_ENCRYPT, &hdev->flags))
- conn->link_mode |= HCI_LM_ENCRYPT;
-
- /* Get remote features */
- if (conn->type == ACL_LINK) {
- struct hci_cp_read_remote_features cp;
- cp.handle = ev->handle;
- hci_send_cmd(hdev, HCI_OP_READ_REMOTE_FEATURES,
- sizeof(cp), &cp);
- }
-
- /* Set packet type for incoming connection */
- if (!conn->out && hdev->hci_ver < BLUETOOTH_VER_2_0) {
- struct hci_cp_change_conn_ptype cp;
- cp.handle = ev->handle;
- cp.pkt_type = cpu_to_le16(conn->pkt_type);
- hci_send_cmd(hdev, HCI_OP_CHANGE_CONN_PTYPE, sizeof(cp),
- &cp);
- }
- } else {
- conn->state = BT_CLOSED;
- if (conn->type == ACL_LINK)
- mgmt_connect_failed(hdev, &ev->bdaddr, conn->type,
- conn->dst_type, ev->status);
- }
-
- if (conn->type == ACL_LINK)
- hci_sco_setup(conn, ev->status);
-
- if (ev->status) {
- hci_proto_connect_cfm(conn, ev->status);
- hci_conn_del(conn);
- } else if (ev->link_type != ACL_LINK)
- hci_proto_connect_cfm(conn, ev->status);
-
-unlock:
- hci_dev_unlock(hdev);
-
- hci_conn_check_pending(hdev);
-}
-
-static inline void hci_conn_request_evt(struct hci_dev *hdev, struct sk_buff *skb)
-{
- struct hci_ev_conn_request *ev = (void *) skb->data;
- int mask = hdev->link_mode;
-
- BT_DBG("%s bdaddr %s type 0x%x", hdev->name,
- batostr(&ev->bdaddr), ev->link_type);
-
- mask |= hci_proto_connect_ind(hdev, &ev->bdaddr, ev->link_type);
-
- if ((mask & HCI_LM_ACCEPT) &&
- !hci_blacklist_lookup(hdev, &ev->bdaddr)) {
- /* Connection accepted */
- struct inquiry_entry *ie;
- struct hci_conn *conn;
-
- hci_dev_lock(hdev);
-
- ie = hci_inquiry_cache_lookup(hdev, &ev->bdaddr);
- if (ie)
- memcpy(ie->data.dev_class, ev->dev_class, 3);
-
- conn = hci_conn_hash_lookup_ba(hdev, ev->link_type, &ev->bdaddr);
- if (!conn) {
- conn = hci_conn_add(hdev, ev->link_type, &ev->bdaddr);
- if (!conn) {
- BT_ERR("No memory for new connection");
- hci_dev_unlock(hdev);
- return;
- }
- }
-
- memcpy(conn->dev_class, ev->dev_class, 3);
- conn->state = BT_CONNECT;
-
- hci_dev_unlock(hdev);
-
- if (ev->link_type == ACL_LINK || !lmp_esco_capable(hdev)) {
- struct hci_cp_accept_conn_req cp;
-
- bacpy(&cp.bdaddr, &ev->bdaddr);
-
- if (lmp_rswitch_capable(hdev) && (mask & HCI_LM_MASTER))
- cp.role = 0x00; /* Become master */
- else
- cp.role = 0x01; /* Remain slave */
-
- hci_send_cmd(hdev, HCI_OP_ACCEPT_CONN_REQ, sizeof(cp),
- &cp);
- } else {
- struct hci_cp_accept_sync_conn_req cp;
-
- bacpy(&cp.bdaddr, &ev->bdaddr);
- cp.pkt_type = cpu_to_le16(conn->pkt_type);
-
- cp.tx_bandwidth = cpu_to_le32(0x00001f40);
- cp.rx_bandwidth = cpu_to_le32(0x00001f40);
- cp.max_latency = cpu_to_le16(0xffff);
- cp.content_format = cpu_to_le16(hdev->voice_setting);
- cp.retrans_effort = 0xff;
-
- hci_send_cmd(hdev, HCI_OP_ACCEPT_SYNC_CONN_REQ,
- sizeof(cp), &cp);
- }
- } else {
- /* Connection rejected */
- struct hci_cp_reject_conn_req cp;
-
- bacpy(&cp.bdaddr, &ev->bdaddr);
- cp.reason = HCI_ERROR_REJ_BAD_ADDR;
- hci_send_cmd(hdev, HCI_OP_REJECT_CONN_REQ, sizeof(cp), &cp);
- }
-}
-
-static inline void hci_disconn_complete_evt(struct hci_dev *hdev, struct sk_buff *skb)
-{
- struct hci_ev_disconn_complete *ev = (void *) skb->data;
- struct hci_conn *conn;
-
- BT_DBG("%s status %d", hdev->name, ev->status);
-
- hci_dev_lock(hdev);
-
- conn = hci_conn_hash_lookup_handle(hdev, __le16_to_cpu(ev->handle));
- if (!conn)
- goto unlock;
-
- if (ev->status == 0)
- conn->state = BT_CLOSED;
-
- if (test_and_clear_bit(HCI_CONN_MGMT_CONNECTED, &conn->flags) &&
- (conn->type == ACL_LINK || conn->type == LE_LINK)) {
- if (ev->status != 0)
- mgmt_disconnect_failed(hdev, &conn->dst, conn->type,
- conn->dst_type, ev->status);
- else
- mgmt_device_disconnected(hdev, &conn->dst, conn->type,
- conn->dst_type);
- }
-
- if (ev->status == 0) {
- if (conn->type == ACL_LINK && conn->flush_key)
- hci_remove_link_key(hdev, &conn->dst);
- hci_proto_disconn_cfm(conn, ev->reason);
- hci_conn_del(conn);
- }
-
-unlock:
- hci_dev_unlock(hdev);
-}
-
-static inline void hci_auth_complete_evt(struct hci_dev *hdev, struct sk_buff *skb)
-{
- struct hci_ev_auth_complete *ev = (void *) skb->data;
- struct hci_conn *conn;
-
- BT_DBG("%s status %d", hdev->name, ev->status);
-
- hci_dev_lock(hdev);
-
- conn = hci_conn_hash_lookup_handle(hdev, __le16_to_cpu(ev->handle));
- if (!conn)
- goto unlock;
-
- if (!ev->status) {
- if (!hci_conn_ssp_enabled(conn) &&
- test_bit(HCI_CONN_REAUTH_PEND, &conn->flags)) {
- BT_INFO("re-auth of legacy device is not possible.");
- } else {
- conn->link_mode |= HCI_LM_AUTH;
- conn->sec_level = conn->pending_sec_level;
- }
- } else {
- mgmt_auth_failed(hdev, &conn->dst, conn->type, conn->dst_type,
- ev->status);
- }
-
- clear_bit(HCI_CONN_AUTH_PEND, &conn->flags);
- clear_bit(HCI_CONN_REAUTH_PEND, &conn->flags);
-
- if (conn->state == BT_CONFIG) {
- if (!ev->status && hci_conn_ssp_enabled(conn)) {
- struct hci_cp_set_conn_encrypt cp;
- cp.handle = ev->handle;
- cp.encrypt = 0x01;
- hci_send_cmd(hdev, HCI_OP_SET_CONN_ENCRYPT, sizeof(cp),
- &cp);
- } else {
- conn->state = BT_CONNECTED;
- hci_proto_connect_cfm(conn, ev->status);
- hci_conn_put(conn);
- }
- } else {
- hci_auth_cfm(conn, ev->status);
-
- hci_conn_hold(conn);
- conn->disc_timeout = HCI_DISCONN_TIMEOUT;
- hci_conn_put(conn);
- }
-
- if (test_bit(HCI_CONN_ENCRYPT_PEND, &conn->flags)) {
- if (!ev->status) {
- struct hci_cp_set_conn_encrypt cp;
- cp.handle = ev->handle;
- cp.encrypt = 0x01;
- hci_send_cmd(hdev, HCI_OP_SET_CONN_ENCRYPT, sizeof(cp),
- &cp);
- } else {
- clear_bit(HCI_CONN_ENCRYPT_PEND, &conn->flags);
- hci_encrypt_cfm(conn, ev->status, 0x00);
- }
- }
-
-unlock:
- hci_dev_unlock(hdev);
-}
-
-static inline void hci_remote_name_evt(struct hci_dev *hdev, struct sk_buff *skb)
-{
- struct hci_ev_remote_name *ev = (void *) skb->data;
- struct hci_conn *conn;
-
- BT_DBG("%s", hdev->name);
-
- hci_conn_check_pending(hdev);
-
- hci_dev_lock(hdev);
-
- conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &ev->bdaddr);
-
- if (!test_bit(HCI_MGMT, &hdev->dev_flags))
- goto check_auth;
-
- if (ev->status == 0)
- hci_check_pending_name(hdev, conn, &ev->bdaddr, ev->name,
- strnlen(ev->name, HCI_MAX_NAME_LENGTH));
- else
- hci_check_pending_name(hdev, conn, &ev->bdaddr, NULL, 0);
-
-check_auth:
- if (!conn)
- goto unlock;
-
- if (!hci_outgoing_auth_needed(hdev, conn))
- goto unlock;
-
- if (!test_and_set_bit(HCI_CONN_AUTH_PEND, &conn->flags)) {
- struct hci_cp_auth_requested cp;
- cp.handle = __cpu_to_le16(conn->handle);
- hci_send_cmd(hdev, HCI_OP_AUTH_REQUESTED, sizeof(cp), &cp);
- }
-
-unlock:
- hci_dev_unlock(hdev);
-}
-
-static inline void hci_encrypt_change_evt(struct hci_dev *hdev, struct sk_buff *skb)
-{
- struct hci_ev_encrypt_change *ev = (void *) skb->data;
- struct hci_conn *conn;
-
- BT_DBG("%s status %d", hdev->name, ev->status);
-
- hci_dev_lock(hdev);
-
- conn = hci_conn_hash_lookup_handle(hdev, __le16_to_cpu(ev->handle));
- if (conn) {
- if (!ev->status) {
- if (ev->encrypt) {
- /* Encryption implies authentication */
- conn->link_mode |= HCI_LM_AUTH;
- conn->link_mode |= HCI_LM_ENCRYPT;
- conn->sec_level = conn->pending_sec_level;
- } else
- conn->link_mode &= ~HCI_LM_ENCRYPT;
- }
-
- clear_bit(HCI_CONN_ENCRYPT_PEND, &conn->flags);
-
- if (ev->status && conn->state == BT_CONNECTED) {
- hci_acl_disconn(conn, 0x13);
- hci_conn_put(conn);
- goto unlock;
- }
-
- if (conn->state == BT_CONFIG) {
- if (!ev->status)
- conn->state = BT_CONNECTED;
-
- hci_proto_connect_cfm(conn, ev->status);
- hci_conn_put(conn);
- } else
- hci_encrypt_cfm(conn, ev->status, ev->encrypt);
- }
-
-unlock:
- hci_dev_unlock(hdev);
-}
-
-static inline void hci_change_link_key_complete_evt(struct hci_dev *hdev, struct sk_buff *skb)
-{
- struct hci_ev_change_link_key_complete *ev = (void *) skb->data;
- struct hci_conn *conn;
-
- BT_DBG("%s status %d", hdev->name, ev->status);
-
- hci_dev_lock(hdev);
-
- conn = hci_conn_hash_lookup_handle(hdev, __le16_to_cpu(ev->handle));
- if (conn) {
- if (!ev->status)
- conn->link_mode |= HCI_LM_SECURE;
-
- clear_bit(HCI_CONN_AUTH_PEND, &conn->flags);
-
- hci_key_change_cfm(conn, ev->status);
- }
-
- hci_dev_unlock(hdev);
-}
-
-static inline void hci_remote_features_evt(struct hci_dev *hdev, struct sk_buff *skb)
-{
- struct hci_ev_remote_features *ev = (void *) skb->data;
- struct hci_conn *conn;
-
- BT_DBG("%s status %d", hdev->name, ev->status);
-
- hci_dev_lock(hdev);
-
- conn = hci_conn_hash_lookup_handle(hdev, __le16_to_cpu(ev->handle));
- if (!conn)
- goto unlock;
-
- if (!ev->status)
- memcpy(conn->features, ev->features, 8);
-
- if (conn->state != BT_CONFIG)
- goto unlock;
-
- if (!ev->status && lmp_ssp_capable(hdev) && lmp_ssp_capable(conn)) {
- struct hci_cp_read_remote_ext_features cp;
- cp.handle = ev->handle;
- cp.page = 0x01;
- hci_send_cmd(hdev, HCI_OP_READ_REMOTE_EXT_FEATURES,
- sizeof(cp), &cp);
- goto unlock;
- }
-
- if (!ev->status && !test_bit(HCI_CONN_MGMT_CONNECTED, &conn->flags)) {
- struct hci_cp_remote_name_req cp;
- memset(&cp, 0, sizeof(cp));
- bacpy(&cp.bdaddr, &conn->dst);
- cp.pscan_rep_mode = 0x02;
- hci_send_cmd(hdev, HCI_OP_REMOTE_NAME_REQ, sizeof(cp), &cp);
- } else if (!test_and_set_bit(HCI_CONN_MGMT_CONNECTED, &conn->flags))
- mgmt_device_connected(hdev, &conn->dst, conn->type,
- conn->dst_type, 0, NULL, 0,
- conn->dev_class);
-
- if (!hci_outgoing_auth_needed(hdev, conn)) {
- conn->state = BT_CONNECTED;
- hci_proto_connect_cfm(conn, ev->status);
- hci_conn_put(conn);
- }
-
-unlock:
- hci_dev_unlock(hdev);
-}
-
-static inline void hci_remote_version_evt(struct hci_dev *hdev, struct sk_buff *skb)
-{
- BT_DBG("%s", hdev->name);
-}
-
-static inline void hci_qos_setup_complete_evt(struct hci_dev *hdev, struct sk_buff *skb)
-{
- BT_DBG("%s", hdev->name);
-}
-
-static inline void hci_cmd_complete_evt(struct hci_dev *hdev, struct sk_buff *skb)
-{
- struct hci_ev_cmd_complete *ev = (void *) skb->data;
- __u16 opcode;
-
- skb_pull(skb, sizeof(*ev));
-
- opcode = __le16_to_cpu(ev->opcode);
-
- switch (opcode) {
- case HCI_OP_INQUIRY_CANCEL:
- hci_cc_inquiry_cancel(hdev, skb);
- break;
-
- case HCI_OP_EXIT_PERIODIC_INQ:
- hci_cc_exit_periodic_inq(hdev, skb);
- break;
-
- case HCI_OP_REMOTE_NAME_REQ_CANCEL:
- hci_cc_remote_name_req_cancel(hdev, skb);
- break;
-
- case HCI_OP_ROLE_DISCOVERY:
- hci_cc_role_discovery(hdev, skb);
- break;
-
- case HCI_OP_READ_LINK_POLICY:
- hci_cc_read_link_policy(hdev, skb);
- break;
-
- case HCI_OP_WRITE_LINK_POLICY:
- hci_cc_write_link_policy(hdev, skb);
- break;
-
- case HCI_OP_READ_DEF_LINK_POLICY:
- hci_cc_read_def_link_policy(hdev, skb);
- break;
-
- case HCI_OP_WRITE_DEF_LINK_POLICY:
- hci_cc_write_def_link_policy(hdev, skb);
- break;
-
- case HCI_OP_RESET:
- hci_cc_reset(hdev, skb);
- break;
-
- case HCI_OP_WRITE_LOCAL_NAME:
- hci_cc_write_local_name(hdev, skb);
- break;
-
- case HCI_OP_READ_LOCAL_NAME:
- hci_cc_read_local_name(hdev, skb);
- break;
-
- case HCI_OP_WRITE_AUTH_ENABLE:
- hci_cc_write_auth_enable(hdev, skb);
- break;
-
- case HCI_OP_WRITE_ENCRYPT_MODE:
- hci_cc_write_encrypt_mode(hdev, skb);
- break;
-
- case HCI_OP_WRITE_SCAN_ENABLE:
- hci_cc_write_scan_enable(hdev, skb);
- break;
-
- case HCI_OP_READ_CLASS_OF_DEV:
- hci_cc_read_class_of_dev(hdev, skb);
- break;
-
- case HCI_OP_WRITE_CLASS_OF_DEV:
- hci_cc_write_class_of_dev(hdev, skb);
- break;
-
- case HCI_OP_READ_VOICE_SETTING:
- hci_cc_read_voice_setting(hdev, skb);
- break;
-
- case HCI_OP_WRITE_VOICE_SETTING:
- hci_cc_write_voice_setting(hdev, skb);
- break;
-
- case HCI_OP_HOST_BUFFER_SIZE:
- hci_cc_host_buffer_size(hdev, skb);
- break;
-
- case HCI_OP_WRITE_SSP_MODE:
- hci_cc_write_ssp_mode(hdev, skb);
- break;
-
- case HCI_OP_READ_LOCAL_VERSION:
- hci_cc_read_local_version(hdev, skb);
- break;
-
- case HCI_OP_READ_LOCAL_COMMANDS:
- hci_cc_read_local_commands(hdev, skb);
- break;
-
- case HCI_OP_READ_LOCAL_FEATURES:
- hci_cc_read_local_features(hdev, skb);
- break;
-
- case HCI_OP_READ_LOCAL_EXT_FEATURES:
- hci_cc_read_local_ext_features(hdev, skb);
- break;
-
- case HCI_OP_READ_BUFFER_SIZE:
- hci_cc_read_buffer_size(hdev, skb);
- break;
-
- case HCI_OP_READ_BD_ADDR:
- hci_cc_read_bd_addr(hdev, skb);
- break;
-
- case HCI_OP_READ_DATA_BLOCK_SIZE:
- hci_cc_read_data_block_size(hdev, skb);
- break;
-
- case HCI_OP_WRITE_CA_TIMEOUT:
- hci_cc_write_ca_timeout(hdev, skb);
- break;
-
- case HCI_OP_READ_FLOW_CONTROL_MODE:
- hci_cc_read_flow_control_mode(hdev, skb);
- break;
-
- case HCI_OP_READ_LOCAL_AMP_INFO:
- hci_cc_read_local_amp_info(hdev, skb);
- break;
-
- case HCI_OP_DELETE_STORED_LINK_KEY:
- hci_cc_delete_stored_link_key(hdev, skb);
- break;
-
- case HCI_OP_SET_EVENT_MASK:
- hci_cc_set_event_mask(hdev, skb);
- break;
-
- case HCI_OP_WRITE_INQUIRY_MODE:
- hci_cc_write_inquiry_mode(hdev, skb);
- break;
-
- case HCI_OP_READ_INQ_RSP_TX_POWER:
- hci_cc_read_inq_rsp_tx_power(hdev, skb);
- break;
-
- case HCI_OP_SET_EVENT_FLT:
- hci_cc_set_event_flt(hdev, skb);
- break;
-
- case HCI_OP_PIN_CODE_REPLY:
- hci_cc_pin_code_reply(hdev, skb);
- break;
-
- case HCI_OP_PIN_CODE_NEG_REPLY:
- hci_cc_pin_code_neg_reply(hdev, skb);
- break;
-
- case HCI_OP_READ_LOCAL_OOB_DATA:
- hci_cc_read_local_oob_data_reply(hdev, skb);
- break;
-
- case HCI_OP_LE_READ_BUFFER_SIZE:
- hci_cc_le_read_buffer_size(hdev, skb);
- break;
-
- case HCI_OP_USER_CONFIRM_REPLY:
- hci_cc_user_confirm_reply(hdev, skb);
- break;
-
- case HCI_OP_USER_CONFIRM_NEG_REPLY:
- hci_cc_user_confirm_neg_reply(hdev, skb);
- break;
-
- case HCI_OP_USER_PASSKEY_REPLY:
- hci_cc_user_passkey_reply(hdev, skb);
- break;
-
- case HCI_OP_USER_PASSKEY_NEG_REPLY:
- hci_cc_user_passkey_neg_reply(hdev, skb);
- break;
-
- case HCI_OP_LE_SET_SCAN_PARAM:
- hci_cc_le_set_scan_param(hdev, skb);
- break;
-
- case HCI_OP_LE_SET_SCAN_ENABLE:
- hci_cc_le_set_scan_enable(hdev, skb);
- break;
-
- case HCI_OP_LE_LTK_REPLY:
- hci_cc_le_ltk_reply(hdev, skb);
- break;
-
- case HCI_OP_LE_LTK_NEG_REPLY:
- hci_cc_le_ltk_neg_reply(hdev, skb);
- break;
-
- case HCI_OP_WRITE_LE_HOST_SUPPORTED:
- hci_cc_write_le_host_supported(hdev, skb);
- break;
-
- default:
- BT_DBG("%s opcode 0x%x", hdev->name, opcode);
- break;
- }
-
- if (ev->opcode != HCI_OP_NOP)
- del_timer(&hdev->cmd_timer);
-
- if (ev->ncmd) {
- atomic_set(&hdev->cmd_cnt, 1);
- if (!skb_queue_empty(&hdev->cmd_q))
- queue_work(hdev->workqueue, &hdev->cmd_work);
- }
-}
-
-static inline void hci_cmd_status_evt(struct hci_dev *hdev, struct sk_buff *skb)
-{
- struct hci_ev_cmd_status *ev = (void *) skb->data;
- __u16 opcode;
-
- skb_pull(skb, sizeof(*ev));
-
- opcode = __le16_to_cpu(ev->opcode);
-
- switch (opcode) {
- case HCI_OP_INQUIRY:
- hci_cs_inquiry(hdev, ev->status);
- break;
-
- case HCI_OP_CREATE_CONN:
- hci_cs_create_conn(hdev, ev->status);
- break;
-
- case HCI_OP_ADD_SCO:
- hci_cs_add_sco(hdev, ev->status);
- break;
-
- case HCI_OP_AUTH_REQUESTED:
- hci_cs_auth_requested(hdev, ev->status);
- break;
-
- case HCI_OP_SET_CONN_ENCRYPT:
- hci_cs_set_conn_encrypt(hdev, ev->status);
- break;
-
- case HCI_OP_REMOTE_NAME_REQ:
- hci_cs_remote_name_req(hdev, ev->status);
- break;
-
- case HCI_OP_READ_REMOTE_FEATURES:
- hci_cs_read_remote_features(hdev, ev->status);
- break;
-
- case HCI_OP_READ_REMOTE_EXT_FEATURES:
- hci_cs_read_remote_ext_features(hdev, ev->status);
- break;
-
- case HCI_OP_SETUP_SYNC_CONN:
- hci_cs_setup_sync_conn(hdev, ev->status);
- break;
-
- case HCI_OP_SNIFF_MODE:
- hci_cs_sniff_mode(hdev, ev->status);
- break;
-
- case HCI_OP_EXIT_SNIFF_MODE:
- hci_cs_exit_sniff_mode(hdev, ev->status);
- break;
-
- case HCI_OP_DISCONNECT:
- hci_cs_disconnect(hdev, ev->status);
- break;
-
- case HCI_OP_LE_CREATE_CONN:
- hci_cs_le_create_conn(hdev, ev->status);
- break;
-
- case HCI_OP_LE_START_ENC:
- hci_cs_le_start_enc(hdev, ev->status);
- break;
-
- default:
- BT_DBG("%s opcode 0x%x", hdev->name, opcode);
- break;
- }
-
- if (ev->opcode != HCI_OP_NOP)
- del_timer(&hdev->cmd_timer);
-
- if (ev->ncmd && !test_bit(HCI_RESET, &hdev->flags)) {
- atomic_set(&hdev->cmd_cnt, 1);
- if (!skb_queue_empty(&hdev->cmd_q))
- queue_work(hdev->workqueue, &hdev->cmd_work);
- }
-}
-
-static inline void hci_role_change_evt(struct hci_dev *hdev, struct sk_buff *skb)
-{
- struct hci_ev_role_change *ev = (void *) skb->data;
- struct hci_conn *conn;
-
- BT_DBG("%s status %d", hdev->name, ev->status);
-
- hci_dev_lock(hdev);
-
- conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &ev->bdaddr);
- if (conn) {
- if (!ev->status) {
- if (ev->role)
- conn->link_mode &= ~HCI_LM_MASTER;
- else
- conn->link_mode |= HCI_LM_MASTER;
- }
-
- clear_bit(HCI_CONN_RSWITCH_PEND, &conn->flags);
-
- hci_role_switch_cfm(conn, ev->status, ev->role);
- }
-
- hci_dev_unlock(hdev);
-}
-
-static inline void hci_num_comp_pkts_evt(struct hci_dev *hdev, struct sk_buff *skb)
-{
- struct hci_ev_num_comp_pkts *ev = (void *) skb->data;
- int i;
-
- if (hdev->flow_ctl_mode != HCI_FLOW_CTL_MODE_PACKET_BASED) {
- BT_ERR("Wrong event for mode %d", hdev->flow_ctl_mode);
- return;
- }
-
- if (skb->len < sizeof(*ev) || skb->len < sizeof(*ev) +
- ev->num_hndl * sizeof(struct hci_comp_pkts_info)) {
- BT_DBG("%s bad parameters", hdev->name);
- return;
- }
-
- BT_DBG("%s num_hndl %d", hdev->name, ev->num_hndl);
-
- for (i = 0; i < ev->num_hndl; i++) {
- struct hci_comp_pkts_info *info = &ev->handles[i];
- struct hci_conn *conn;
- __u16 handle, count;
-
- handle = __le16_to_cpu(info->handle);
- count = __le16_to_cpu(info->count);
-
- conn = hci_conn_hash_lookup_handle(hdev, handle);
- if (!conn)
- continue;
-
- conn->sent -= count;
-
- switch (conn->type) {
- case ACL_LINK:
- hdev->acl_cnt += count;
- if (hdev->acl_cnt > hdev->acl_pkts)
- hdev->acl_cnt = hdev->acl_pkts;
- break;
-
- case LE_LINK:
- if (hdev->le_pkts) {
- hdev->le_cnt += count;
- if (hdev->le_cnt > hdev->le_pkts)
- hdev->le_cnt = hdev->le_pkts;
- } else {
- hdev->acl_cnt += count;
- if (hdev->acl_cnt > hdev->acl_pkts)
- hdev->acl_cnt = hdev->acl_pkts;
- }
- break;
-
- case SCO_LINK:
- hdev->sco_cnt += count;
- if (hdev->sco_cnt > hdev->sco_pkts)
- hdev->sco_cnt = hdev->sco_pkts;
- break;
-
- default:
- BT_ERR("Unknown type %d conn %p", conn->type, conn);
- break;
- }
- }
-
- queue_work(hdev->workqueue, &hdev->tx_work);
-}
-
-static inline void hci_num_comp_blocks_evt(struct hci_dev *hdev,
- struct sk_buff *skb)
-{
- struct hci_ev_num_comp_blocks *ev = (void *) skb->data;
- int i;
-
- if (hdev->flow_ctl_mode != HCI_FLOW_CTL_MODE_BLOCK_BASED) {
- BT_ERR("Wrong event for mode %d", hdev->flow_ctl_mode);
- return;
- }
-
- if (skb->len < sizeof(*ev) || skb->len < sizeof(*ev) +
- ev->num_hndl * sizeof(struct hci_comp_blocks_info)) {
- BT_DBG("%s bad parameters", hdev->name);
- return;
- }
-
- BT_DBG("%s num_blocks %d num_hndl %d", hdev->name, ev->num_blocks,
- ev->num_hndl);
-
- for (i = 0; i < ev->num_hndl; i++) {
- struct hci_comp_blocks_info *info = &ev->handles[i];
- struct hci_conn *conn;
- __u16 handle, block_count;
-
- handle = __le16_to_cpu(info->handle);
- block_count = __le16_to_cpu(info->blocks);
-
- conn = hci_conn_hash_lookup_handle(hdev, handle);
- if (!conn)
- continue;
-
- conn->sent -= block_count;
-
- switch (conn->type) {
- case ACL_LINK:
- hdev->block_cnt += block_count;
- if (hdev->block_cnt > hdev->num_blocks)
- hdev->block_cnt = hdev->num_blocks;
- break;
-
- default:
- BT_ERR("Unknown type %d conn %p", conn->type, conn);
- break;
- }
- }
-
- queue_work(hdev->workqueue, &hdev->tx_work);
-}
-
-static inline void hci_mode_change_evt(struct hci_dev *hdev, struct sk_buff *skb)
-{
- struct hci_ev_mode_change *ev = (void *) skb->data;
- struct hci_conn *conn;
-
- BT_DBG("%s status %d", hdev->name, ev->status);
-
- hci_dev_lock(hdev);
-
- conn = hci_conn_hash_lookup_handle(hdev, __le16_to_cpu(ev->handle));
- if (conn) {
- conn->mode = ev->mode;
- conn->interval = __le16_to_cpu(ev->interval);
-
- if (!test_and_clear_bit(HCI_CONN_MODE_CHANGE_PEND, &conn->flags)) {
- if (conn->mode == HCI_CM_ACTIVE)
- set_bit(HCI_CONN_POWER_SAVE, &conn->flags);
- else
- clear_bit(HCI_CONN_POWER_SAVE, &conn->flags);
- }
-
- if (test_and_clear_bit(HCI_CONN_SCO_SETUP_PEND, &conn->flags))
- hci_sco_setup(conn, ev->status);
- }
-
- hci_dev_unlock(hdev);
-}
-
-static inline void hci_pin_code_request_evt(struct hci_dev *hdev, struct sk_buff *skb)
-{
- struct hci_ev_pin_code_req *ev = (void *) skb->data;
- struct hci_conn *conn;
-
- BT_DBG("%s", hdev->name);
-
- hci_dev_lock(hdev);
-
- conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &ev->bdaddr);
- if (!conn)
- goto unlock;
-
- if (conn->state == BT_CONNECTED) {
- hci_conn_hold(conn);
- conn->disc_timeout = HCI_PAIRING_TIMEOUT;
- hci_conn_put(conn);
- }
-
- if (!test_bit(HCI_PAIRABLE, &hdev->dev_flags))
- hci_send_cmd(hdev, HCI_OP_PIN_CODE_NEG_REPLY,
- sizeof(ev->bdaddr), &ev->bdaddr);
- else if (test_bit(HCI_MGMT, &hdev->dev_flags)) {
- u8 secure;
-
- if (conn->pending_sec_level == BT_SECURITY_HIGH)
- secure = 1;
- else
- secure = 0;
-
- mgmt_pin_code_request(hdev, &ev->bdaddr, secure);
- }
-
-unlock:
- hci_dev_unlock(hdev);
-}
-
-static inline void hci_link_key_request_evt(struct hci_dev *hdev, struct sk_buff *skb)
-{
- struct hci_ev_link_key_req *ev = (void *) skb->data;
- struct hci_cp_link_key_reply cp;
- struct hci_conn *conn;
- struct link_key *key;
-
- BT_DBG("%s", hdev->name);
-
- if (!test_bit(HCI_LINK_KEYS, &hdev->dev_flags))
- return;
-
- hci_dev_lock(hdev);
-
- key = hci_find_link_key(hdev, &ev->bdaddr);
- if (!key) {
- BT_DBG("%s link key not found for %s", hdev->name,
- batostr(&ev->bdaddr));
- goto not_found;
- }
-
- BT_DBG("%s found key type %u for %s", hdev->name, key->type,
- batostr(&ev->bdaddr));
-
- if (!test_bit(HCI_DEBUG_KEYS, &hdev->dev_flags) &&
- key->type == HCI_LK_DEBUG_COMBINATION) {
- BT_DBG("%s ignoring debug key", hdev->name);
- goto not_found;
- }
-
- conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &ev->bdaddr);
- if (conn) {
- if (key->type == HCI_LK_UNAUTH_COMBINATION &&
- conn->auth_type != 0xff &&
- (conn->auth_type & 0x01)) {
- BT_DBG("%s ignoring unauthenticated key", hdev->name);
- goto not_found;
- }
-
- if (key->type == HCI_LK_COMBINATION && key->pin_len < 16 &&
- conn->pending_sec_level == BT_SECURITY_HIGH) {
- BT_DBG("%s ignoring key unauthenticated for high \
- security", hdev->name);
- goto not_found;
- }
-
- conn->key_type = key->type;
- conn->pin_length = key->pin_len;
- }
-
- bacpy(&cp.bdaddr, &ev->bdaddr);
- memcpy(cp.link_key, key->val, 16);
-
- hci_send_cmd(hdev, HCI_OP_LINK_KEY_REPLY, sizeof(cp), &cp);
-
- hci_dev_unlock(hdev);
-
- return;
-
-not_found:
- hci_send_cmd(hdev, HCI_OP_LINK_KEY_NEG_REPLY, 6, &ev->bdaddr);
- hci_dev_unlock(hdev);
-}
-
-static inline void hci_link_key_notify_evt(struct hci_dev *hdev, struct sk_buff *skb)
-{
- struct hci_ev_link_key_notify *ev = (void *) skb->data;
- struct hci_conn *conn;
- u8 pin_len = 0;
-
- BT_DBG("%s", hdev->name);
-
- hci_dev_lock(hdev);
-
- conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &ev->bdaddr);
- if (conn) {
- hci_conn_hold(conn);
- conn->disc_timeout = HCI_DISCONN_TIMEOUT;
- pin_len = conn->pin_length;
-
- if (ev->key_type != HCI_LK_CHANGED_COMBINATION)
- conn->key_type = ev->key_type;
-
- hci_conn_put(conn);
- }
-
- if (test_bit(HCI_LINK_KEYS, &hdev->dev_flags))
- hci_add_link_key(hdev, conn, 1, &ev->bdaddr, ev->link_key,
- ev->key_type, pin_len);
-
- hci_dev_unlock(hdev);
-}
-
-static inline void hci_clock_offset_evt(struct hci_dev *hdev, struct sk_buff *skb)
-{
- struct hci_ev_clock_offset *ev = (void *) skb->data;
- struct hci_conn *conn;
-
- BT_DBG("%s status %d", hdev->name, ev->status);
-
- hci_dev_lock(hdev);
-
- conn = hci_conn_hash_lookup_handle(hdev, __le16_to_cpu(ev->handle));
- if (conn && !ev->status) {
- struct inquiry_entry *ie;
-
- ie = hci_inquiry_cache_lookup(hdev, &conn->dst);
- if (ie) {
- ie->data.clock_offset = ev->clock_offset;
- ie->timestamp = jiffies;
- }
- }
-
- hci_dev_unlock(hdev);
-}
-
-static inline void hci_pkt_type_change_evt(struct hci_dev *hdev, struct sk_buff *skb)
-{
- struct hci_ev_pkt_type_change *ev = (void *) skb->data;
- struct hci_conn *conn;
-
- BT_DBG("%s status %d", hdev->name, ev->status);
-
- hci_dev_lock(hdev);
-
- conn = hci_conn_hash_lookup_handle(hdev, __le16_to_cpu(ev->handle));
- if (conn && !ev->status)
- conn->pkt_type = __le16_to_cpu(ev->pkt_type);
-
- hci_dev_unlock(hdev);
-}
-
-static inline void hci_pscan_rep_mode_evt(struct hci_dev *hdev, struct sk_buff *skb)
-{
- struct hci_ev_pscan_rep_mode *ev = (void *) skb->data;
- struct inquiry_entry *ie;
-
- BT_DBG("%s", hdev->name);
-
- hci_dev_lock(hdev);
-
- ie = hci_inquiry_cache_lookup(hdev, &ev->bdaddr);
- if (ie) {
- ie->data.pscan_rep_mode = ev->pscan_rep_mode;
- ie->timestamp = jiffies;
- }
-
- hci_dev_unlock(hdev);
-}
-
-static inline void hci_inquiry_result_with_rssi_evt(struct hci_dev *hdev, struct sk_buff *skb)
-{
- struct inquiry_data data;
- int num_rsp = *((__u8 *) skb->data);
- bool name_known, ssp;
-
- BT_DBG("%s num_rsp %d", hdev->name, num_rsp);
-
- if (!num_rsp)
- return;
-
- hci_dev_lock(hdev);
-
- if ((skb->len - 1) / num_rsp != sizeof(struct inquiry_info_with_rssi)) {
- struct inquiry_info_with_rssi_and_pscan_mode *info;
- info = (void *) (skb->data + 1);
-
- for (; num_rsp; num_rsp--, info++) {
- bacpy(&data.bdaddr, &info->bdaddr);
- data.pscan_rep_mode = info->pscan_rep_mode;
- data.pscan_period_mode = info->pscan_period_mode;
- data.pscan_mode = info->pscan_mode;
- memcpy(data.dev_class, info->dev_class, 3);
- data.clock_offset = info->clock_offset;
- data.rssi = info->rssi;
- data.ssp_mode = 0x00;
-
- name_known = hci_inquiry_cache_update(hdev, &data,
- false, &ssp);
- mgmt_device_found(hdev, &info->bdaddr, ACL_LINK, 0x00,
- info->dev_class, info->rssi,
- !name_known, ssp, NULL, 0);
- }
- } else {
- struct inquiry_info_with_rssi *info = (void *) (skb->data + 1);
-
- for (; num_rsp; num_rsp--, info++) {
- bacpy(&data.bdaddr, &info->bdaddr);
- data.pscan_rep_mode = info->pscan_rep_mode;
- data.pscan_period_mode = info->pscan_period_mode;
- data.pscan_mode = 0x00;
- memcpy(data.dev_class, info->dev_class, 3);
- data.clock_offset = info->clock_offset;
- data.rssi = info->rssi;
- data.ssp_mode = 0x00;
- name_known = hci_inquiry_cache_update(hdev, &data,
- false, &ssp);
- mgmt_device_found(hdev, &info->bdaddr, ACL_LINK, 0x00,
- info->dev_class, info->rssi,
- !name_known, ssp, NULL, 0);
- }
- }
-
- hci_dev_unlock(hdev);
-}
-
-static inline void hci_remote_ext_features_evt(struct hci_dev *hdev, struct sk_buff *skb)
-{
- struct hci_ev_remote_ext_features *ev = (void *) skb->data;
- struct hci_conn *conn;
-
- BT_DBG("%s", hdev->name);
-
- hci_dev_lock(hdev);
-
- conn = hci_conn_hash_lookup_handle(hdev, __le16_to_cpu(ev->handle));
- if (!conn)
- goto unlock;
-
- if (!ev->status && ev->page == 0x01) {
- struct inquiry_entry *ie;
-
- ie = hci_inquiry_cache_lookup(hdev, &conn->dst);
- if (ie)
- ie->data.ssp_mode = (ev->features[0] & LMP_HOST_SSP);
-
- if (ev->features[0] & LMP_HOST_SSP)
- set_bit(HCI_CONN_SSP_ENABLED, &conn->flags);
- }
-
- if (conn->state != BT_CONFIG)
- goto unlock;
-
- if (!ev->status && !test_bit(HCI_CONN_MGMT_CONNECTED, &conn->flags)) {
- struct hci_cp_remote_name_req cp;
- memset(&cp, 0, sizeof(cp));
- bacpy(&cp.bdaddr, &conn->dst);
- cp.pscan_rep_mode = 0x02;
- hci_send_cmd(hdev, HCI_OP_REMOTE_NAME_REQ, sizeof(cp), &cp);
- } else if (!test_and_set_bit(HCI_CONN_MGMT_CONNECTED, &conn->flags))
- mgmt_device_connected(hdev, &conn->dst, conn->type,
- conn->dst_type, 0, NULL, 0,
- conn->dev_class);
-
- if (!hci_outgoing_auth_needed(hdev, conn)) {
- conn->state = BT_CONNECTED;
- hci_proto_connect_cfm(conn, ev->status);
- hci_conn_put(conn);
- }
-
-unlock:
- hci_dev_unlock(hdev);
-}
-
-static inline void hci_sync_conn_complete_evt(struct hci_dev *hdev, struct sk_buff *skb)
-{
- struct hci_ev_sync_conn_complete *ev = (void *) skb->data;
- struct hci_conn *conn;
-
- BT_DBG("%s status %d", hdev->name, ev->status);
-
- hci_dev_lock(hdev);
-
- conn = hci_conn_hash_lookup_ba(hdev, ev->link_type, &ev->bdaddr);
- if (!conn) {
- if (ev->link_type == ESCO_LINK)
- goto unlock;
-
- conn = hci_conn_hash_lookup_ba(hdev, ESCO_LINK, &ev->bdaddr);
- if (!conn)
- goto unlock;
-
- conn->type = SCO_LINK;
- }
-
- switch (ev->status) {
- case 0x00:
- conn->handle = __le16_to_cpu(ev->handle);
- conn->state = BT_CONNECTED;
-
- hci_conn_hold_device(conn);
- hci_conn_add_sysfs(conn);
- break;
-
- case 0x11: /* Unsupported Feature or Parameter Value */
- case 0x1c: /* SCO interval rejected */
- case 0x1a: /* Unsupported Remote Feature */
- case 0x1f: /* Unspecified error */
- if (conn->out && conn->attempt < 2) {
- conn->pkt_type = (hdev->esco_type & SCO_ESCO_MASK) |
- (hdev->esco_type & EDR_ESCO_MASK);
- hci_setup_sync(conn, conn->link->handle);
- goto unlock;
- }
- /* fall through */
-
- default:
- conn->state = BT_CLOSED;
- break;
- }
-
- hci_proto_connect_cfm(conn, ev->status);
- if (ev->status)
- hci_conn_del(conn);
-
-unlock:
- hci_dev_unlock(hdev);
-}
-
-static inline void hci_sync_conn_changed_evt(struct hci_dev *hdev, struct sk_buff *skb)
-{
- BT_DBG("%s", hdev->name);
-}
-
-static inline void hci_sniff_subrate_evt(struct hci_dev *hdev, struct sk_buff *skb)
-{
- struct hci_ev_sniff_subrate *ev = (void *) skb->data;
-
- BT_DBG("%s status %d", hdev->name, ev->status);
-}
-
-static inline void hci_extended_inquiry_result_evt(struct hci_dev *hdev, struct sk_buff *skb)
-{
- struct inquiry_data data;
- struct extended_inquiry_info *info = (void *) (skb->data + 1);
- int num_rsp = *((__u8 *) skb->data);
- size_t eir_len;
-
- BT_DBG("%s num_rsp %d", hdev->name, num_rsp);
-
- if (!num_rsp)
- return;
-
- hci_dev_lock(hdev);
-
- for (; num_rsp; num_rsp--, info++) {
- bool name_known, ssp;
-
- bacpy(&data.bdaddr, &info->bdaddr);
- data.pscan_rep_mode = info->pscan_rep_mode;
- data.pscan_period_mode = info->pscan_period_mode;
- data.pscan_mode = 0x00;
- memcpy(data.dev_class, info->dev_class, 3);
- data.clock_offset = info->clock_offset;
- data.rssi = info->rssi;
- data.ssp_mode = 0x01;
-
- if (test_bit(HCI_MGMT, &hdev->dev_flags))
- name_known = eir_has_data_type(info->data,
- sizeof(info->data),
- EIR_NAME_COMPLETE);
- else
- name_known = true;
-
- name_known = hci_inquiry_cache_update(hdev, &data, name_known,
- &ssp);
- eir_len = eir_get_length(info->data, sizeof(info->data));
- mgmt_device_found(hdev, &info->bdaddr, ACL_LINK, 0x00,
- info->dev_class, info->rssi, !name_known,
- ssp, info->data, eir_len);
- }
-
- hci_dev_unlock(hdev);
-}
-
-static inline u8 hci_get_auth_req(struct hci_conn *conn)
-{
- /* If remote requests dedicated bonding follow that lead */
- if (conn->remote_auth == 0x02 || conn->remote_auth == 0x03) {
- /* If both remote and local IO capabilities allow MITM
- * protection then require it, otherwise don't */
- if (conn->remote_cap == 0x03 || conn->io_capability == 0x03)
- return 0x02;
- else
- return 0x03;
- }
-
- /* If remote requests no-bonding follow that lead */
- if (conn->remote_auth == 0x00 || conn->remote_auth == 0x01)
- return conn->remote_auth | (conn->auth_type & 0x01);
-
- return conn->auth_type;
-}
-
-static inline void hci_io_capa_request_evt(struct hci_dev *hdev, struct sk_buff *skb)
-{
- struct hci_ev_io_capa_request *ev = (void *) skb->data;
- struct hci_conn *conn;
-
- BT_DBG("%s", hdev->name);
-
- hci_dev_lock(hdev);
-
- conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &ev->bdaddr);
- if (!conn)
- goto unlock;
-
- hci_conn_hold(conn);
-
- if (!test_bit(HCI_MGMT, &hdev->dev_flags))
- goto unlock;
-
- if (test_bit(HCI_PAIRABLE, &hdev->dev_flags) ||
- (conn->remote_auth & ~0x01) == HCI_AT_NO_BONDING) {
- struct hci_cp_io_capability_reply cp;
-
- bacpy(&cp.bdaddr, &ev->bdaddr);
- /* Change the IO capability from KeyboardDisplay
- * to DisplayYesNo as it is not supported by BT spec. */
- cp.capability = (conn->io_capability == 0x04) ?
- 0x01 : conn->io_capability;
- conn->auth_type = hci_get_auth_req(conn);
- cp.authentication = conn->auth_type;
-
- if ((conn->out || test_bit(HCI_CONN_REMOTE_OOB, &conn->flags)) &&
- hci_find_remote_oob_data(hdev, &conn->dst))
- cp.oob_data = 0x01;
- else
- cp.oob_data = 0x00;
-
- hci_send_cmd(hdev, HCI_OP_IO_CAPABILITY_REPLY,
- sizeof(cp), &cp);
- } else {
- struct hci_cp_io_capability_neg_reply cp;
-
- bacpy(&cp.bdaddr, &ev->bdaddr);
- cp.reason = HCI_ERROR_PAIRING_NOT_ALLOWED;
-
- hci_send_cmd(hdev, HCI_OP_IO_CAPABILITY_NEG_REPLY,
- sizeof(cp), &cp);
- }
-
-unlock:
- hci_dev_unlock(hdev);
-}
-
-static inline void hci_io_capa_reply_evt(struct hci_dev *hdev, struct sk_buff *skb)
-{
- struct hci_ev_io_capa_reply *ev = (void *) skb->data;
- struct hci_conn *conn;
-
- BT_DBG("%s", hdev->name);
-
- hci_dev_lock(hdev);
-
- conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &ev->bdaddr);
- if (!conn)
- goto unlock;
-
- conn->remote_cap = ev->capability;
- conn->remote_auth = ev->authentication;
- if (ev->oob_data)
- set_bit(HCI_CONN_REMOTE_OOB, &conn->flags);
-
-unlock:
- hci_dev_unlock(hdev);
-}
-
-static inline void hci_user_confirm_request_evt(struct hci_dev *hdev,
- struct sk_buff *skb)
-{
- struct hci_ev_user_confirm_req *ev = (void *) skb->data;
- int loc_mitm, rem_mitm, confirm_hint = 0;
- struct hci_conn *conn;
-
- BT_DBG("%s", hdev->name);
-
- hci_dev_lock(hdev);
-
- if (!test_bit(HCI_MGMT, &hdev->dev_flags))
- goto unlock;
-
- conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &ev->bdaddr);
- if (!conn)
- goto unlock;
-
- loc_mitm = (conn->auth_type & 0x01);
- rem_mitm = (conn->remote_auth & 0x01);
-
- /* If we require MITM but the remote device can't provide that
- * (it has NoInputNoOutput) then reject the confirmation
- * request. The only exception is when we're dedicated bonding
- * initiators (connect_cfm_cb set) since then we always have the MITM
- * bit set. */
- if (!conn->connect_cfm_cb && loc_mitm && conn->remote_cap == 0x03) {
- BT_DBG("Rejecting request: remote device can't provide MITM");
- hci_send_cmd(hdev, HCI_OP_USER_CONFIRM_NEG_REPLY,
- sizeof(ev->bdaddr), &ev->bdaddr);
- goto unlock;
- }
-
- /* If no side requires MITM protection; auto-accept */
- if ((!loc_mitm || conn->remote_cap == 0x03) &&
- (!rem_mitm || conn->io_capability == 0x03)) {
-
- /* If we're not the initiators request authorization to
- * proceed from user space (mgmt_user_confirm with
- * confirm_hint set to 1). */
- if (!test_bit(HCI_CONN_AUTH_PEND, &conn->flags)) {
- BT_DBG("Confirming auto-accept as acceptor");
- confirm_hint = 1;
- goto confirm;
- }
-
- BT_DBG("Auto-accept of user confirmation with %ums delay",
- hdev->auto_accept_delay);
-
- if (hdev->auto_accept_delay > 0) {
- int delay = msecs_to_jiffies(hdev->auto_accept_delay);
- mod_timer(&conn->auto_accept_timer, jiffies + delay);
- goto unlock;
- }
-
- hci_send_cmd(hdev, HCI_OP_USER_CONFIRM_REPLY,
- sizeof(ev->bdaddr), &ev->bdaddr);
- goto unlock;
- }
-
-confirm:
- mgmt_user_confirm_request(hdev, &ev->bdaddr, ACL_LINK, 0, ev->passkey,
- confirm_hint);
-
-unlock:
- hci_dev_unlock(hdev);
-}
-
-static inline void hci_user_passkey_request_evt(struct hci_dev *hdev,
- struct sk_buff *skb)
-{
- struct hci_ev_user_passkey_req *ev = (void *) skb->data;
-