diff options
Diffstat (limited to 'net')
-rw-r--r-- | net/6lowpan/iphc.c | 212 | ||||
-rw-r--r-- | net/bluetooth/hci_core.c | 185 | ||||
-rw-r--r-- | net/bluetooth/hci_event.c | 50 | ||||
-rw-r--r-- | net/bluetooth/hidp/core.c | 2 | ||||
-rw-r--r-- | net/bluetooth/mgmt.c | 57 | ||||
-rw-r--r-- | net/bluetooth/rfcomm/core.c | 7 | ||||
-rw-r--r-- | net/bluetooth/smp.c | 33 | ||||
-rw-r--r-- | net/nfc/digital.h | 3 | ||||
-rw-r--r-- | net/nfc/digital_core.c | 27 | ||||
-rw-r--r-- | net/nfc/digital_dep.c | 11 | ||||
-rw-r--r-- | net/nfc/digital_technology.c | 96 | ||||
-rw-r--r-- | net/nfc/hci/core.c | 7 | ||||
-rw-r--r-- | net/nfc/nci/ntf.c | 4 |
13 files changed, 520 insertions, 174 deletions
diff --git a/net/6lowpan/iphc.c b/net/6lowpan/iphc.c index a1b7117a9600..142eef55c9e2 100644 --- a/net/6lowpan/iphc.c +++ b/net/6lowpan/iphc.c @@ -177,8 +177,8 @@ static int skb_deliver(struct sk_buff *skb, struct ipv6hdr *hdr, struct sk_buff *new; int stat; - new = skb_copy_expand(skb, sizeof(struct ipv6hdr), - skb_tailroom(skb), GFP_ATOMIC); + new = skb_copy_expand(skb, sizeof(struct ipv6hdr), skb_tailroom(skb), + GFP_ATOMIC); kfree_skb(skb); if (!new) @@ -205,10 +205,9 @@ static int skb_deliver(struct sk_buff *skb, struct ipv6hdr *hdr, /* Uncompress function for multicast destination address, * when M bit is set. */ -static int -lowpan_uncompress_multicast_daddr(struct sk_buff *skb, - struct in6_addr *ipaddr, - const u8 dam) +static int lowpan_uncompress_multicast_daddr(struct sk_buff *skb, + struct in6_addr *ipaddr, + const u8 dam) { bool fail; @@ -254,41 +253,41 @@ lowpan_uncompress_multicast_daddr(struct sk_buff *skb, } raw_dump_inline(NULL, "Reconstructed ipv6 multicast addr is", - ipaddr->s6_addr, 16); + ipaddr->s6_addr, 16); return 0; } -static int -uncompress_udp_header(struct sk_buff *skb, struct udphdr *uh) +static int uncompress_udp_header(struct sk_buff *skb, struct udphdr *uh) { bool fail; u8 tmp = 0, val = 0; - if (!uh) - goto err; - - fail = lowpan_fetch_skb(skb, &tmp, 1); + fail = lowpan_fetch_skb(skb, &tmp, sizeof(tmp)); if ((tmp & LOWPAN_NHC_UDP_MASK) == LOWPAN_NHC_UDP_ID) { pr_debug("UDP header uncompression\n"); switch (tmp & LOWPAN_NHC_UDP_CS_P_11) { case LOWPAN_NHC_UDP_CS_P_00: - fail |= lowpan_fetch_skb(skb, &uh->source, 2); - fail |= lowpan_fetch_skb(skb, &uh->dest, 2); + fail |= lowpan_fetch_skb(skb, &uh->source, + sizeof(uh->source)); + fail |= lowpan_fetch_skb(skb, &uh->dest, + sizeof(uh->dest)); break; case LOWPAN_NHC_UDP_CS_P_01: - fail |= lowpan_fetch_skb(skb, &uh->source, 2); - fail |= lowpan_fetch_skb(skb, &val, 1); + fail |= lowpan_fetch_skb(skb, &uh->source, + sizeof(uh->source)); + fail |= lowpan_fetch_skb(skb, &val, sizeof(val)); uh->dest = htons(val + LOWPAN_NHC_UDP_8BIT_PORT); break; case LOWPAN_NHC_UDP_CS_P_10: - fail |= lowpan_fetch_skb(skb, &val, 1); + fail |= lowpan_fetch_skb(skb, &val, sizeof(val)); uh->source = htons(val + LOWPAN_NHC_UDP_8BIT_PORT); - fail |= lowpan_fetch_skb(skb, &uh->dest, 2); + fail |= lowpan_fetch_skb(skb, &uh->dest, + sizeof(uh->dest)); break; case LOWPAN_NHC_UDP_CS_P_11: - fail |= lowpan_fetch_skb(skb, &val, 1); + fail |= lowpan_fetch_skb(skb, &val, sizeof(val)); uh->source = htons(LOWPAN_NHC_UDP_4BIT_PORT + (val >> 4)); uh->dest = htons(LOWPAN_NHC_UDP_4BIT_PORT + @@ -307,10 +306,11 @@ uncompress_udp_header(struct sk_buff *skb, struct udphdr *uh) pr_debug_ratelimited("checksum elided currently not supported\n"); goto err; } else { - fail |= lowpan_fetch_skb(skb, &uh->check, 2); + fail |= lowpan_fetch_skb(skb, &uh->check, + sizeof(uh->check)); } - /* UDP lenght needs to be infered from the lower layers + /* UDP length needs to be infered from the lower layers * here, we obtain the hint from the remaining size of the * frame */ @@ -333,9 +333,8 @@ err: static const u8 lowpan_ttl_values[] = { 0, 1, 64, 255 }; int lowpan_process_data(struct sk_buff *skb, struct net_device *dev, - const u8 *saddr, const u8 saddr_type, - const u8 saddr_len, const u8 *daddr, - const u8 daddr_type, const u8 daddr_len, + const u8 *saddr, const u8 saddr_type, const u8 saddr_len, + const u8 *daddr, const u8 daddr_type, const u8 daddr_len, u8 iphc0, u8 iphc1, skb_delivery_cb deliver_skb) { struct ipv6hdr hdr = {}; @@ -348,7 +347,7 @@ int lowpan_process_data(struct sk_buff *skb, struct net_device *dev, /* another if the CID flag is set */ if (iphc1 & LOWPAN_IPHC_CID) { pr_debug("CID flag is set, increase header with one\n"); - if (lowpan_fetch_skb_u8(skb, &num_context)) + if (lowpan_fetch_skb(skb, &num_context, sizeof(num_context))) goto drop; } @@ -360,7 +359,7 @@ int lowpan_process_data(struct sk_buff *skb, struct net_device *dev, * ECN + DSCP + 4-bit Pad + Flow Label (4 bytes) */ case 0: /* 00b */ - if (lowpan_fetch_skb_u8(skb, &tmp)) + if (lowpan_fetch_skb(skb, &tmp, sizeof(tmp))) goto drop; memcpy(&hdr.flow_lbl, &skb->data[0], 3); @@ -373,7 +372,7 @@ int lowpan_process_data(struct sk_buff *skb, struct net_device *dev, * ECN + DSCP (1 byte), Flow Label is elided */ case 2: /* 10b */ - if (lowpan_fetch_skb_u8(skb, &tmp)) + if (lowpan_fetch_skb(skb, &tmp, sizeof(tmp))) goto drop; hdr.priority = ((tmp >> 2) & 0x0f); @@ -383,7 +382,7 @@ int lowpan_process_data(struct sk_buff *skb, struct net_device *dev, * ECN + 2-bit Pad + Flow Label (3 bytes), DSCP is elided */ case 1: /* 01b */ - if (lowpan_fetch_skb_u8(skb, &tmp)) + if (lowpan_fetch_skb(skb, &tmp, sizeof(tmp))) goto drop; hdr.flow_lbl[0] = (skb->data[0] & 0x0F) | ((tmp >> 2) & 0x30); @@ -400,7 +399,7 @@ int lowpan_process_data(struct sk_buff *skb, struct net_device *dev, /* Next Header */ if ((iphc0 & LOWPAN_IPHC_NH_C) == 0) { /* Next header is carried inline */ - if (lowpan_fetch_skb_u8(skb, &(hdr.nexthdr))) + if (lowpan_fetch_skb(skb, &hdr.nexthdr, sizeof(hdr.nexthdr))) goto drop; pr_debug("NH flag is set, next header carried inline: %02x\n", @@ -411,7 +410,8 @@ int lowpan_process_data(struct sk_buff *skb, struct net_device *dev, if ((iphc0 & 0x03) != LOWPAN_IPHC_TTL_I) { hdr.hop_limit = lowpan_ttl_values[iphc0 & 0x03]; } else { - if (lowpan_fetch_skb_u8(skb, &(hdr.hop_limit))) + if (lowpan_fetch_skb(skb, &hdr.hop_limit, + sizeof(hdr.hop_limit))) goto drop; } @@ -421,8 +421,7 @@ int lowpan_process_data(struct sk_buff *skb, struct net_device *dev, if (iphc1 & LOWPAN_IPHC_SAC) { /* Source address context based uncompression */ pr_debug("SAC bit is set. Handle context based source address.\n"); - err = uncompress_context_based_src_addr( - skb, &hdr.saddr, tmp); + err = uncompress_context_based_src_addr(skb, &hdr.saddr, tmp); } else { /* Source address uncompression */ pr_debug("source address stateless compression\n"); @@ -443,8 +442,9 @@ int lowpan_process_data(struct sk_buff *skb, struct net_device *dev, pr_debug("dest: context-based mcast compression\n"); /* TODO: implement this */ } else { - err = lowpan_uncompress_multicast_daddr( - skb, &hdr.daddr, tmp); + err = lowpan_uncompress_multicast_daddr(skb, &hdr.daddr, + tmp); + if (err) goto drop; } @@ -497,8 +497,7 @@ int lowpan_process_data(struct sk_buff *skb, struct net_device *dev, hdr.version, ntohs(hdr.payload_len), hdr.nexthdr, hdr.hop_limit, &hdr.daddr); - raw_dump_table(__func__, "raw header dump", - (u8 *)&hdr, sizeof(hdr)); + raw_dump_table(__func__, "raw header dump", (u8 *)&hdr, sizeof(hdr)); return skb_deliver(skb, &hdr, dev, deliver_skb); @@ -508,7 +507,7 @@ drop: } EXPORT_SYMBOL_GPL(lowpan_process_data); -static u8 lowpan_compress_addr_64(u8 **hc06_ptr, u8 shift, +static u8 lowpan_compress_addr_64(u8 **hc_ptr, u8 shift, const struct in6_addr *ipaddr, const unsigned char *lladdr) { @@ -519,24 +518,22 @@ static u8 lowpan_compress_addr_64(u8 **hc06_ptr, u8 shift, pr_debug("address compression 0 bits\n"); } else if (lowpan_is_iid_16_bit_compressable(ipaddr)) { /* compress IID to 16 bits xxxx::XXXX */ - memcpy(*hc06_ptr, &ipaddr->s6_addr16[7], 2); - *hc06_ptr += 2; + lowpan_push_hc_data(hc_ptr, &ipaddr->s6_addr16[7], 2); val = 2; /* 16-bits */ raw_dump_inline(NULL, "Compressed ipv6 addr is (16 bits)", - *hc06_ptr - 2, 2); + *hc_ptr - 2, 2); } else { /* do not compress IID => xxxx::IID */ - memcpy(*hc06_ptr, &ipaddr->s6_addr16[4], 8); - *hc06_ptr += 8; + lowpan_push_hc_data(hc_ptr, &ipaddr->s6_addr16[4], 8); val = 1; /* 64-bits */ raw_dump_inline(NULL, "Compressed ipv6 addr is (64 bits)", - *hc06_ptr - 8, 8); + *hc_ptr - 8, 8); } return rol8(val, shift); } -static void compress_udp_header(u8 **hc06_ptr, struct sk_buff *skb) +static void compress_udp_header(u8 **hc_ptr, struct sk_buff *skb) { struct udphdr *uh = udp_hdr(skb); u8 tmp; @@ -548,46 +545,46 @@ static void compress_udp_header(u8 **hc06_ptr, struct sk_buff *skb) pr_debug("UDP header: both ports compression to 4 bits\n"); /* compression value */ tmp = LOWPAN_NHC_UDP_CS_P_11; - lowpan_push_hc_data(hc06_ptr, &tmp, sizeof(tmp)); + lowpan_push_hc_data(hc_ptr, &tmp, sizeof(tmp)); /* source and destination port */ tmp = ntohs(uh->dest) - LOWPAN_NHC_UDP_4BIT_PORT + ((ntohs(uh->source) - LOWPAN_NHC_UDP_4BIT_PORT) << 4); - lowpan_push_hc_data(hc06_ptr, &tmp, sizeof(tmp)); + lowpan_push_hc_data(hc_ptr, &tmp, sizeof(tmp)); } else if ((ntohs(uh->dest) & LOWPAN_NHC_UDP_8BIT_MASK) == LOWPAN_NHC_UDP_8BIT_PORT) { pr_debug("UDP header: remove 8 bits of dest\n"); /* compression value */ tmp = LOWPAN_NHC_UDP_CS_P_01; - lowpan_push_hc_data(hc06_ptr, &tmp, sizeof(tmp)); + lowpan_push_hc_data(hc_ptr, &tmp, sizeof(tmp)); /* source port */ - lowpan_push_hc_data(hc06_ptr, &uh->source, sizeof(uh->source)); + lowpan_push_hc_data(hc_ptr, &uh->source, sizeof(uh->source)); /* destination port */ tmp = ntohs(uh->dest) - LOWPAN_NHC_UDP_8BIT_PORT; - lowpan_push_hc_data(hc06_ptr, &tmp, sizeof(tmp)); + lowpan_push_hc_data(hc_ptr, &tmp, sizeof(tmp)); } else if ((ntohs(uh->source) & LOWPAN_NHC_UDP_8BIT_MASK) == LOWPAN_NHC_UDP_8BIT_PORT) { pr_debug("UDP header: remove 8 bits of source\n"); /* compression value */ tmp = LOWPAN_NHC_UDP_CS_P_10; - lowpan_push_hc_data(hc06_ptr, &tmp, sizeof(tmp)); + lowpan_push_hc_data(hc_ptr, &tmp, sizeof(tmp)); /* source port */ tmp = ntohs(uh->source) - LOWPAN_NHC_UDP_8BIT_PORT; - lowpan_push_hc_data(hc06_ptr, &tmp, sizeof(tmp)); + lowpan_push_hc_data(hc_ptr, &tmp, sizeof(tmp)); /* destination port */ - lowpan_push_hc_data(hc06_ptr, &uh->dest, sizeof(uh->dest)); + lowpan_push_hc_data(hc_ptr, &uh->dest, sizeof(uh->dest)); } else { pr_debug("UDP header: can't compress\n"); /* compression value */ tmp = LOWPAN_NHC_UDP_CS_P_00; - lowpan_push_hc_data(hc06_ptr, &tmp, sizeof(tmp)); + lowpan_push_hc_data(hc_ptr, &tmp, sizeof(tmp)); /* source port */ - lowpan_push_hc_data(hc06_ptr, &uh->source, sizeof(uh->source)); + lowpan_push_hc_data(hc_ptr, &uh->source, sizeof(uh->source)); /* destination port */ - lowpan_push_hc_data(hc06_ptr, &uh->dest, sizeof(uh->dest)); + lowpan_push_hc_data(hc_ptr, &uh->dest, sizeof(uh->dest)); } /* checksum is always inline */ - lowpan_push_hc_data(hc06_ptr, &uh->check, sizeof(uh->check)); + lowpan_push_hc_data(hc_ptr, &uh->check, sizeof(uh->check)); /* skip the UDP header */ skb_pull(skb, sizeof(struct udphdr)); @@ -597,15 +594,16 @@ int lowpan_header_compress(struct sk_buff *skb, struct net_device *dev, unsigned short type, const void *_daddr, const void *_saddr, unsigned int len) { - u8 tmp, iphc0, iphc1, *hc06_ptr; + u8 tmp, iphc0, iphc1, *hc_ptr; struct ipv6hdr *hdr; u8 head[100] = {}; + int addr_type; if (type != ETH_P_IPV6) return -EINVAL; hdr = ipv6_hdr(skb); - hc06_ptr = head + 2; + hc_ptr = head + 2; pr_debug("IPv6 header dump:\n\tversion = %d\n\tlength = %d\n" "\tnexthdr = 0x%02x\n\thop_lim = %d\n\tdest = %pI6c\n", @@ -630,8 +628,7 @@ int lowpan_header_compress(struct sk_buff *skb, struct net_device *dev, raw_dump_inline(__func__, "daddr", (unsigned char *)_daddr, IEEE802154_ADDR_LEN); - raw_dump_table(__func__, - "sending raw skb network uncompressed packet", + raw_dump_table(__func__, "sending raw skb network uncompressed packet", skb->data, skb->len); /* Traffic class, flow label @@ -640,7 +637,7 @@ int lowpan_header_compress(struct sk_buff *skb, struct net_device *dev, * class depends on the presence of version and flow label */ - /* hc06 format of TC is ECN | DSCP , original one is DSCP | ECN */ + /* hc format of TC is ECN | DSCP , original one is DSCP | ECN */ tmp = (hdr->priority << 4) | (hdr->flow_lbl[0] >> 4); tmp = ((tmp & 0x03) << 6) | (tmp >> 2); @@ -654,8 +651,8 @@ int lowpan_header_compress(struct sk_buff *skb, struct net_device *dev, iphc0 |= LOWPAN_IPHC_TC_C; } else { /* compress only the flow label */ - *hc06_ptr = tmp; - hc06_ptr += 1; + *hc_ptr = tmp; + hc_ptr += 1; } } else { /* Flow label cannot be compressed */ @@ -663,15 +660,15 @@ int lowpan_header_compress(struct sk_buff *skb, struct net_device *dev, ((hdr->flow_lbl[0] & 0xF0) == 0)) { /* compress only traffic class */ iphc0 |= LOWPAN_IPHC_TC_C; - *hc06_ptr = (tmp & 0xc0) | (hdr->flow_lbl[0] & 0x0F); - memcpy(hc06_ptr + 1, &hdr->flow_lbl[1], 2); - hc06_ptr += 3; + *hc_ptr = (tmp & 0xc0) | (hdr->flow_lbl[0] & 0x0F); + memcpy(hc_ptr + 1, &hdr->flow_lbl[1], 2); + hc_ptr += 3; } else { /* compress nothing */ - memcpy(hc06_ptr, hdr, 4); + memcpy(hc_ptr, hdr, 4); /* replace the top byte with new ECN | DSCP format */ - *hc06_ptr = tmp; - hc06_ptr += 4; + *hc_ptr = tmp; + hc_ptr += 4; } } @@ -681,10 +678,9 @@ int lowpan_header_compress(struct sk_buff *skb, struct net_device *dev, if (hdr->nexthdr == UIP_PROTO_UDP) iphc0 |= LOWPAN_IPHC_NH_C; - if ((iphc0 & LOWPAN_IPHC_NH_C) == 0) { - *hc06_ptr = hdr->nexthdr; - hc06_ptr += 1; - } + if ((iphc0 & LOWPAN_IPHC_NH_C) == 0) + lowpan_push_hc_data(&hc_ptr, &hdr->nexthdr, + sizeof(hdr->nexthdr)); /* Hop limit * if 1: compress, encoding is 01 @@ -703,84 +699,86 @@ int lowpan_header_compress(struct sk_buff *skb, struct net_device *dev, iphc0 |= LOWPAN_IPHC_TTL_255; break; default: - *hc06_ptr = hdr->hop_limit; - hc06_ptr += 1; - break; + lowpan_push_hc_data(&hc_ptr, &hdr->hop_limit, + sizeof(hdr->hop_limit)); } + addr_type = ipv6_addr_type(&hdr->saddr); /* source address compression */ - if (is_addr_unspecified(&hdr->saddr)) { + if (addr_type == IPV6_ADDR_ANY) { pr_debug("source address is unspecified, setting SAC\n"); iphc1 |= LOWPAN_IPHC_SAC; - /* TODO: context lookup */ - } else if (is_addr_link_local(&hdr->saddr)) { - iphc1 |= lowpan_compress_addr_64(&hc06_ptr, - LOWPAN_IPHC_SAM_BIT, &hdr->saddr, _saddr); - pr_debug("source address unicast link-local %pI6c " - "iphc1 0x%02x\n", &hdr->saddr, iphc1); } else { - pr_debug("send the full source address\n"); - memcpy(hc06_ptr, &hdr->saddr.s6_addr16[0], 16); - hc06_ptr += 16; + if (addr_type & IPV6_ADDR_LINKLOCAL) { + iphc1 |= lowpan_compress_addr_64(&hc_ptr, + LOWPAN_IPHC_SAM_BIT, + &hdr->saddr, _saddr); + pr_debug("source address unicast link-local %pI6c iphc1 0x%02x\n", + &hdr->saddr, iphc1); + } else { + pr_debug("send the full source address\n"); + lowpan_push_hc_data(&hc_ptr, hdr->saddr.s6_addr, 16); + } } + addr_type = ipv6_addr_type(&hdr->daddr); /* destination address compression */ - if (is_addr_mcast(&hdr->daddr)) { + if (addr_type & IPV6_ADDR_MULTICAST) { pr_debug("destination address is multicast: "); iphc1 |= LOWPAN_IPHC_M; if (lowpan_is_mcast_addr_compressable8(&hdr->daddr)) { pr_debug("compressed to 1 octet\n"); iphc1 |= LOWPAN_IPHC_DAM_11; /* use last byte */ - *hc06_ptr = hdr->daddr.s6_addr[15]; - hc06_ptr += 1; + lowpan_push_hc_data(&hc_ptr, + &hdr->daddr.s6_addr[15], 1); } else if (lowpan_is_mcast_addr_compressable32(&hdr->daddr)) { pr_debug("compressed to 4 octets\n"); iphc1 |= LOWPAN_IPHC_DAM_10; /* second byte + the last three */ - *hc06_ptr = hdr->daddr.s6_addr[1]; - memcpy(hc06_ptr + 1, &hdr->daddr.s6_addr[13], 3); - hc06_ptr += 4; + lowpan_push_hc_data(&hc_ptr, + &hdr->daddr.s6_addr[1], 1); + lowpan_push_hc_data(&hc_ptr, + &hdr->daddr.s6_addr[13], 3); } else if (lowpan_is_mcast_addr_compressable48(&hdr->daddr)) { pr_debug("compressed to 6 octets\n"); iphc1 |= LOWPAN_IPHC_DAM_01; /* second byte + the last five */ - *hc06_ptr = hdr->daddr.s6_addr[1]; - memcpy(hc06_ptr + 1, &hdr->daddr.s6_addr[11], 5); - hc06_ptr += 6; + lowpan_push_hc_data(&hc_ptr, + &hdr->daddr.s6_addr[1], 1); + lowpan_push_hc_data(&hc_ptr, + &hdr->daddr.s6_addr[11], 5); } else { pr_debug("using full address\n"); iphc1 |= LOWPAN_IPHC_DAM_00; - memcpy(hc06_ptr, &hdr->daddr.s6_addr[0], 16); - hc06_ptr += 16; + lowpan_push_hc_data(&hc_ptr, hdr->daddr.s6_addr, 16); } } else { - /* TODO: context lookup */ - if (is_addr_link_local(&hdr->daddr)) { - iphc1 |= lowpan_compress_addr_64(&hc06_ptr, + if (addr_type & IPV6_ADDR_LINKLOCAL) { + /* TODO: context lookup */ + iphc1 |= lowpan_compress_addr_64(&hc_ptr, LOWPAN_IPHC_DAM_BIT, &hdr->daddr, _daddr); pr_debug("dest address unicast link-local %pI6c " - "iphc1 0x%02x\n", &hdr->daddr, iphc1); + "iphc1 0x%02x\n", &hdr->daddr, iphc1); } else { pr_debug("dest address unicast %pI6c\n", &hdr->daddr); - memcpy(hc06_ptr, &hdr->daddr.s6_addr16[0], 16); - hc06_ptr += 16; + lowpan_push_hc_data(&hc_ptr, hdr->daddr.s6_addr, 16); } } /* UDP header compression */ if (hdr->nexthdr == UIP_PROTO_UDP) - compress_udp_header(&hc06_ptr, skb); + compress_udp_header(&hc_ptr, skb); head[0] = iphc0; head[1] = iphc1; skb_pull(skb, sizeof(struct ipv6hdr)); skb_reset_transport_header(skb); - memcpy(skb_push(skb, hc06_ptr - head), head, hc06_ptr - head); + memcpy(skb_push(skb, hc_ptr - head), head, hc_ptr - head); skb_reset_network_header(skb); - pr_debug("header len %d skb %u\n", (int)(hc06_ptr - head), skb->len); + pr_debug("header len %d skb %u\n", (int)(hc_ptr - head), skb->len); raw_dump_table(__func__, "raw skb data dump compressed", skb->data, skb->len); diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c index cfcb6055ced8..32b96f1aaf42 100644 --- a/net/bluetooth/hci_core.c +++ b/net/bluetooth/hci_core.c @@ -970,6 +970,62 @@ static int adv_channel_map_get(void *data, u64 *val) DEFINE_SIMPLE_ATTRIBUTE(adv_channel_map_fops, adv_channel_map_get, adv_channel_map_set, "%llu\n"); +static int adv_min_interval_set(void *data, u64 val) +{ + struct hci_dev *hdev = data; + + if (val < 0x0020 || val > 0x4000 || val > hdev->le_adv_max_interval) + return -EINVAL; + + hci_dev_lock(hdev); + hdev->le_adv_min_interval = val; + hci_dev_unlock(hdev); + + return 0; +} + +static int adv_min_interval_get(void *data, u64 *val) +{ + struct hci_dev *hdev = data; + + hci_dev_lock(hdev); + *val = hdev->le_adv_min_interval; + hci_dev_unlock(hdev); + + return 0; +} + +DEFINE_SIMPLE_ATTRIBUTE(adv_min_interval_fops, adv_min_interval_get, + adv_min_interval_set, "%llu\n"); + +static int adv_max_interval_set(void *data, u64 val) +{ + struct hci_dev *hdev = data; + + if (val < 0x0020 || val > 0x4000 || val < hdev->le_adv_min_interval) + return -EINVAL; + + hci_dev_lock(hdev); + hdev->le_adv_max_interval = val; + hci_dev_unlock(hdev); + + return 0; +} + +static int adv_max_interval_get(void *data, u64 *val) +{ + struct hci_dev *hdev = data; + + hci_dev_lock(hdev); + *val = hdev->le_adv_max_interval; + hci_dev_unlock(hdev); + + return 0; +} + +DEFINE_SIMPLE_ATTRIBUTE(adv_max_interval_fops, adv_max_interval_get, + adv_max_interval_set, "%llu\n"); + static int device_list_show(struct seq_file *f, void *ptr) { struct hci_dev *hdev = f->private; @@ -1567,7 +1623,7 @@ static void hci_set_le_support(struct hci_request *req) if (test_bit(HCI_LE_ENABLED, &hdev->dev_flags)) { cp.le = 0x01; - cp.simul = lmp_le_br_capable(hdev); + cp.simul = 0x00; } if (cp.le != lmp_host_le_capable(hdev)) @@ -1686,6 +1742,14 @@ static void hci_init4_req(struct hci_request *req, unsigned long opt) if (hdev->commands[22] & 0x04) hci_set_event_mask_page_2(req); + /* Read local codec list if the HCI command is supported */ + if (hdev->commands[29] & 0x20) + hci_req_add(req, HCI_OP_READ_LOCAL_CODECS, 0, NULL); + + /* Get MWS transport configuration if the HCI command is supported */ + if (hdev->commands[30] & 0x08) + hci_req_add(req, HCI_OP_GET_MWS_TRANSPORT_CONFIG, 0, NULL); + /* Check for Synchronization Train support */ if (lmp_sync_train_capable(hdev)) hci_req_add(req, HCI_OP_READ_SYNC_TRAIN_PARAMS, 0, NULL); @@ -1825,6 +1889,10 @@ static int __hci_init(struct hci_dev *hdev) hdev, &supervision_timeout_fops); debugfs_create_file("adv_channel_map", 0644, hdev->debugfs, hdev, &adv_channel_map_fops); + debugfs_create_file("adv_min_interval", 0644, hdev->debugfs, + hdev, &adv_min_interval_fops); + debugfs_create_file("adv_max_interval", 0644, hdev->debugfs, + hdev, &adv_max_interval_fops); debugfs_create_file("device_list", 0444, hdev->debugfs, hdev, &device_list_fops); debugfs_create_u16("discov_interleaved_timeout", 0644, @@ -2453,14 +2521,14 @@ int hci_dev_open(__u16 dev) flush_workqueue(hdev->req_workqueue); /* For controllers not using the management interface and that - * are brought up using legacy ioctl, set the HCI_PAIRABLE bit + * are brought up using legacy ioctl, set the HCI_BONDABLE bit * so that pairing works for them. Once the management interface * is in use this bit will be cleared again and userspace has * to explicitly enable it. */ if (!test_bit(HCI_USER_CHANNEL, &hdev->dev_flags) && !test_bit(HCI_MGMT, &hdev->dev_flags)) - set_bit(HCI_PAIRABLE, &hdev->dev_flags); + set_bit(HCI_BONDABLE, &hdev->dev_flags); err = hci_dev_do_open(hdev); @@ -3639,6 +3707,7 @@ int hci_conn_params_set(struct hci_dev *hdev, bdaddr_t *addr, u8 addr_type, list_add(¶ms->action, &hdev->pend_le_reports); hci_update_background_scan(hdev); break; + case HCI_AUTO_CONN_DIRECT: case HCI_AUTO_CONN_ALWAYS: if (!is_connected(hdev, addr, addr_type)) { list_add(¶ms->action, &hdev->pend_le_conns); @@ -3914,6 +3983,8 @@ struct hci_dev *hci_alloc_dev(void) hdev->sniff_min_interval = 80; hdev->le_adv_channel_map = 0x07; + hdev->le_adv_min_interval = 0x0800; + hdev->le_adv_max_interval = 0x0800; hdev->le_scan_interval = 0x0060; hdev->le_scan_window = 0x0030; hdev->le_conn_min_interval = 0x0028; @@ -5397,12 +5468,113 @@ void hci_req_add_le_scan_disable(struct hci_request *req) hci_req_add(req, HCI_OP_LE_SET_SCAN_ENABLE, sizeof(cp), &cp); } +static void add_to_white_list(struct hci_request *req, + struct hci_conn_params *params) +{ + struct hci_cp_le_add_to_white_list cp; + + cp.bdaddr_type = params->addr_type; + bacpy(&cp.bdaddr, ¶ms->addr); + + hci_req_add(req, HCI_OP_LE_ADD_TO_WHITE_LIST, sizeof(cp), &cp); +} + +static u8 update_white_list(struct hci_request *req) +{ + struct hci_dev *hdev = req->hdev; + struct hci_conn_params *params; + struct bdaddr_list *b; + uint8_t white_list_entries = 0; + + /* Go through the current white list programmed into the + * controller one by one and check if that address is still + * in the list of pending connections or list of devices to + * report. If not present in either list, then queue the + * command to remove it from the controller. + */ + list_for_each_entry(b, &hdev->le_white_list, list) { + struct hci_cp_le_del_from_white_list cp; + + if (hci_pend_le_action_lookup(&hdev->pend_le_conns, + &b->bdaddr, b->bdaddr_type) || + hci_pend_le_action_lookup(&hdev->pend_le_reports, + &b->bdaddr, b->bdaddr_type)) { + white_list_entries++; + continue; + } + + cp.bdaddr_type = b->bdaddr_type; + bacpy(&cp.bdaddr, &b->bdaddr); + + hci_req_add(req, HCI_OP_LE_DEL_FROM_WHITE_LIST, + sizeof(cp), &cp); + } + + /* Since all no longer valid white list entries have been + * removed, walk through the list of pending connections + * and ensure that any new device gets programmed into + * the controller. + * + * If the list of the devices is larger than the list of + * available white list entries in the controller, then + * just abort and return filer policy value to not use the + * white list. + */ + list_for_each_entry(params, &hdev->pend_le_conns, action) { + if (hci_bdaddr_list_lookup(&hdev->le_white_list, + ¶ms->addr, params->addr_type)) + continue; + + if (white_list_entries >= hdev->le_white_list_size) { + /* Select filter policy to accept all advertising */ + return 0x00; + } + + if (hci_find_irk_by_addr(hdev, ¶ms->addr, + params->addr_type)) { + /* White list can not be used with RPAs */ + return 0x00; + } + + white_list_entries++; + add_to_white_list(req, params); + } + + /* After adding all new pending connections, walk through + * the list of pending reports and also add these to the + * white list if there is still space. + */ + list_for_each_entry(params, &hdev->pend_le_reports, action) { + if (hci_bdaddr_list_lookup(&hdev->le_white_list, + ¶ms->addr, params->addr_type)) + continue; + + if (white_list_entries >= hdev->le_white_list_size) { + /* Select filter policy to accept all advertising */ + return 0x00; + } + + if (hci_find_irk_by_addr(hdev, ¶ms->addr, + params->addr_type)) { + /* White list can not be used with RPAs */ + return 0x00; + } + + white_list_entries++; + add_to_white_list(req, params); + } + + /* Select filter policy to use white list */ + return 0x01; +} + void hci_req_add_le_passive_scan(struct hci_request *req) { struct hci_cp_le_set_scan_param param_cp; struct hci_cp_le_set_scan_enable enable_cp; struct hci_dev *hdev = req->hdev; u8 own_addr_type; + u8 filter_policy; /* Set require_privacy to false since no SCAN_REQ are send * during passive scanning. Not using an unresolvable address @@ -5413,11 +5585,18 @@ void hci_req_add_le_passive_scan(struct hci_request *req) if (hci_update_random_address(req, false, &own_addr_type)) return; + /* Adding or removing entries from the white list must + * happen before enabling scanning. The controller does + * not allow white list modification while scanning. + */ + filter_policy = update_white_list(req); + memset(¶m_cp, 0, sizeof(param_cp)); param_cp.type = LE_SCAN_PASSIVE; param_cp.interval = cpu_to_le16(hdev->le_scan_interval); param_cp.window = cpu_to_le16(hdev->le_scan_window); param_cp.own_address_type = own_addr_type; + param_cp.filter_policy = filter_policy; hci_req_add(req, HCI_OP_LE_SET_SCAN_PARAM, sizeof(param_cp), ¶m_cp); diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c index 4c41774aa556..be35598984d9 100644 --- a/net/bluetooth/hci_event.c +++ b/net/bluetooth/hci_event.c @@ -317,7 +317,7 @@ static void hci_cc_write_scan_enable(struct hci_dev *hdev, struct sk_buff *skb) if (param & SCAN_PAGE) set_bit(HCI_PSCAN, &hdev->flags); else - clear_bit(HCI_ISCAN, &hdev->flags); + clear_bit(HCI_PSCAN, &hdev->flags); done: hci_dev_unlock(hdev); @@ -2259,6 +2259,7 @@ static void hci_disconn_complete_evt(struct hci_dev *hdev, struct sk_buff *skb) break; /* Fall through */ + case HCI_AUTO_CONN_DIRECT: case HCI_AUTO_CONN_ALWAYS: list_del_init(¶ms->action); list_add(¶ms->action, &hdev->pend_le_conns); @@ -3118,7 +3119,7 @@ static void hci_pin_code_request_evt(struct hci_dev *hdev, struct sk_buff *skb) hci_conn_drop(conn); } - if (!test_bit(HCI_PAIRABLE, &hdev->dev_flags) && + if (!test_bit(HCI_BONDABLE, &hdev->dev_flags) && !test_bit(HCI_CONN_AUTH_INITIATOR, &conn->flags)) { hci_send_cmd(hdev, HCI_OP_PIN_CODE_NEG_REPLY, sizeof(ev->bdaddr), &ev->bdaddr); @@ -3651,7 +3652,7 @@ static void hci_io_capa_request_evt(struct hci_dev *hdev, struct sk_buff *skb) /* Allow pairing if we're pairable, the initiators of the * pairing or if the remote is not requesting bonding. */ - if (test_bit(HCI_PAIRABLE, &hdev->dev_flags) || + if (test_bit(HCI_BONDABLE, &hdev->dev_flags) || test_bit(HCI_CONN_AUTH_INITIATOR, &conn->flags) || (conn->remote_auth & ~0x01) == HCI_AT_NO_BONDING) { struct hci_cp_io_capability_reply cp; @@ -3670,13 +3671,18 @@ static void hci_io_capa_request_evt(struct hci_dev *hdev, struct sk_buff *skb) if (conn->io_capability != HCI_IO_NO_INPUT_OUTPUT && conn->auth_type != HCI_AT_NO_BONDING) conn->auth_type |= 0x01; - - cp.authentication = conn->auth_type; } else { conn->auth_type = hci_get_auth_req(conn); - cp.authentication = conn->auth_type; } + /* If we're not bondable, force one of the non-bondable + * authentication requirement values. + */ + if (!test_bit(HCI_BONDABLE, &hdev->dev_flags)) + conn->auth_type &= HCI_AT_NO_BONDING_MITM; + + cp.authentication = conn->auth_type; + if (hci_find_remote_oob_data(hdev, &conn->dst) && (conn->out || test_bit(HCI_CONN_REMOTE_OOB, &conn->flags))) cp.oob_data = 0x01; @@ -4251,6 +4257,7 @@ static void check_pending_le_conn(struct hci_dev *hdev, bdaddr_t *addr, u8 addr_type, u8 adv_type) { struct hci_conn *conn; + struct hci_conn_params *params; /* If the event is not connectable don't proceed further */ if (adv_type != LE_ADV_IND && adv_type != LE_ADV_DIRECT_IND) @@ -4266,18 +4273,35 @@ static void check_pending_le_conn(struct hci_dev *hdev, bdaddr_t *addr, if (hdev->conn_hash.le_num_slave > 0) return; - /* If we're connectable, always connect any ADV_DIRECT_IND event */ - if (test_bit(HCI_CONNECTABLE, &hdev->dev_flags) && - adv_type == LE_ADV_DIRECT_IND) - goto connect; - /* If we're not connectable only connect devices that we have in * our pend_le_conns list. */ - if (!hci_pend_le_action_lookup(&hdev->pend_le_conns, addr, addr_type)) + params = hci_pend_le_action_lookup(&hdev->pend_le_conns, + addr, addr_type); + if (!params) + return; + + switch (params->auto_connect) { + case HCI_AUTO_CONN_DIRECT: + /* Only devices advertising with ADV_DIRECT_IND are + * triggering a connection attempt. This is allowing + * incoming connections from slave devices. + */ + if (adv_type != LE_ADV_DIRECT_IND) + return; + break; + case HCI_AUTO_CONN_ALWAYS: + /* Devices advertising with ADV_IND or ADV_DIRECT_IND + * are triggering a connection attempt. This means + * that incoming connectioms from slave device are + * accepted and also outgoing connections to slave + * devices are established when found. + */ + break; + default: return; + } -connect: conn = hci_connect_le(hdev, addr, addr_type, BT_SECURITY_LOW, HCI_LE_AUTOCONN_TIMEOUT, HCI_ROLE_MASTER); if (!IS_ERR(conn)) diff --git a/net/bluetooth/hidp/core.c b/net/bluetooth/hidp/core.c index 8181ea4bc2f2..6c7ecf116e74 100644 --- a/net/bluetooth/hidp/core.c +++ b/net/bluetooth/hidp/core.c @@ -154,7 +154,7 @@ static int hidp_input_event(struct input_dev *dev, unsigned int type, (!!test_bit(LED_COMPOSE, dev->led) << 3) | (!!test_bit(LED_SCROLLL, dev->led) << 2) | (!!test_bit(LED_CAPSL, dev->led) << 1) | - (!!test_bit(LED_NUML, dev->led)); + (!!test_bit(LED_NUML, dev->led) << 0); if (session->leds == newleds) return 0; diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index 190668367e42..b8554d429d88 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -44,7 +44,7 @@ static const u16 mgmt_commands[] = { MGMT_OP_SET_DISCOVERABLE, MGMT_OP_SET_CONNECTABLE, MGMT_OP_SET_FAST_CONNECTABLE, - MGMT_OP_SET_PAIRABLE, + MGMT_OP_SET_BONDABLE, MGMT_OP_SET_LINK_SECURITY, MGMT_OP_SET_SSP, MGMT_OP_SET_HS, @@ -553,7 +553,7 @@ static u32 get_supported_settings(struct hci_dev *hdev) u32 settings = 0; settings |= MGMT_SETTING_POWERED; - settings |= MGMT_SETTING_PAIRABLE; + settings |= MGMT_SETTING_BONDABLE; settings |= MGMT_SETTING_DEBUG_KEYS; settings |= MGMT_SETTING_CONNECTABLE; settings |= MGMT_SETTING_DISCOVERABLE; @@ -603,8 +603,8 @@ static u32 get_current_settings(struct hci_dev *hdev) if (test_bit(HCI_DISCOVERABLE, &hdev->dev_flags)) settings |= MGMT_SETTING_DISCOVERABLE; - if (test_bit(HCI_PAIRABLE, &hdev->dev_flags)) - settings |= MGMT_SETTING_PAIRABLE; + if (test_bit(HCI_BONDABLE, &hdev->dev_flags)) + settings |= MGMT_SETTING_BONDABLE; if (test_bit(HCI_BREDR_ENABLED, &hdev->dev_flags)) settings |= MGMT_SETTING_BREDR; @@ -1086,8 +1086,8 @@ static void enable_advertising(struct hci_request *req) return; memset(&cp, 0, sizeof(cp)); - cp.min_interval = cpu_to_le16(0x0800); - cp.max_interval = cpu_to_le16(0x0800); + cp.min_interval = cpu_to_le16(hdev->le_adv_min_interval); + cp.max_interval = cpu_to_le16(hdev->le_adv_max_interval); cp.type = connectable ? LE_ADV_IND : LE_ADV_NONCONN_IND; cp.own_address_type = own_addr_type; cp.channel_map = hdev->le_adv_channel_map; @@ -1152,7 +1152,7 @@ static void mgmt_init_hdev(struct sock *sk, struct hci_dev *hdev) * for mgmt we require user-space to explicitly enable * it */ - clear_bit(HCI_PAIRABLE, &hdev->dev_flags); + clear_bit(HCI_BONDABLE, &hdev->dev_flags); } static int read_controller_info(struct sock *sk, struct hci_dev *hdev, @@ -1881,7 +1881,18 @@ static int set_connectable(struct sock *sk, struct hci_dev *hdev, void *data, if (cp->val) { scan = SCAN_PAGE; } else { - scan = 0; + /* If we don't have any whitelist entries just + * disable all scanning. If there are entries + * and we had both page and inquiry scanning + * enabled then fall back to only page scanning. + * Otherwise no changes are needed. + */ + if (list_empty(&hdev->whitelist)) + scan = SCAN_DISABLED; + else if (test_bit(HCI_ISCAN, &hdev->flags)) + scan = SCAN_PAGE; + else + goto no_scan_update; if (test_bit(HCI_ISCAN, &hdev->flags) && hdev->discov_timeout > 0) @@ -1891,6 +1902,7 @@ static int set_connectable(struct sock *sk, struct hci_dev *hdev, void *data, hci_req_add(&req, HCI_OP_WRITE_SCAN_ENABLE, 1, &scan); } +no_scan_update: /* If we're going from non-connectable to connectable or * vice-versa when fast connectable is enabled ensure that fast * connectable gets disabled. write_fast_connectable won't do @@ -1918,7 +1930,7 @@ failed: return err; } -static int set_pairable(struct sock *sk, struct hci_dev *hdev, void *data, +static int set_bondable(struct sock *sk, struct hci_dev *hdev, void *data, u16 len) { struct mgmt_mode *cp = data; @@ -1928,17 +1940,17 @@ static int set_pairable(struct sock *sk, struct hci_dev *hdev, void *data, BT_DBG("request for %s", hdev->name); if (cp->val != 0x00 && cp->val != 0x01) - return cmd_status(sk, hdev->id, MGMT_OP_SET_PAIRABLE, + return cmd_status(sk, hdev->id, MGMT_OP_SET_BONDABLE, MGMT_STATUS_INVALID_PARAMS); hci_dev_lock(hdev); if (cp->val) - changed = !test_and_set_bit(HCI_PAIRABLE, &hdev->dev_flags); + changed = !test_and_set_bit(HCI_BONDABLE, &hdev->dev_flags); else - changed = test_and_clear_bit(HCI_PAIRABLE, &hdev->dev_flags); + changed = test_and_clear_bit(HCI_BONDABLE, &hdev->dev_flags); - err = send_settings_rsp(sk, MGMT_OP_SET_PAIRABLE, hdev); + err = send_settings_rsp(sk, MGMT_OP_SET_BONDABLE, hdev); if (err < 0) goto unlock; @@ -2264,7 +2276,7 @@ static int set_le(struct sock *sk, struct hci_dev *hdev, void *data, u16 len) if (val) { hci_cp.le = val; - hci_cp.simul = lmp_le_br_capable(hdev); + hci_cp.simul = 0x00; } else { if (test_bit(HCI_LE_ADV, &hdev->dev_flags)) disable_advertising(&req); @@ -3201,7 +3213,7 @@ static int pair_device(struct sock *sk, struct hci_dev *hdev, void *data, conn->io_capability = cp->io_cap; cmd->user_data = conn; - if (conn->state == BT_CONNECTED && + if ((conn->state == BT_CONNECTED || conn->state == BT_CONFIG) && hci_conn_security(conn, sec_level, auth_type, true)) pairing_complete(cmd, 0); @@ -5271,7 +5283,7 @@ static int add_device(struct sock *sk, struct hci_dev *hdev, MGMT_STATUS_INVALID_PARAMS, &cp->addr, sizeof(cp->addr)); - if (cp->action != 0x00 && cp->action != 0x01) + if (cp->action != 0x00 && cp->action != 0x01 && cp->action != 0x02) return cmd_complete(sk, hdev->id, MGMT_OP_ADD_DEVICE, MGMT_STATUS_INVALID_PARAMS, &cp->addr, sizeof(cp->addr)); @@ -5281,7 +5293,7 @@ static int add_device(struct sock *sk, struct hci_dev *hdev, if (cp->addr.type == BDADDR_BREDR) { bool update_scan; - /* Only "connect" action supported for now */ + /* Only incoming connections action is supported for now */ if (cp->action != 0x01) { err = cmd_complete(sk, hdev->id, MGMT_OP_ADD_DEVICE, MGMT_STATUS_INVALID_PARAMS, @@ -5307,8 +5319,10 @@ static int add_device(struct sock *sk, struct hci_dev *hdev, else addr_type = ADDR_LE_DEV_RANDOM; - if (cp->action) + if (cp->action == 0x02) auto_conn = HCI_AUTO_CONN_ALWAYS; + else if (cp->action == 0x01) + auto_conn = HCI_AUTO_CONN_DIRECT; else auto_conn = HCI_AUTO_CONN_REPORT; @@ -5665,7 +5679,7 @@ static const struct mgmt_handler { { set_discoverable, false, MGMT_SET_DISCOVERABLE_SIZE }, { set_connectable, false, MGMT_SETTING_SIZE }, { set_fast_connectable, false, MGMT_SETTING_SIZE }, - { set_pairable, false, MGMT_SETTING_SIZE }, + { set_bondable, false, MGMT_SETTING_SIZE }, { set_link_security, false, MGMT_SETTING_SIZE }, { set_ssp, false, MGMT_SETTING_SIZE }, { set_hs, false, MGMT_SETTING_SIZE }, @@ -5870,6 +5884,7 @@ static void restart_le_actions(struct hci_dev *hdev) list_del_init(&p->action); switch (p->auto_connect) { + case HCI_AUTO_CONN_DIRECT: case HCI_AUTO_CONN_ALWAYS: list_add(&p->action, &hdev->pend_le_conns); break; @@ -5922,8 +5937,8 @@ static int powered_update_hci(struct hci_dev *hdev) lmp_bredr_capable(hdev)) { struct hci_cp_write_le_host_supported cp; - cp.le = 1; - cp.simul = lmp_le_br_capable(hdev); + cp.le = 0x01; + cp.simul = 0x00; /* Check first if we already have the right * host state (host features set) diff --git a/net/bluetooth/rfcomm/core.c b/net/bluetooth/rfcomm/core.c index a0690a84f3e9..af73bc3acb40 100644 --- a/net/bluetooth/rfcomm/core.c +++ b/net/bluetooth/rfcomm/core.c @@ -1910,10 +1910,13 @@ static struct rfcomm_session *rfcomm_process_rx(struct rfcomm_session *s) /* Get data directly from socket receive queue without copying it. */ while ((skb = skb_dequeue(&sk->sk_receive_queue))) { skb_orphan(skb); - if (!skb_linearize(skb)) + if (!skb_linearize(skb)) { s = rfcomm_recv_frame(s, skb); - else + if (!s) + break; + } else { kfree_skb(skb); + } } if (s && (sk->sk_state == BT_CLOSED)) diff --git a/net/bluetooth/smp.c b/net/bluetooth/smp.c index e49c83d8b957..fd3294300803 100644 --- a/net/bluetooth/smp.c +++ b/net/bluetooth/smp.c @@ -307,7 +307,7 @@ static void build_pairing_cmd(struct l2cap_conn *conn, struct hci_dev *hdev = hcon->hdev; u8 local_dist = 0, remote_dist = 0; - if (test_bit(HCI_PAIRABLE, &conn->hcon->hdev->dev_flags)) { + if (test_bit(HCI_BONDABLE, &conn->hcon->hdev->dev_flags)) { local_dist = SMP_DIST_ENC_KEY | SMP_DIST_SIGN; remote_dist = SMP_DIST_ENC_KEY | SMP_DIST_SIGN; authreq |= SMP_AUTH_BONDING; @@ -579,13 +579,16 @@ static struct smp_chan *smp_chan_create(struct l2cap_conn *conn) struct smp_chan *smp; smp = kzalloc(sizeof(*smp), GFP_ATOMIC); - if (!smp) + if (!smp) { + clear_bit(HCI_CONN_LE_SMP_PEND, &conn->hcon->flags); return NULL; + } smp->tfm_aes = crypto_alloc_blkcipher("ecb(aes)", 0, CRYPTO_ALG_ASYNC); if (IS_ERR(smp->tfm_aes)) { BT_ERR("Unable to create ECB crypto context"); kfree(smp); + clear_bit(HCI_CONN_LE_SMP_PEND, &conn->hcon->flags); return NULL; } @@ -701,7 +704,7 @@ static u8 smp_cmd_pairing_req(struct l2cap_conn *conn, struct sk_buff *skb) if (!smp) return SMP_UNSPECIFIED; - if (!test_bit(HCI_PAIRABLE, &hdev->dev_flags) && + if (!test_bit(HCI_BONDABLE, &hdev->dev_flags) && (req->auth_req & SMP_AUTH_BONDING)) return SMP_PAIRING_NOTSUPP; @@ -923,14 +926,14 @@ static u8 smp_cmd_security_req(struct l2cap_conn *conn, struct sk_buff *skb) if (test_and_set_bit(HCI_CONN_LE_SMP_PEND, &hcon->flags)) return 0; - if (!test_bit(HCI_PAIRABLE, &hcon->hdev->dev_flags) && - (rp->auth_req & SMP_AUTH_BONDING)) - return SMP_PAIRING_NOTSUPP; - smp = smp_chan_create(conn); if (!smp) return SMP_UNSPECIFIED; + if (!test_bit(HCI_BONDABLE, &hcon->hdev->dev_flags) && + (rp->auth_req & SMP_AUTH_BONDING)) + return SMP_PAIRING_NOTSUPP; + skb_pull(skb, sizeof(*rp)); memset(&cp, 0, sizeof(cp)); @@ -1291,6 +1294,22 @@ static void smp_notify_keys(struct l2cap_conn *conn) bacpy(&hcon->dst, &smp->remote_irk->bdaddr); hcon->dst_type = smp->remote_irk->addr_type; l2cap_conn_update_id_addr(hcon); + + /* When receiving an indentity resolving key for + * a remote device that does not use a resolvable + * private address, just remove the key so that + * it is possible to use the controller white + * list for scanning. + * + * Userspace will have been told to not store + * this key at this point. So it is safe to + * just remove it. + */ + if (!bacmp(&smp->remote_irk->rpa, BDADDR_ANY)) { + list_del(&smp->remote_irk->list); + kfree(smp->remote_irk); + smp->remote_irk = NULL; + } } /* The LTKs and CSRKs should be persistent only if both sides diff --git a/net/nfc/digital.h b/net/nfc/digital.h index 71ad7eefddd4..3c39c72eb038 100644 --- a/net/nfc/digital.h +++ b/net/nfc/digital.h @@ -29,6 +29,7 @@ #define DIGITAL_CMD_TG_SEND 1 #define DIGITAL_CMD_TG_LISTEN 2 #define DIGITAL_CMD_TG_LISTEN_MDAA 3 +#define DIGITAL_CMD_TG_LISTEN_MD 4 #define DIGITAL_MAX_HEADER_LEN 7 #define DIGITAL_CRC_LEN 2 @@ -121,6 +122,8 @@ int digital_tg_send_dep_res(struct nfc_digital_dev *ddev, struct sk_buff *skb); int digital_tg_listen_nfca(struct nfc_digital_dev *ddev, u8 rf_tech); int digital_tg_listen_nfcf(struct nfc_digital_dev *ddev, u8 rf_tech); +void digital_tg_recv_md_req(struct nfc_digital_dev *ddev, void *arg, + struct sk_buff *resp); typedef u16 (*crc_func_t)(u16, const u8 *, size_t); diff --git a/net/nfc/digital_core.c b/net/nfc/digital_core.c index a6ce3c627e4e..009bcf317101 100644 --- a/net/nfc/digital_core.c +++ b/net/nfc/digital_core.c @@ -201,6 +201,11 @@ static void digital_wq_cmd(struct work_struct *work) digital_send_cmd_complete, cmd); break; + case DIGITAL_CMD_TG_LISTEN_MD: + rc = ddev->ops->tg_listen_md(ddev, cmd->timeout, + digital_send_cmd_complete, cmd); + break; + default: pr_err("Unknown cmd type %d\n", cmd->type); return; @@ -293,12 +298,19 @@ static int digital_tg_listen_mdaa(struct nfc_digital_dev *ddev, u8 rf_tech) 500, digital_tg_recv_atr_req, NULL); } +static int digital_tg_listen_md(struct nfc_digital_dev *ddev, u8 rf_tech) +{ + return digital_send_cmd(ddev, DIGITAL_CMD_TG_LISTEN_MD, NULL, NULL, 500, + digital_tg_recv_md_req, NULL); +} + int digital_target_found(struct nfc_digital_dev *ddev, struct nfc_target *target, u8 protocol) { int rc; u8 framing; u8 rf_tech; + u8 poll_tech_count; int (*check_crc)(struct sk_buff *skb); void (*add_crc)(struct sk_buff *skb); @@ -375,12 +387,16 @@ int digital_target_found(struct nfc_digital_dev *ddev, return rc; target->supported_protocols = (1 << protocol); - rc = nfc_targets_found(ddev->nfc_dev, target, 1); - if (rc) - return rc; + poll_tech_count = ddev->poll_tech_count; ddev->poll_tech_count = 0; + rc = nfc_targets_found(ddev->nfc_dev, target, 1); + if (rc) { + ddev->poll_tech_count = poll_tech_count; + return rc; + } + return 0; } @@ -505,6 +521,9 @@ static int digital_start_poll(struct nfc_dev *nfc_dev, __u32 im_protocols, if (ddev->ops->tg_listen_mdaa) { digital_add_poll_tech(ddev, 0, digital_tg_listen_mdaa); + } else if (ddev->ops->tg_listen_md) { + digital_add_poll_tech(ddev, 0, + digital_tg_listen_md); } else { digital_add_poll_tech(ddev, NFC_DIGITAL_RF_TECH_106A, digital_tg_listen_nfca); @@ -732,7 +751,7 @@ struct nfc_digital_dev *nfc_digital_allocate_device(struct nfc_digital_ops *ops, if (!ops->in_configure_hw || !ops->in_send_cmd || !ops->tg_listen || !ops->tg_configure_hw || !ops->tg_send_cmd || !ops->abort_cmd || - !ops->switch_rf) + !ops->switch_rf || (ops->tg_listen_md && !ops->tg_get_rf_tech)) return NULL; ddev = kzalloc(sizeof(struct nfc_digital_dev), GFP_KERNEL); diff --git a/net/nfc/digital_dep.c b/net/nfc/digital_dep.c index 37deb173c956..e1638dab076d 100644 --- a/net/nfc/digital_dep.c +++ b/net/nfc/digital_dep.c @@ -671,6 +671,7 @@ void digital_tg_recv_atr_req(struct nfc_digital_dev *ddev, void *arg, int rc; struct digital_atr_req *atr_req; size_t gb_len, min_size; + u8 poll_tech_count; if (IS_ERR(resp)) { rc = PTR_ERR(resp); @@ -728,12 +729,16 @@ void digital_tg_recv_atr_req(struct nfc_digital_dev *ddev, void *arg, goto exit; gb_len = resp->len - sizeof(struct digital_atr_req); + + poll_tech_count = ddev->poll_tech_count; + ddev->poll_tech_count = 0; + rc = nfc_tm_activated(ddev->nfc_dev, NFC_PROTO_NFC_DEP_MASK, NFC_COMM_PASSIVE, atr_req->gb, gb_len); - if (rc) + if (rc) { + ddev->poll_tech_count = poll_tech_count; goto exit; - - ddev->poll_tech_count = 0; + } rc = 0; exit: diff --git a/net/nfc/digital_technology.c b/net/nfc/digital_technology.c index c2c1c0189b7c..fb58ed2dd41d 100644 --- a/net/nfc/digital_technology.c +++ b/net/nfc/digital_technology.c @@ -318,6 +318,8 @@ static void digital_in_recv_sel_res(struct nfc_digital_dev *ddev, void *arg, if (DIGITAL_SEL_RES_IS_T2T(sel_res)) { nfc_proto = NFC_PROTO_MIFARE; + } else if (DIGITAL_SEL_RES_IS_NFC_DEP(sel_res)) { + nfc_proto = NFC_PROTO_NFC_DEP; } else if (DIGITAL_SEL_RES_IS_T4T(sel_res)) { rc = digital_in_send_rats(ddev, target); if (rc) @@ -327,8 +329,6 @@ static void digital_in_recv_sel_res(struct nfc_digital_dev *ddev, void *arg, * done when receiving the ATS */ goto exit_free_skb; - } else if (DIGITAL_SEL_RES_IS_NFC_DEP(sel_res)) { - nfc_proto = NFC_PROTO_NFC_DEP; } else { rc = -EOPNOTSUPP; goto exit; @@ -944,6 +944,13 @@ static int digital_tg_send_sel_res(struct nfc_digital_dev *ddev) if (!DIGITAL_DRV_CAPS_TG_CRC(ddev)) digital_skb_add_crc_a(skb); + rc = digital_tg_configure_hw(ddev, NFC_DIGITAL_CONFIG_FRAMING, + NFC_DIGITAL_FRAMING_NFCA_ANTICOL_COMPLETE); + if (rc) { + kfree_skb(skb); + return rc; + } + rc = digital_tg_send_cmd(ddev, skb, 300, digital_tg_recv_atr_req, NULL); if (rc) @@ -1002,6 +1009,13 @@ static int digital_tg_send_sdd_res(struct nfc_digital_dev *ddev) for (i = 0; i < 4; i++) sdd_res->bcc ^= sdd_res->nfcid1[i]; + rc = digital_tg_configure_hw(ddev, NFC_DIGITAL_CONFIG_FRAMING, + NFC_DIGITAL_FRAMING_NFCA_STANDARD_WITH_CRC_A); + if (rc) { + kfree_skb(skb); + return rc; + } + rc = digital_tg_send_cmd(ddev, skb, 300, digital_tg_recv_sel_req, NULL); if (rc) @@ -1054,6 +1068,13 @@ static int digital_tg_send_sens_res(struct nfc_digital_dev *ddev) sens_res[0] = (DIGITAL_SENS_RES_NFC_DEP >> 8) & 0xFF; sens_res[1] = DIGITAL_SENS_RES_NFC_DEP & 0xFF; + rc = digital_tg_configure_hw(ddev, NFC_DIGITAL_CONFIG_FRAMING, + NFC_DIGITAL_FRAMING_NFCA_STANDARD); + if (rc) { + kfree_skb(skb); + return rc; + } + rc = digital_tg_send_cmd(ddev, skb, 300, digital_tg_recv_sdd_req, NULL); if (rc) @@ -1197,33 +1218,48 @@ exit: dev_kfree_skb(resp); } -int digital_tg_listen_nfca(struct nfc_digital_dev *ddev, u8 rf_tech) +static int digital_tg_config_nfca(struct nfc_digital_dev *ddev) { int rc; - rc = digital_tg_configure_hw(ddev, NFC_DIGITAL_CONFIG_RF_TECH, rf_tech); + rc = digital_tg_configure_hw(ddev, NFC_DIGITAL_CONFIG_RF_TECH, + NFC_DIGITAL_RF_TECH_106A); if (rc) return rc; - rc = digital_tg_configure_hw(ddev, NFC_DIGITAL_CONFIG_FRAMING, - NFC_DIGITAL_FRAMING_NFCA_NFC_DEP); + return digital_tg_configure_hw(ddev, NFC_DIGITAL_CONFIG_FRAMING, + NFC_DIGITAL_FRAMING_NFCA_NFC_DEP); +} + +int digital_tg_listen_nfca(struct nfc_digital_dev *ddev, u8 rf_tech) +{ + int rc; + + rc = digital_tg_config_nfca(ddev); if (rc) return rc; return digital_tg_listen(ddev, 300, digital_tg_recv_sens_req, NULL); } -int digital_tg_listen_nfcf(struct nfc_digital_dev *ddev, u8 rf_tech) +static int digital_tg_config_nfcf(struct nfc_digital_dev *ddev, u8 rf_tech) { int rc; - u8 *nfcid2; rc = digital_tg_configure_hw(ddev, NFC_DIGITAL_CONFIG_RF_TECH, rf_tech); if (rc) return rc; - rc = digital_tg_configure_hw(ddev, NFC_DIGITAL_CONFIG_FRAMING, - NFC_DIGITAL_FRAMING_NFCF_NFC_DEP); + return digital_tg_configure_hw(ddev, NFC_DIGITAL_CONFIG_FRAMING, + NFC_DIGITAL_FRAMING_NFCF_NFC_DEP); +} + +int digital_tg_listen_nfcf(struct nfc_digital_dev *ddev, u8 rf_tech) +{ + int rc; + u8 *nfcid2; + + rc = digital_tg_config_nfcf(ddev, rf_tech); if (rc) return rc; @@ -1237,3 +1273,43 @@ int digital_tg_listen_nfcf(struct nfc_digital_dev *ddev, u8 rf_tech) return digital_tg_listen(ddev, 300, digital_tg_recv_sensf_req, nfcid2); } + +void digital_tg_recv_md_req(struct nfc_digital_dev *ddev, void *arg, + struct sk_buff *resp) +{ + u8 rf_tech; + int rc; + + if (IS_ERR(resp)) { + resp = NULL; + goto exit_free_skb; + } + + rc = ddev->ops->tg_get_rf_tech(ddev, &rf_tech); + if (rc) + goto exit_free_skb; + + switch (rf_tech) { + case NFC_DIGITAL_RF_TECH_106A: + rc = digital_tg_config_nfca(ddev); + if (rc) + goto exit_free_skb; + digital_tg_recv_sens_req(ddev, arg, resp); + break; + case NFC_DIGITAL_RF_TECH_212F: + case NFC_DIGITAL_RF_TECH_424F: + rc = digital_tg_config_nfcf(ddev, rf_tech); + if (rc) + goto exit_free_skb; + digital_tg_recv_sensf_req(ddev, arg, resp); + break; + default: + goto exit_free_skb; + } + + return; + +exit_free_skb: + digital_poll_next_tech(ddev); + dev_kfree_skb(resp); +} diff --git a/net/nfc/hci/core.c b/net/nfc/hci/core.c index 47403705197e..117708263ced 100644 --- a/net/nfc/hci/core.c +++ b/net/nfc/hci/core.c @@ -553,8 +553,11 @@ static void hci_stop_poll(struct nfc_dev *nfc_dev) { struct nfc_hci_dev *hdev = nfc_get_drvdata(nfc_dev); - nfc_hci_send_event(hdev, NFC_HCI_RF_READER_A_GATE, - NFC_HCI_EVT_END_OPERATION, NULL, 0); + if (hdev->ops->stop_poll) + hdev->ops->stop_poll(hdev); + else + nfc_hci_send_event(hdev, NFC_HCI_RF_READER_A_GATE, + NFC_HCI_EVT_END_OPERATION, NULL, 0); } static int hci_dep_link_up(struct nfc_dev *nfc_dev, struct nfc_target *target, diff --git a/net/nfc/nci/ntf.c b/net/nfc/nci/ntf.c index f8f6af231381..df91bb95b12a 100644 --- a/net/nfc/nci/ntf.c +++ b/net/nfc/nci/ntf.c @@ -166,7 +166,9 @@ static int nci_add_new_protocol(struct nci_dev *ndev, struct rf_tech_specific_params_nfcf_poll *nfcf_poll; __u32 protocol; - if (rf_protocol == NCI_RF_PROTOCOL_T2T) + if (rf_protocol == NCI_RF_PROTOCOL_T1T) + protocol = NFC_PROTO_JEWEL_MASK; + else if (rf_protocol == NCI_RF_PROTOCOL_T2T) protocol = NFC_PROTO_MIFARE_MASK; else if (rf_protocol == NCI_RF_PROTOCOL_ISO_DEP) if (rf_tech_and_mode == NCI_NFC_A_PASSIVE_POLL_MODE) |