diff options
Diffstat (limited to 'net')
369 files changed, 15676 insertions, 12785 deletions
diff --git a/net/6lowpan/Kconfig b/net/6lowpan/Kconfig new file mode 100644 index 000000000000..e4a02ef55102 --- /dev/null +++ b/net/6lowpan/Kconfig | |||
| @@ -0,0 +1,6 @@ | |||
| 1 | config 6LOWPAN | ||
| 2 | tristate "6LoWPAN Support" | ||
| 3 | depends on IPV6 | ||
| 4 | ---help--- | ||
| 5 | This enables IPv6 over Low power Wireless Personal Area Network - | ||
| 6 | "6LoWPAN" which is supported by IEEE 802.15.4 or Bluetooth stacks. | ||
diff --git a/net/6lowpan/Makefile b/net/6lowpan/Makefile new file mode 100644 index 000000000000..415886bb456a --- /dev/null +++ b/net/6lowpan/Makefile | |||
| @@ -0,0 +1,3 @@ | |||
| 1 | obj-$(CONFIG_6LOWPAN) := 6lowpan.o | ||
| 2 | |||
| 3 | 6lowpan-y := iphc.o | ||
diff --git a/net/ieee802154/6lowpan_iphc.c b/net/6lowpan/iphc.c index 211b5686d719..142eef55c9e2 100644 --- a/net/ieee802154/6lowpan_iphc.c +++ b/net/6lowpan/iphc.c | |||
| @@ -3,8 +3,7 @@ | |||
| 3 | * written by Alexander Smirnov <alex.bluesman.smirnov@gmail.com> | 3 | * written by Alexander Smirnov <alex.bluesman.smirnov@gmail.com> |
| 4 | */ | 4 | */ |
| 5 | 5 | ||
| 6 | /* | 6 | /* Based on patches from Jon Smirl <jonsmirl@gmail.com> |
| 7 | * Based on patches from Jon Smirl <jonsmirl@gmail.com> | ||
| 8 | * Copyright (c) 2011 Jon Smirl <jonsmirl@gmail.com> | 7 | * Copyright (c) 2011 Jon Smirl <jonsmirl@gmail.com> |
| 9 | * | 8 | * |
| 10 | * This program is free software; you can redistribute it and/or modify | 9 | * This program is free software; you can redistribute it and/or modify |
| @@ -58,16 +57,15 @@ | |||
| 58 | #include <net/ipv6.h> | 57 | #include <net/ipv6.h> |
| 59 | #include <net/af_ieee802154.h> | 58 | #include <net/af_ieee802154.h> |
| 60 | 59 | ||
| 61 | /* | 60 | /* Uncompress address function for source and |
| 62 | * Uncompress address function for source and | ||
| 63 | * destination address(non-multicast). | 61 | * destination address(non-multicast). |
| 64 | * | 62 | * |
| 65 | * address_mode is sam value or dam value. | 63 | * address_mode is sam value or dam value. |
| 66 | */ | 64 | */ |
| 67 | static int uncompress_addr(struct sk_buff *skb, | 65 | static int uncompress_addr(struct sk_buff *skb, |
| 68 | struct in6_addr *ipaddr, const u8 address_mode, | 66 | struct in6_addr *ipaddr, const u8 address_mode, |
| 69 | const u8 *lladdr, const u8 addr_type, | 67 | const u8 *lladdr, const u8 addr_type, |
| 70 | const u8 addr_len) | 68 | const u8 addr_len) |
| 71 | { | 69 | { |
| 72 | bool fail; | 70 | bool fail; |
| 73 | 71 | ||
| @@ -140,13 +138,12 @@ static int uncompress_addr(struct sk_buff *skb, | |||
| 140 | return 0; | 138 | return 0; |
| 141 | } | 139 | } |
| 142 | 140 | ||
| 143 | /* | 141 | /* Uncompress address function for source context |
| 144 | * Uncompress address function for source context | ||
| 145 | * based address(non-multicast). | 142 | * based address(non-multicast). |
| 146 | */ | 143 | */ |
| 147 | static int uncompress_context_based_src_addr(struct sk_buff *skb, | 144 | static int uncompress_context_based_src_addr(struct sk_buff *skb, |
| 148 | struct in6_addr *ipaddr, | 145 | struct in6_addr *ipaddr, |
| 149 | const u8 sam) | 146 | const u8 sam) |
| 150 | { | 147 | { |
| 151 | switch (sam) { | 148 | switch (sam) { |
| 152 | case LOWPAN_IPHC_ADDR_00: | 149 | case LOWPAN_IPHC_ADDR_00: |
| @@ -175,13 +172,13 @@ static int uncompress_context_based_src_addr(struct sk_buff *skb, | |||
| 175 | } | 172 | } |
| 176 | 173 | ||
| 177 | static int skb_deliver(struct sk_buff *skb, struct ipv6hdr *hdr, | 174 | static int skb_deliver(struct sk_buff *skb, struct ipv6hdr *hdr, |
| 178 | struct net_device *dev, skb_delivery_cb deliver_skb) | 175 | struct net_device *dev, skb_delivery_cb deliver_skb) |
| 179 | { | 176 | { |
| 180 | struct sk_buff *new; | 177 | struct sk_buff *new; |
| 181 | int stat; | 178 | int stat; |
| 182 | 179 | ||
| 183 | new = skb_copy_expand(skb, sizeof(struct ipv6hdr), skb_tailroom(skb), | 180 | new = skb_copy_expand(skb, sizeof(struct ipv6hdr), skb_tailroom(skb), |
| 184 | GFP_ATOMIC); | 181 | GFP_ATOMIC); |
| 185 | kfree_skb(skb); | 182 | kfree_skb(skb); |
| 186 | 183 | ||
| 187 | if (!new) | 184 | if (!new) |
| @@ -196,7 +193,7 @@ static int skb_deliver(struct sk_buff *skb, struct ipv6hdr *hdr, | |||
| 196 | new->dev = dev; | 193 | new->dev = dev; |
| 197 | 194 | ||
| 198 | raw_dump_table(__func__, "raw skb data dump before receiving", | 195 | raw_dump_table(__func__, "raw skb data dump before receiving", |
| 199 | new->data, new->len); | 196 | new->data, new->len); |
| 200 | 197 | ||
| 201 | stat = deliver_skb(new, dev); | 198 | stat = deliver_skb(new, dev); |
| 202 | 199 | ||
| @@ -208,10 +205,9 @@ static int skb_deliver(struct sk_buff *skb, struct ipv6hdr *hdr, | |||
| 208 | /* Uncompress function for multicast destination address, | 205 | /* Uncompress function for multicast destination address, |
| 209 | * when M bit is set. | 206 | * when M bit is set. |
| 210 | */ | 207 | */ |
| 211 | static int | 208 | static int lowpan_uncompress_multicast_daddr(struct sk_buff *skb, |
| 212 | lowpan_uncompress_multicast_daddr(struct sk_buff *skb, | 209 | struct in6_addr *ipaddr, |
| 213 | struct in6_addr *ipaddr, | 210 | const u8 dam) |
| 214 | const u8 dam) | ||
| 215 | { | 211 | { |
| 216 | bool fail; | 212 | bool fail; |
| 217 | 213 | ||
| @@ -257,41 +253,41 @@ lowpan_uncompress_multicast_daddr(struct sk_buff *skb, | |||
| 257 | } | 253 | } |
| 258 | 254 | ||
| 259 | raw_dump_inline(NULL, "Reconstructed ipv6 multicast addr is", | 255 | raw_dump_inline(NULL, "Reconstructed ipv6 multicast addr is", |
| 260 | ipaddr->s6_addr, 16); | 256 | ipaddr->s6_addr, 16); |
| 261 | 257 | ||
| 262 | return 0; | 258 | return 0; |
| 263 | } | 259 | } |
| 264 | 260 | ||
| 265 | static int | 261 | static int uncompress_udp_header(struct sk_buff *skb, struct udphdr *uh) |
| 266 | uncompress_udp_header(struct sk_buff *skb, struct udphdr *uh) | ||
| 267 | { | 262 | { |
| 268 | bool fail; | 263 | bool fail; |
| 269 | u8 tmp = 0, val = 0; | 264 | u8 tmp = 0, val = 0; |
| 270 | 265 | ||
| 271 | if (!uh) | 266 | fail = lowpan_fetch_skb(skb, &tmp, sizeof(tmp)); |
| 272 | goto err; | ||
| 273 | |||
| 274 | fail = lowpan_fetch_skb(skb, &tmp, 1); | ||
| 275 | 267 | ||
| 276 | if ((tmp & LOWPAN_NHC_UDP_MASK) == LOWPAN_NHC_UDP_ID) { | 268 | if ((tmp & LOWPAN_NHC_UDP_MASK) == LOWPAN_NHC_UDP_ID) { |
| 277 | pr_debug("UDP header uncompression\n"); | 269 | pr_debug("UDP header uncompression\n"); |
| 278 | switch (tmp & LOWPAN_NHC_UDP_CS_P_11) { | 270 | switch (tmp & LOWPAN_NHC_UDP_CS_P_11) { |
| 279 | case LOWPAN_NHC_UDP_CS_P_00: | 271 | case LOWPAN_NHC_UDP_CS_P_00: |
| 280 | fail |= lowpan_fetch_skb(skb, &uh->source, 2); | 272 | fail |= lowpan_fetch_skb(skb, &uh->source, |
| 281 | fail |= lowpan_fetch_skb(skb, &uh->dest, 2); | 273 | sizeof(uh->source)); |
| 274 | fail |= lowpan_fetch_skb(skb, &uh->dest, | ||
| 275 | sizeof(uh->dest)); | ||
| 282 | break; | 276 | break; |
| 283 | case LOWPAN_NHC_UDP_CS_P_01: | 277 | case LOWPAN_NHC_UDP_CS_P_01: |
| 284 | fail |= lowpan_fetch_skb(skb, &uh->source, 2); | 278 | fail |= lowpan_fetch_skb(skb, &uh->source, |
| 285 | fail |= lowpan_fetch_skb(skb, &val, 1); | 279 | sizeof(uh->source)); |
| 280 | fail |= lowpan_fetch_skb(skb, &val, sizeof(val)); | ||
| 286 | uh->dest = htons(val + LOWPAN_NHC_UDP_8BIT_PORT); | 281 | uh->dest = htons(val + LOWPAN_NHC_UDP_8BIT_PORT); |
| 287 | break; | 282 | break; |
| 288 | case LOWPAN_NHC_UDP_CS_P_10: | 283 | case LOWPAN_NHC_UDP_CS_P_10: |
| 289 | fail |= lowpan_fetch_skb(skb, &val, 1); | 284 | fail |= lowpan_fetch_skb(skb, &val, sizeof(val)); |
| 290 | uh->source = htons(val + LOWPAN_NHC_UDP_8BIT_PORT); | 285 | uh->source = htons(val + LOWPAN_NHC_UDP_8BIT_PORT); |
| 291 | fail |= lowpan_fetch_skb(skb, &uh->dest, 2); | 286 | fail |= lowpan_fetch_skb(skb, &uh->dest, |
| 287 | sizeof(uh->dest)); | ||
| 292 | break; | 288 | break; |
| 293 | case LOWPAN_NHC_UDP_CS_P_11: | 289 | case LOWPAN_NHC_UDP_CS_P_11: |
| 294 | fail |= lowpan_fetch_skb(skb, &val, 1); | 290 | fail |= lowpan_fetch_skb(skb, &val, sizeof(val)); |
| 295 | uh->source = htons(LOWPAN_NHC_UDP_4BIT_PORT + | 291 | uh->source = htons(LOWPAN_NHC_UDP_4BIT_PORT + |
| 296 | (val >> 4)); | 292 | (val >> 4)); |
| 297 | uh->dest = htons(LOWPAN_NHC_UDP_4BIT_PORT + | 293 | uh->dest = htons(LOWPAN_NHC_UDP_4BIT_PORT + |
| @@ -300,7 +296,6 @@ uncompress_udp_header(struct sk_buff *skb, struct udphdr *uh) | |||
| 300 | default: | 296 | default: |
| 301 | pr_debug("ERROR: unknown UDP format\n"); | 297 | pr_debug("ERROR: unknown UDP format\n"); |
| 302 | goto err; | 298 | goto err; |
| 303 | break; | ||
| 304 | } | 299 | } |
| 305 | 300 | ||
| 306 | pr_debug("uncompressed UDP ports: src = %d, dst = %d\n", | 301 | pr_debug("uncompressed UDP ports: src = %d, dst = %d\n", |
| @@ -311,11 +306,11 @@ uncompress_udp_header(struct sk_buff *skb, struct udphdr *uh) | |||
| 311 | pr_debug_ratelimited("checksum elided currently not supported\n"); | 306 | pr_debug_ratelimited("checksum elided currently not supported\n"); |
| 312 | goto err; | 307 | goto err; |
| 313 | } else { | 308 | } else { |
| 314 | fail |= lowpan_fetch_skb(skb, &uh->check, 2); | 309 | fail |= lowpan_fetch_skb(skb, &uh->check, |
| 310 | sizeof(uh->check)); | ||
| 315 | } | 311 | } |
| 316 | 312 | ||
| 317 | /* | 313 | /* UDP length needs to be infered from the lower layers |
| 318 | * UDP lenght needs to be infered from the lower layers | ||
| 319 | * here, we obtain the hint from the remaining size of the | 314 | * here, we obtain the hint from the remaining size of the |
| 320 | * frame | 315 | * frame |
| 321 | */ | 316 | */ |
| @@ -338,21 +333,21 @@ err: | |||
| 338 | static const u8 lowpan_ttl_values[] = { 0, 1, 64, 255 }; | 333 | static const u8 lowpan_ttl_values[] = { 0, 1, 64, 255 }; |
| 339 | 334 | ||
| 340 | int lowpan_process_data(struct sk_buff *skb, struct net_device *dev, | 335 | int lowpan_process_data(struct sk_buff *skb, struct net_device *dev, |
| 341 | const u8 *saddr, const u8 saddr_type, const u8 saddr_len, | 336 | const u8 *saddr, const u8 saddr_type, const u8 saddr_len, |
| 342 | const u8 *daddr, const u8 daddr_type, const u8 daddr_len, | 337 | const u8 *daddr, const u8 daddr_type, const u8 daddr_len, |
| 343 | u8 iphc0, u8 iphc1, skb_delivery_cb deliver_skb) | 338 | u8 iphc0, u8 iphc1, skb_delivery_cb deliver_skb) |
| 344 | { | 339 | { |
| 345 | struct ipv6hdr hdr = {}; | 340 | struct ipv6hdr hdr = {}; |
| 346 | u8 tmp, num_context = 0; | 341 | u8 tmp, num_context = 0; |
| 347 | int err; | 342 | int err; |
| 348 | 343 | ||
| 349 | raw_dump_table(__func__, "raw skb data dump uncompressed", | 344 | raw_dump_table(__func__, "raw skb data dump uncompressed", |
| 350 | skb->data, skb->len); | 345 | skb->data, skb->len); |
| 351 | 346 | ||
| 352 | /* another if the CID flag is set */ | 347 | /* another if the CID flag is set */ |
| 353 | if (iphc1 & LOWPAN_IPHC_CID) { | 348 | if (iphc1 & LOWPAN_IPHC_CID) { |
| 354 | pr_debug("CID flag is set, increase header with one\n"); | 349 | pr_debug("CID flag is set, increase header with one\n"); |
| 355 | if (lowpan_fetch_skb_u8(skb, &num_context)) | 350 | if (lowpan_fetch_skb(skb, &num_context, sizeof(num_context))) |
| 356 | goto drop; | 351 | goto drop; |
| 357 | } | 352 | } |
| 358 | 353 | ||
| @@ -360,12 +355,11 @@ int lowpan_process_data(struct sk_buff *skb, struct net_device *dev, | |||
| 360 | 355 | ||
| 361 | /* Traffic Class and Flow Label */ | 356 | /* Traffic Class and Flow Label */ |
| 362 | switch ((iphc0 & LOWPAN_IPHC_TF) >> 3) { | 357 | switch ((iphc0 & LOWPAN_IPHC_TF) >> 3) { |
| 363 | /* | 358 | /* Traffic Class and FLow Label carried in-line |
| 364 | * Traffic Class and FLow Label carried in-line | ||
| 365 | * ECN + DSCP + 4-bit Pad + Flow Label (4 bytes) | 359 | * ECN + DSCP + 4-bit Pad + Flow Label (4 bytes) |
| 366 | */ | 360 | */ |
| 367 | case 0: /* 00b */ | 361 | case 0: /* 00b */ |
| 368 | if (lowpan_fetch_skb_u8(skb, &tmp)) | 362 | if (lowpan_fetch_skb(skb, &tmp, sizeof(tmp))) |
| 369 | goto drop; | 363 | goto drop; |
| 370 | 364 | ||
| 371 | memcpy(&hdr.flow_lbl, &skb->data[0], 3); | 365 | memcpy(&hdr.flow_lbl, &skb->data[0], 3); |
| @@ -374,23 +368,21 @@ int lowpan_process_data(struct sk_buff *skb, struct net_device *dev, | |||
| 374 | hdr.flow_lbl[0] = ((tmp >> 2) & 0x30) | (tmp << 6) | | 368 | hdr.flow_lbl[0] = ((tmp >> 2) & 0x30) | (tmp << 6) | |
| 375 | (hdr.flow_lbl[0] & 0x0f); | 369 | (hdr.flow_lbl[0] & 0x0f); |
| 376 | break; | 370 | break; |
| 377 | /* | 371 | /* Traffic class carried in-line |
| 378 | * Traffic class carried in-line | ||
| 379 | * ECN + DSCP (1 byte), Flow Label is elided | 372 | * ECN + DSCP (1 byte), Flow Label is elided |
| 380 | */ | 373 | */ |
| 381 | case 2: /* 10b */ | 374 | case 2: /* 10b */ |
| 382 | if (lowpan_fetch_skb_u8(skb, &tmp)) | 375 | if (lowpan_fetch_skb(skb, &tmp, sizeof(tmp))) |
| 383 | goto drop; | 376 | goto drop; |
| 384 | 377 | ||
| 385 | hdr.priority = ((tmp >> 2) & 0x0f); | 378 | hdr.priority = ((tmp >> 2) & 0x0f); |
| 386 | hdr.flow_lbl[0] = ((tmp << 6) & 0xC0) | ((tmp >> 2) & 0x30); | 379 | hdr.flow_lbl[0] = ((tmp << 6) & 0xC0) | ((tmp >> 2) & 0x30); |
| 387 | break; | 380 | break; |
| 388 | /* | 381 | /* Flow Label carried in-line |
| 389 | * Flow Label carried in-line | ||
| 390 | * ECN + 2-bit Pad + Flow Label (3 bytes), DSCP is elided | 382 | * ECN + 2-bit Pad + Flow Label (3 bytes), DSCP is elided |
| 391 | */ | 383 | */ |
| 392 | case 1: /* 01b */ | 384 | case 1: /* 01b */ |
| 393 | if (lowpan_fetch_skb_u8(skb, &tmp)) | 385 | if (lowpan_fetch_skb(skb, &tmp, sizeof(tmp))) |
| 394 | goto drop; | 386 | goto drop; |
| 395 | 387 | ||
| 396 | hdr.flow_lbl[0] = (skb->data[0] & 0x0F) | ((tmp >> 2) & 0x30); | 388 | hdr.flow_lbl[0] = (skb->data[0] & 0x0F) | ((tmp >> 2) & 0x30); |
| @@ -407,7 +399,7 @@ int lowpan_process_data(struct sk_buff *skb, struct net_device *dev, | |||
| 407 | /* Next Header */ | 399 | /* Next Header */ |
| 408 | if ((iphc0 & LOWPAN_IPHC_NH_C) == 0) { | 400 | if ((iphc0 & LOWPAN_IPHC_NH_C) == 0) { |
| 409 | /* Next header is carried inline */ | 401 | /* Next header is carried inline */ |
| 410 | if (lowpan_fetch_skb_u8(skb, &(hdr.nexthdr))) | 402 | if (lowpan_fetch_skb(skb, &hdr.nexthdr, sizeof(hdr.nexthdr))) |
| 411 | goto drop; | 403 | goto drop; |
| 412 | 404 | ||
| 413 | pr_debug("NH flag is set, next header carried inline: %02x\n", | 405 | pr_debug("NH flag is set, next header carried inline: %02x\n", |
| @@ -415,10 +407,11 @@ int lowpan_process_data(struct sk_buff *skb, struct net_device *dev, | |||
| 415 | } | 407 | } |
| 416 | 408 | ||
| 417 | /* Hop Limit */ | 409 | /* Hop Limit */ |
| 418 | if ((iphc0 & 0x03) != LOWPAN_IPHC_TTL_I) | 410 | if ((iphc0 & 0x03) != LOWPAN_IPHC_TTL_I) { |
| 419 | hdr.hop_limit = lowpan_ttl_values[iphc0 & 0x03]; | 411 | hdr.hop_limit = lowpan_ttl_values[iphc0 & 0x03]; |
| 420 | else { | 412 | } else { |
| 421 | if (lowpan_fetch_skb_u8(skb, &(hdr.hop_limit))) | 413 | if (lowpan_fetch_skb(skb, &hdr.hop_limit, |
| 414 | sizeof(hdr.hop_limit))) | ||
| 422 | goto drop; | 415 | goto drop; |
| 423 | } | 416 | } |
| 424 | 417 | ||
| @@ -428,13 +421,12 @@ int lowpan_process_data(struct sk_buff *skb, struct net_device *dev, | |||
| 428 | if (iphc1 & LOWPAN_IPHC_SAC) { | 421 | if (iphc1 & LOWPAN_IPHC_SAC) { |
| 429 | /* Source address context based uncompression */ | 422 | /* Source address context based uncompression */ |
| 430 | pr_debug("SAC bit is set. Handle context based source address.\n"); | 423 | pr_debug("SAC bit is set. Handle context based source address.\n"); |
| 431 | err = uncompress_context_based_src_addr( | 424 | err = uncompress_context_based_src_addr(skb, &hdr.saddr, tmp); |
| 432 | skb, &hdr.saddr, tmp); | ||
| 433 | } else { | 425 | } else { |
| 434 | /* Source address uncompression */ | 426 | /* Source address uncompression */ |
| 435 | pr_debug("source address stateless compression\n"); | 427 | pr_debug("source address stateless compression\n"); |
| 436 | err = uncompress_addr(skb, &hdr.saddr, tmp, saddr, | 428 | err = uncompress_addr(skb, &hdr.saddr, tmp, saddr, |
| 437 | saddr_type, saddr_len); | 429 | saddr_type, saddr_len); |
| 438 | } | 430 | } |
| 439 | 431 | ||
| 440 | /* Check on error of previous branch */ | 432 | /* Check on error of previous branch */ |
| @@ -450,16 +442,17 @@ int lowpan_process_data(struct sk_buff *skb, struct net_device *dev, | |||
| 450 | pr_debug("dest: context-based mcast compression\n"); | 442 | pr_debug("dest: context-based mcast compression\n"); |
| 451 | /* TODO: implement this */ | 443 | /* TODO: implement this */ |
| 452 | } else { | 444 | } else { |
| 453 | err = lowpan_uncompress_multicast_daddr( | 445 | err = lowpan_uncompress_multicast_daddr(skb, &hdr.daddr, |
| 454 | skb, &hdr.daddr, tmp); | 446 | tmp); |
| 447 | |||
| 455 | if (err) | 448 | if (err) |
| 456 | goto drop; | 449 | goto drop; |
| 457 | } | 450 | } |
| 458 | } else { | 451 | } else { |
| 459 | err = uncompress_addr(skb, &hdr.daddr, tmp, daddr, | 452 | err = uncompress_addr(skb, &hdr.daddr, tmp, daddr, |
| 460 | daddr_type, daddr_len); | 453 | daddr_type, daddr_len); |
| 461 | pr_debug("dest: stateless compression mode %d dest %pI6c\n", | 454 | pr_debug("dest: stateless compression mode %d dest %pI6c\n", |
| 462 | tmp, &hdr.daddr); | 455 | tmp, &hdr.daddr); |
| 463 | if (err) | 456 | if (err) |
| 464 | goto drop; | 457 | goto drop; |
| 465 | } | 458 | } |
| @@ -468,11 +461,11 @@ int lowpan_process_data(struct sk_buff *skb, struct net_device *dev, | |||
| 468 | if (iphc0 & LOWPAN_IPHC_NH_C) { | 461 | if (iphc0 & LOWPAN_IPHC_NH_C) { |
| 469 | struct udphdr uh; | 462 | struct udphdr uh; |
| 470 | struct sk_buff *new; | 463 | struct sk_buff *new; |
| 464 | |||
| 471 | if (uncompress_udp_header(skb, &uh)) | 465 | if (uncompress_udp_header(skb, &uh)) |
| 472 | goto drop; | 466 | goto drop; |
| 473 | 467 | ||
| 474 | /* | 468 | /* replace the compressed UDP head by the uncompressed UDP |
| 475 | * replace the compressed UDP head by the uncompressed UDP | ||
| 476 | * header | 469 | * header |
| 477 | */ | 470 | */ |
| 478 | new = skb_copy_expand(skb, sizeof(struct udphdr), | 471 | new = skb_copy_expand(skb, sizeof(struct udphdr), |
| @@ -489,7 +482,7 @@ int lowpan_process_data(struct sk_buff *skb, struct net_device *dev, | |||
| 489 | skb_copy_to_linear_data(skb, &uh, sizeof(struct udphdr)); | 482 | skb_copy_to_linear_data(skb, &uh, sizeof(struct udphdr)); |
| 490 | 483 | ||
| 491 | raw_dump_table(__func__, "raw UDP header dump", | 484 | raw_dump_table(__func__, "raw UDP header dump", |
| 492 | (u8 *)&uh, sizeof(uh)); | 485 | (u8 *)&uh, sizeof(uh)); |
| 493 | 486 | ||
| 494 | hdr.nexthdr = UIP_PROTO_UDP; | 487 | hdr.nexthdr = UIP_PROTO_UDP; |
| 495 | } | 488 | } |
| @@ -504,8 +497,7 @@ int lowpan_process_data(struct sk_buff *skb, struct net_device *dev, | |||
| 504 | hdr.version, ntohs(hdr.payload_len), hdr.nexthdr, | 497 | hdr.version, ntohs(hdr.payload_len), hdr.nexthdr, |
| 505 | hdr.hop_limit, &hdr.daddr); | 498 | hdr.hop_limit, &hdr.daddr); |
| 506 | 499 | ||
| 507 | raw_dump_table(__func__, "raw header dump", (u8 *)&hdr, | 500 | raw_dump_table(__func__, "raw header dump", (u8 *)&hdr, sizeof(hdr)); |
| 508 | sizeof(hdr)); | ||
| 509 | 501 | ||
| 510 | return skb_deliver(skb, &hdr, dev, deliver_skb); | 502 | return skb_deliver(skb, &hdr, dev, deliver_skb); |
| 511 | 503 | ||
| @@ -515,9 +507,9 @@ drop: | |||
| 515 | } | 507 | } |
| 516 | EXPORT_SYMBOL_GPL(lowpan_process_data); | 508 | EXPORT_SYMBOL_GPL(lowpan_process_data); |
| 517 | 509 | ||
| 518 | static u8 lowpan_compress_addr_64(u8 **hc06_ptr, u8 shift, | 510 | static u8 lowpan_compress_addr_64(u8 **hc_ptr, u8 shift, |
| 519 | const struct in6_addr *ipaddr, | 511 | const struct in6_addr *ipaddr, |
| 520 | const unsigned char *lladdr) | 512 | const unsigned char *lladdr) |
| 521 | { | 513 | { |
| 522 | u8 val = 0; | 514 | u8 val = 0; |
| 523 | 515 | ||
| @@ -526,24 +518,22 @@ static u8 lowpan_compress_addr_64(u8 **hc06_ptr, u8 shift, | |||
| 526 | pr_debug("address compression 0 bits\n"); | 518 | pr_debug("address compression 0 bits\n"); |
| 527 | } else if (lowpan_is_iid_16_bit_compressable(ipaddr)) { | 519 | } else if (lowpan_is_iid_16_bit_compressable(ipaddr)) { |
| 528 | /* compress IID to 16 bits xxxx::XXXX */ | 520 | /* compress IID to 16 bits xxxx::XXXX */ |
| 529 | memcpy(*hc06_ptr, &ipaddr->s6_addr16[7], 2); | 521 | lowpan_push_hc_data(hc_ptr, &ipaddr->s6_addr16[7], 2); |
| 530 | *hc06_ptr += 2; | ||
| 531 | val = 2; /* 16-bits */ | 522 | val = 2; /* 16-bits */ |
| 532 | raw_dump_inline(NULL, "Compressed ipv6 addr is (16 bits)", | 523 | raw_dump_inline(NULL, "Compressed ipv6 addr is (16 bits)", |
| 533 | *hc06_ptr - 2, 2); | 524 | *hc_ptr - 2, 2); |
| 534 | } else { | 525 | } else { |
| 535 | /* do not compress IID => xxxx::IID */ | 526 | /* do not compress IID => xxxx::IID */ |
| 536 | memcpy(*hc06_ptr, &ipaddr->s6_addr16[4], 8); | 527 | lowpan_push_hc_data(hc_ptr, &ipaddr->s6_addr16[4], 8); |
| 537 | *hc06_ptr += 8; | ||
| 538 | val = 1; /* 64-bits */ | 528 | val = 1; /* 64-bits */ |
| 539 | raw_dump_inline(NULL, "Compressed ipv6 addr is (64 bits)", | 529 | raw_dump_inline(NULL, "Compressed ipv6 addr is (64 bits)", |
| 540 | *hc06_ptr - 8, 8); | 530 | *hc_ptr - 8, 8); |
| 541 | } | 531 | } |
| 542 | 532 | ||
| 543 | return rol8(val, shift); | 533 | return rol8(val, shift); |
| 544 | } | 534 | } |
| 545 | 535 | ||
| 546 | static void compress_udp_header(u8 **hc06_ptr, struct sk_buff *skb) | 536 | static void compress_udp_header(u8 **hc_ptr, struct sk_buff *skb) |
| 547 | { | 537 | { |
| 548 | struct udphdr *uh = udp_hdr(skb); | 538 | struct udphdr *uh = udp_hdr(skb); |
| 549 | u8 tmp; | 539 | u8 tmp; |
| @@ -555,75 +545,75 @@ static void compress_udp_header(u8 **hc06_ptr, struct sk_buff *skb) | |||
| 555 | pr_debug("UDP header: both ports compression to 4 bits\n"); | 545 | pr_debug("UDP header: both ports compression to 4 bits\n"); |
| 556 | /* compression value */ | 546 | /* compression value */ |
| 557 | tmp = LOWPAN_NHC_UDP_CS_P_11; | 547 | tmp = LOWPAN_NHC_UDP_CS_P_11; |
| 558 | lowpan_push_hc_data(hc06_ptr, &tmp, sizeof(tmp)); | 548 | lowpan_push_hc_data(hc_ptr, &tmp, sizeof(tmp)); |
| 559 | /* source and destination port */ | 549 | /* source and destination port */ |
| 560 | tmp = ntohs(uh->dest) - LOWPAN_NHC_UDP_4BIT_PORT + | 550 | tmp = ntohs(uh->dest) - LOWPAN_NHC_UDP_4BIT_PORT + |
| 561 | ((ntohs(uh->source) - LOWPAN_NHC_UDP_4BIT_PORT) << 4); | 551 | ((ntohs(uh->source) - LOWPAN_NHC_UDP_4BIT_PORT) << 4); |
| 562 | lowpan_push_hc_data(hc06_ptr, &tmp, sizeof(tmp)); | 552 | lowpan_push_hc_data(hc_ptr, &tmp, sizeof(tmp)); |
| 563 | } else if ((ntohs(uh->dest) & LOWPAN_NHC_UDP_8BIT_MASK) == | 553 | } else if ((ntohs(uh->dest) & LOWPAN_NHC_UDP_8BIT_MASK) == |
| 564 | LOWPAN_NHC_UDP_8BIT_PORT) { | 554 | LOWPAN_NHC_UDP_8BIT_PORT) { |
| 565 | pr_debug("UDP header: remove 8 bits of dest\n"); | 555 | pr_debug("UDP header: remove 8 bits of dest\n"); |
| 566 | /* compression value */ | 556 | /* compression value */ |
| 567 | tmp = LOWPAN_NHC_UDP_CS_P_01; | 557 | tmp = LOWPAN_NHC_UDP_CS_P_01; |
| 568 | lowpan_push_hc_data(hc06_ptr, &tmp, sizeof(tmp)); | 558 | lowpan_push_hc_data(hc_ptr, &tmp, sizeof(tmp)); |
| 569 | /* source port */ | 559 | /* source port */ |
| 570 | lowpan_push_hc_data(hc06_ptr, &uh->source, sizeof(uh->source)); | 560 | lowpan_push_hc_data(hc_ptr, &uh->source, sizeof(uh->source)); |
| 571 | /* destination port */ | 561 | /* destination port */ |
| 572 | tmp = ntohs(uh->dest) - LOWPAN_NHC_UDP_8BIT_PORT; | 562 | tmp = ntohs(uh->dest) - LOWPAN_NHC_UDP_8BIT_PORT; |
| 573 | lowpan_push_hc_data(hc06_ptr, &tmp, sizeof(tmp)); | 563 | lowpan_push_hc_data(hc_ptr, &tmp, sizeof(tmp)); |
| 574 | } else if ((ntohs(uh->source) & LOWPAN_NHC_UDP_8BIT_MASK) == | 564 | } else if ((ntohs(uh->source) & LOWPAN_NHC_UDP_8BIT_MASK) == |
| 575 | LOWPAN_NHC_UDP_8BIT_PORT) { | 565 | LOWPAN_NHC_UDP_8BIT_PORT) { |
| 576 | pr_debug("UDP header: remove 8 bits of source\n"); | 566 | pr_debug("UDP header: remove 8 bits of source\n"); |
| 577 | /* compression value */ | 567 | /* compression value */ |
| 578 | tmp = LOWPAN_NHC_UDP_CS_P_10; | 568 | tmp = LOWPAN_NHC_UDP_CS_P_10; |
| 579 | lowpan_push_hc_data(hc06_ptr, &tmp, sizeof(tmp)); | 569 | lowpan_push_hc_data(hc_ptr, &tmp, sizeof(tmp)); |
| 580 | /* source port */ | 570 | /* source port */ |
| 581 | tmp = ntohs(uh->source) - LOWPAN_NHC_UDP_8BIT_PORT; | 571 | tmp = ntohs(uh->source) - LOWPAN_NHC_UDP_8BIT_PORT; |
| 582 | lowpan_push_hc_data(hc06_ptr, &tmp, sizeof(tmp)); | 572 | lowpan_push_hc_data(hc_ptr, &tmp, sizeof(tmp)); |
| 583 | /* destination port */ | 573 | /* destination port */ |
| 584 | lowpan_push_hc_data(hc06_ptr, &uh->dest, sizeof(uh->dest)); | 574 | lowpan_push_hc_data(hc_ptr, &uh->dest, sizeof(uh->dest)); |
| 585 | } else { | 575 | } else { |
| 586 | pr_debug("UDP header: can't compress\n"); | 576 | pr_debug("UDP header: can't compress\n"); |
| 587 | /* compression value */ | 577 | /* compression value */ |
| 588 | tmp = LOWPAN_NHC_UDP_CS_P_00; | 578 | tmp = LOWPAN_NHC_UDP_CS_P_00; |
| 589 | lowpan_push_hc_data(hc06_ptr, &tmp, sizeof(tmp)); | 579 | lowpan_push_hc_data(hc_ptr, &tmp, sizeof(tmp)); |
| 590 | /* source port */ | 580 | /* source port */ |
| 591 | lowpan_push_hc_data(hc06_ptr, &uh->source, sizeof(uh->source)); | 581 | lowpan_push_hc_data(hc_ptr, &uh->source, sizeof(uh->source)); |
| 592 | /* destination port */ | 582 | /* destination port */ |
| 593 | lowpan_push_hc_data(hc06_ptr, &uh->dest, sizeof(uh->dest)); | 583 | lowpan_push_hc_data(hc_ptr, &uh->dest, sizeof(uh->dest)); |
| 594 | } | 584 | } |
| 595 | 585 | ||
| 596 | /* checksum is always inline */ | 586 | /* checksum is always inline */ |
| 597 | lowpan_push_hc_data(hc06_ptr, &uh->check, sizeof(uh->check)); | 587 | lowpan_push_hc_data(hc_ptr, &uh->check, sizeof(uh->check)); |
| 598 | 588 | ||
| 599 | /* skip the UDP header */ | 589 | /* skip the UDP header */ |
| 600 | skb_pull(skb, sizeof(struct udphdr)); | 590 | skb_pull(skb, sizeof(struct udphdr)); |
| 601 | } | 591 | } |
| 602 | 592 | ||
| 603 | int lowpan_header_compress(struct sk_buff *skb, struct net_device *dev, | 593 | int lowpan_header_compress(struct sk_buff *skb, struct net_device *dev, |
| 604 | unsigned short type, const void *_daddr, | 594 | unsigned short type, const void *_daddr, |
| 605 | const void *_saddr, unsigned int len) | 595 | const void *_saddr, unsigned int len) |
| 606 | { | 596 | { |
| 607 | u8 tmp, iphc0, iphc1, *hc06_ptr; | 597 | u8 tmp, iphc0, iphc1, *hc_ptr; |
| 608 | struct ipv6hdr *hdr; | 598 | struct ipv6hdr *hdr; |
| 609 | u8 head[100] = {}; | 599 | u8 head[100] = {}; |
| 600 | int addr_type; | ||
| 610 | 601 | ||
| 611 | if (type != ETH_P_IPV6) | 602 | if (type != ETH_P_IPV6) |
| 612 | return -EINVAL; | 603 | return -EINVAL; |
| 613 | 604 | ||
| 614 | hdr = ipv6_hdr(skb); | 605 | hdr = ipv6_hdr(skb); |
| 615 | hc06_ptr = head + 2; | 606 | hc_ptr = head + 2; |
| 616 | 607 | ||
| 617 | pr_debug("IPv6 header dump:\n\tversion = %d\n\tlength = %d\n" | 608 | pr_debug("IPv6 header dump:\n\tversion = %d\n\tlength = %d\n" |
| 618 | "\tnexthdr = 0x%02x\n\thop_lim = %d\n\tdest = %pI6c\n", | 609 | "\tnexthdr = 0x%02x\n\thop_lim = %d\n\tdest = %pI6c\n", |
| 619 | hdr->version, ntohs(hdr->payload_len), hdr->nexthdr, | 610 | hdr->version, ntohs(hdr->payload_len), hdr->nexthdr, |
| 620 | hdr->hop_limit, &hdr->daddr); | 611 | hdr->hop_limit, &hdr->daddr); |
| 621 | 612 | ||
| 622 | raw_dump_table(__func__, "raw skb network header dump", | 613 | raw_dump_table(__func__, "raw skb network header dump", |
| 623 | skb_network_header(skb), sizeof(struct ipv6hdr)); | 614 | skb_network_header(skb), sizeof(struct ipv6hdr)); |
| 624 | 615 | ||
| 625 | /* | 616 | /* As we copy some bit-length fields, in the IPHC encoding bytes, |
| 626 | * As we copy some bit-length fields, in the IPHC encoding bytes, | ||
| 627 | * we sometimes use |= | 617 | * we sometimes use |= |
| 628 | * If the field is 0, and the current bit value in memory is 1, | 618 | * If the field is 0, and the current bit value in memory is 1, |
| 629 | * this does not work. We therefore reset the IPHC encoding here | 619 | * this does not work. We therefore reset the IPHC encoding here |
| @@ -638,49 +628,47 @@ int lowpan_header_compress(struct sk_buff *skb, struct net_device *dev, | |||
| 638 | raw_dump_inline(__func__, "daddr", | 628 | raw_dump_inline(__func__, "daddr", |
| 639 | (unsigned char *)_daddr, IEEE802154_ADDR_LEN); | 629 | (unsigned char *)_daddr, IEEE802154_ADDR_LEN); |
| 640 | 630 | ||
| 641 | raw_dump_table(__func__, | 631 | raw_dump_table(__func__, "sending raw skb network uncompressed packet", |
| 642 | "sending raw skb network uncompressed packet", | 632 | skb->data, skb->len); |
| 643 | skb->data, skb->len); | ||
| 644 | 633 | ||
| 645 | /* | 634 | /* Traffic class, flow label |
| 646 | * Traffic class, flow label | ||
| 647 | * If flow label is 0, compress it. If traffic class is 0, compress it | 635 | * If flow label is 0, compress it. If traffic class is 0, compress it |
| 648 | * We have to process both in the same time as the offset of traffic | 636 | * We have to process both in the same time as the offset of traffic |
| 649 | * class depends on the presence of version and flow label | 637 | * class depends on the presence of version and flow label |
| 650 | */ | 638 | */ |
| 651 | 639 | ||
| 652 | /* hc06 format of TC is ECN | DSCP , original one is DSCP | ECN */ | 640 | /* hc format of TC is ECN | DSCP , original one is DSCP | ECN */ |
| 653 | tmp = (hdr->priority << 4) | (hdr->flow_lbl[0] >> 4); | 641 | tmp = (hdr->priority << 4) | (hdr->flow_lbl[0] >> 4); |
| 654 | tmp = ((tmp & 0x03) << 6) | (tmp >> 2); | 642 | tmp = ((tmp & 0x03) << 6) | (tmp >> 2); |
| 655 | 643 | ||
| 656 | if (((hdr->flow_lbl[0] & 0x0F) == 0) && | 644 | if (((hdr->flow_lbl[0] & 0x0F) == 0) && |
| 657 | (hdr->flow_lbl[1] == 0) && (hdr->flow_lbl[2] == 0)) { | 645 | (hdr->flow_lbl[1] == 0) && (hdr->flow_lbl[2] == 0)) { |
| 658 | /* flow label can be compressed */ | 646 | /* flow label can be compressed */ |
| 659 | iphc0 |= LOWPAN_IPHC_FL_C; | 647 | iphc0 |= LOWPAN_IPHC_FL_C; |
| 660 | if ((hdr->priority == 0) && | 648 | if ((hdr->priority == 0) && |
| 661 | ((hdr->flow_lbl[0] & 0xF0) == 0)) { | 649 | ((hdr->flow_lbl[0] & 0xF0) == 0)) { |
| 662 | /* compress (elide) all */ | 650 | /* compress (elide) all */ |
| 663 | iphc0 |= LOWPAN_IPHC_TC_C; | 651 | iphc0 |= LOWPAN_IPHC_TC_C; |
| 664 | } else { | 652 | } else { |
| 665 | /* compress only the flow label */ | 653 | /* compress only the flow label */ |
| 666 | *hc06_ptr = tmp; | 654 | *hc_ptr = tmp; |
| 667 | hc06_ptr += 1; | 655 | hc_ptr += 1; |
| 668 | } | 656 | } |
| 669 | } else { | 657 | } else { |
| 670 | /* Flow label cannot be compressed */ | 658 | /* Flow label cannot be compressed */ |
| 671 | if ((hdr->priority == 0) && | 659 | if ((hdr->priority == 0) && |
| 672 | ((hdr->flow_lbl[0] & 0xF0) == 0)) { | 660 | ((hdr->flow_lbl[0] & 0xF0) == 0)) { |
| 673 | /* compress only traffic class */ | 661 | /* compress only traffic class */ |
| 674 | iphc0 |= LOWPAN_IPHC_TC_C; | 662 | iphc0 |= LOWPAN_IPHC_TC_C; |
| 675 | *hc06_ptr = (tmp & 0xc0) | (hdr->flow_lbl[0] & 0x0F); | 663 | *hc_ptr = (tmp & 0xc0) | (hdr->flow_lbl[0] & 0x0F); |
| 676 | memcpy(hc06_ptr + 1, &hdr->flow_lbl[1], 2); | 664 | memcpy(hc_ptr + 1, &hdr->flow_lbl[1], 2); |
| 677 | hc06_ptr += 3; | 665 | hc_ptr += 3; |
| 678 | } else { | 666 | } else { |
| 679 | /* compress nothing */ | 667 | /* compress nothing */ |
| 680 | memcpy(hc06_ptr, hdr, 4); | 668 | memcpy(hc_ptr, hdr, 4); |
| 681 | /* replace the top byte with new ECN | DSCP format */ | 669 | /* replace the top byte with new ECN | DSCP format */ |
| 682 | *hc06_ptr = tmp; | 670 | *hc_ptr = tmp; |
| 683 | hc06_ptr += 4; | 671 | hc_ptr += 4; |
| 684 | } | 672 | } |
| 685 | } | 673 | } |
| 686 | 674 | ||
| @@ -690,13 +678,11 @@ int lowpan_header_compress(struct sk_buff *skb, struct net_device *dev, | |||
| 690 | if (hdr->nexthdr == UIP_PROTO_UDP) | 678 | if (hdr->nexthdr == UIP_PROTO_UDP) |
| 691 | iphc0 |= LOWPAN_IPHC_NH_C; | 679 | iphc0 |= LOWPAN_IPHC_NH_C; |
| 692 | 680 | ||
| 693 | if ((iphc0 & LOWPAN_IPHC_NH_C) == 0) { | 681 | if ((iphc0 & LOWPAN_IPHC_NH_C) == 0) |
| 694 | *hc06_ptr = hdr->nexthdr; | 682 | lowpan_push_hc_data(&hc_ptr, &hdr->nexthdr, |
| 695 | hc06_ptr += 1; | 683 | sizeof(hdr->nexthdr)); |
| 696 | } | ||
| 697 | 684 | ||
| 698 | /* | 685 | /* Hop limit |
| 699 | * Hop limit | ||
| 700 | * if 1: compress, encoding is 01 | 686 | * if 1: compress, encoding is 01 |
| 701 | * if 64: compress, encoding is 10 | 687 | * if 64: compress, encoding is 10 |
| 702 | * if 255: compress, encoding is 11 | 688 | * if 255: compress, encoding is 11 |
| @@ -713,87 +699,89 @@ int lowpan_header_compress(struct sk_buff *skb, struct net_device *dev, | |||
| 713 | iphc0 |= LOWPAN_IPHC_TTL_255; | 699 | iphc0 |= LOWPAN_IPHC_TTL_255; |
| 714 | break; | 700 | break; |
| 715 | default: | 701 | default: |
| 716 | *hc06_ptr = hdr->hop_limit; | 702 | lowpan_push_hc_data(&hc_ptr, &hdr->hop_limit, |
| 717 | hc06_ptr += 1; | 703 | sizeof(hdr->hop_limit)); |
| 718 | break; | ||
| 719 | } | 704 | } |
| 720 | 705 | ||
| 706 | addr_type = ipv6_addr_type(&hdr->saddr); | ||
| 721 | /* source address compression */ | 707 | /* source address compression */ |
| 722 | if (is_addr_unspecified(&hdr->saddr)) { | 708 | if (addr_type == IPV6_ADDR_ANY) { |
| 723 | pr_debug("source address is unspecified, setting SAC\n"); | 709 | pr_debug("source address is unspecified, setting SAC\n"); |
| 724 | iphc1 |= LOWPAN_IPHC_SAC; | 710 | iphc1 |= LOWPAN_IPHC_SAC; |
| 725 | /* TODO: context lookup */ | ||
| 726 | } else if (is_addr_link_local(&hdr->saddr)) { | ||
| 727 | iphc1 |= lowpan_compress_addr_64(&hc06_ptr, | ||
| 728 | LOWPAN_IPHC_SAM_BIT, &hdr->saddr, _saddr); | ||
| 729 | pr_debug("source address unicast link-local %pI6c " | ||
| 730 | "iphc1 0x%02x\n", &hdr->saddr, iphc1); | ||
| 731 | } else { | 711 | } else { |
| 732 | pr_debug("send the full source address\n"); | 712 | if (addr_type & IPV6_ADDR_LINKLOCAL) { |
| 733 | memcpy(hc06_ptr, &hdr->saddr.s6_addr16[0], 16); | 713 | iphc1 |= lowpan_compress_addr_64(&hc_ptr, |
| 734 | hc06_ptr += 16; | 714 | LOWPAN_IPHC_SAM_BIT, |
| 715 | &hdr->saddr, _saddr); | ||
| 716 | pr_debug("source address unicast link-local %pI6c iphc1 0x%02x\n", | ||
| 717 | &hdr->saddr, iphc1); | ||
| 718 | } else { | ||
| 719 | pr_debug("send the full source address\n"); | ||
| 720 | lowpan_push_hc_data(&hc_ptr, hdr->saddr.s6_addr, 16); | ||
| 721 | } | ||
| 735 | } | 722 | } |
| 736 | 723 | ||
| 724 | addr_type = ipv6_addr_type(&hdr->daddr); | ||
| 737 | /* destination address compression */ | 725 | /* destination address compression */ |
| 738 | if (is_addr_mcast(&hdr->daddr)) { | 726 | if (addr_type & IPV6_ADDR_MULTICAST) { |
| 739 | pr_debug("destination address is multicast: "); | 727 | pr_debug("destination address is multicast: "); |
| 740 | iphc1 |= LOWPAN_IPHC_M; | 728 | iphc1 |= LOWPAN_IPHC_M; |
| 741 | if (lowpan_is_mcast_addr_compressable8(&hdr->daddr)) { | 729 | if (lowpan_is_mcast_addr_compressable8(&hdr->daddr)) { |
| 742 | pr_debug("compressed to 1 octet\n"); | 730 | pr_debug("compressed to 1 octet\n"); |
| 743 | iphc1 |= LOWPAN_IPHC_DAM_11; | 731 | iphc1 |= LOWPAN_IPHC_DAM_11; |
| 744 | /* use last byte */ | 732 | /* use last byte */ |
| 745 | *hc06_ptr = hdr->daddr.s6_addr[15]; | 733 | lowpan_push_hc_data(&hc_ptr, |
| 746 | hc06_ptr += 1; | 734 | &hdr->daddr.s6_addr[15], 1); |
| 747 | } else if (lowpan_is_mcast_addr_compressable32(&hdr->daddr)) { | 735 | } else if (lowpan_is_mcast_addr_compressable32(&hdr->daddr)) { |
| 748 | pr_debug("compressed to 4 octets\n"); | 736 | pr_debug("compressed to 4 octets\n"); |
| 749 | iphc1 |= LOWPAN_IPHC_DAM_10; | 737 | iphc1 |= LOWPAN_IPHC_DAM_10; |
| 750 | /* second byte + the last three */ | 738 | /* second byte + the last three */ |
| 751 | *hc06_ptr = hdr->daddr.s6_addr[1]; | 739 | lowpan_push_hc_data(&hc_ptr, |
| 752 | memcpy(hc06_ptr + 1, &hdr->daddr.s6_addr[13], 3); | 740 | &hdr->daddr.s6_addr[1], 1); |
| 753 | hc06_ptr += 4; | 741 | lowpan_push_hc_data(&hc_ptr, |
| 742 | &hdr->daddr.s6_addr[13], 3); | ||
| 754 | } else if (lowpan_is_mcast_addr_compressable48(&hdr->daddr)) { | 743 | } else if (lowpan_is_mcast_addr_compressable48(&hdr->daddr)) { |
| 755 | pr_debug("compressed to 6 octets\n"); | 744 | pr_debug("compressed to 6 octets\n"); |
| 756 | iphc1 |= LOWPAN_IPHC_DAM_01; | 745 | iphc1 |= LOWPAN_IPHC_DAM_01; |
| 757 | /* second byte + the last five */ | 746 | /* second byte + the last five */ |
| 758 | *hc06_ptr = hdr->daddr.s6_addr[1]; | 747 | lowpan_push_hc_data(&hc_ptr, |
| 759 | memcpy(hc06_ptr + 1, &hdr->daddr.s6_addr[11], 5); | 748 | &hdr->daddr.s6_addr[1], 1); |
| 760 | hc06_ptr += 6; | 749 | lowpan_push_hc_data(&hc_ptr, |
| 750 | &hdr->daddr.s6_addr[11], 5); | ||
| 761 | } else { | 751 | } else { |
| 762 | pr_debug("using full address\n"); | 752 | pr_debug("using full address\n"); |
| 763 | iphc1 |= LOWPAN_IPHC_DAM_00; | 753 | iphc1 |= LOWPAN_IPHC_DAM_00; |
| 764 | memcpy(hc06_ptr, &hdr->daddr.s6_addr[0], 16); | 754 | lowpan_push_hc_data(&hc_ptr, hdr->daddr.s6_addr, 16); |
| 765 | hc06_ptr += 16; | ||
| 766 | } | 755 | } |
| 767 | } else { | 756 | } else { |
| 768 | /* TODO: context lookup */ | 757 | if (addr_type & IPV6_ADDR_LINKLOCAL) { |
| 769 | if (is_addr_link_local(&hdr->daddr)) { | 758 | /* TODO: context lookup */ |
| 770 | iphc1 |= lowpan_compress_addr_64(&hc06_ptr, | 759 | iphc1 |= lowpan_compress_addr_64(&hc_ptr, |
| 771 | LOWPAN_IPHC_DAM_BIT, &hdr->daddr, _daddr); | 760 | LOWPAN_IPHC_DAM_BIT, &hdr->daddr, _daddr); |
| 772 | pr_debug("dest address unicast link-local %pI6c " | 761 | pr_debug("dest address unicast link-local %pI6c " |
| 773 | "iphc1 0x%02x\n", &hdr->daddr, iphc1); | 762 | "iphc1 0x%02x\n", &hdr->daddr, iphc1); |
| 774 | } else { | 763 | } else { |
| 775 | pr_debug("dest address unicast %pI6c\n", &hdr->daddr); | 764 | pr_debug("dest address unicast %pI6c\n", &hdr->daddr); |
| 776 | memcpy(hc06_ptr, &hdr->daddr.s6_addr16[0], 16); | 765 | lowpan_push_hc_data(&hc_ptr, hdr->daddr.s6_addr, 16); |
| 777 | hc06_ptr += 16; | ||
| 778 | } | 766 | } |
| 779 | } | 767 | } |
| 780 | 768 | ||
| 781 | /* UDP header compression */ | 769 | /* UDP header compression */ |
| 782 | if (hdr->nexthdr == UIP_PROTO_UDP) | 770 | if (hdr->nexthdr == UIP_PROTO_UDP) |
| 783 | compress_udp_header(&hc06_ptr, skb); | 771 | compress_udp_header(&hc_ptr, skb); |
| 784 | 772 | ||
| 785 | head[0] = iphc0; | 773 | head[0] = iphc0; |
| 786 | head[1] = iphc1; | 774 | head[1] = iphc1; |
| 787 | 775 | ||
| 788 | skb_pull(skb, sizeof(struct ipv6hdr)); | 776 | skb_pull(skb, sizeof(struct ipv6hdr)); |
| 789 | skb_reset_transport_header(skb); | 777 | skb_reset_transport_header(skb); |
| 790 | memcpy(skb_push(skb, hc06_ptr - head), head, hc06_ptr - head); | 778 | memcpy(skb_push(skb, hc_ptr - head), head, hc_ptr - head); |
| 791 | skb_reset_network_header(skb); | 779 | skb_reset_network_header(skb); |
| 792 | 780 | ||
| 793 | pr_debug("header len %d skb %u\n", (int)(hc06_ptr - head), skb->len); | 781 | pr_debug("header len %d skb %u\n", (int)(hc_ptr - head), skb->len); |
| 794 | 782 | ||
| 795 | raw_dump_table(__func__, "raw skb data dump compressed", | 783 | raw_dump_table(__func__, "raw skb data dump compressed", |
| 796 | skb->data, skb->len); | 784 | skb->data, skb->len); |
| 797 | return 0; | 785 | return 0; |
| 798 | } | 786 | } |
| 799 | EXPORT_SYMBOL_GPL(lowpan_header_compress); | 787 | EXPORT_SYMBOL_GPL(lowpan_header_compress); |
diff --git a/net/802/fc.c b/net/802/fc.c index 05eea6b98bb8..7c174b6750cd 100644 --- a/net/802/fc.c +++ b/net/802/fc.c | |||
| @@ -126,6 +126,6 @@ static void fc_setup(struct net_device *dev) | |||
| 126 | */ | 126 | */ |
| 127 | struct net_device *alloc_fcdev(int sizeof_priv) | 127 | struct net_device *alloc_fcdev(int sizeof_priv) |
| 128 | { | 128 | { |
| 129 | return alloc_netdev(sizeof_priv, "fc%d", fc_setup); | 129 | return alloc_netdev(sizeof_priv, "fc%d", NET_NAME_UNKNOWN, fc_setup); |
| 130 | } | 130 | } |
| 131 | EXPORT_SYMBOL(alloc_fcdev); | 131 | EXPORT_SYMBOL(alloc_fcdev); |
diff --git a/net/802/fddi.c b/net/802/fddi.c index 9cda40661e0d..59e7346f1193 100644 --- a/net/802/fddi.c +++ b/net/802/fddi.c | |||
| @@ -207,7 +207,8 @@ static void fddi_setup(struct net_device *dev) | |||
| 207 | */ | 207 | */ |
| 208 | struct net_device *alloc_fddidev(int sizeof_priv) | 208 | struct net_device *alloc_fddidev(int sizeof_priv) |
| 209 | { | 209 | { |
| 210 | return alloc_netdev(sizeof_priv, "fddi%d", fddi_setup); | 210 | return alloc_netdev(sizeof_priv, "fddi%d", NET_NAME_UNKNOWN, |
| 211 | fddi_setup); | ||
| 211 | } | 212 | } |
| 212 | EXPORT_SYMBOL(alloc_fddidev); | 213 | EXPORT_SYMBOL(alloc_fddidev); |
| 213 | 214 | ||
diff --git a/net/802/hippi.c b/net/802/hippi.c index 5ff2a718ddca..2e03f8259dd5 100644 --- a/net/802/hippi.c +++ b/net/802/hippi.c | |||
| @@ -228,7 +228,8 @@ static void hippi_setup(struct net_device *dev) | |||
| 228 | 228 | ||
| 229 | struct net_device *alloc_hippi_dev(int sizeof_priv) | 229 | struct net_device *alloc_hippi_dev(int sizeof_priv) |
| 230 | { | 230 | { |
| 231 | return alloc_netdev(sizeof_priv, "hip%d", hippi_setup); | 231 | return alloc_netdev(sizeof_priv, "hip%d", NET_NAME_UNKNOWN, |
| 232 | hippi_setup); | ||
| 232 | } | 233 | } |
| 233 | 234 | ||
| 234 | EXPORT_SYMBOL(alloc_hippi_dev); | 235 | EXPORT_SYMBOL(alloc_hippi_dev); |
diff --git a/net/8021q/vlan.c b/net/8021q/vlan.c index 44ebd5c2cd4a..64c6bed4a3d3 100644 --- a/net/8021q/vlan.c +++ b/net/8021q/vlan.c | |||
| @@ -250,7 +250,8 @@ static int register_vlan_device(struct net_device *real_dev, u16 vlan_id) | |||
| 250 | snprintf(name, IFNAMSIZ, "vlan%.4i", vlan_id); | 250 | snprintf(name, IFNAMSIZ, "vlan%.4i", vlan_id); |
| 251 | } | 251 | } |
| 252 | 252 | ||
| 253 | new_dev = alloc_netdev(sizeof(struct vlan_dev_priv), name, vlan_setup); | 253 | new_dev = alloc_netdev(sizeof(struct vlan_dev_priv), name, |
| 254 | NET_NAME_UNKNOWN, vlan_setup); | ||
| 254 | 255 | ||
| 255 | if (new_dev == NULL) | 256 | if (new_dev == NULL) |
| 256 | return -ENOBUFS; | 257 | return -ENOBUFS; |
| @@ -324,23 +325,24 @@ static void vlan_transfer_features(struct net_device *dev, | |||
| 324 | netdev_update_features(vlandev); | 325 | netdev_update_features(vlandev); |
| 325 | } | 326 | } |
| 326 | 327 | ||
| 327 | static void __vlan_device_event(struct net_device *dev, unsigned long event) | 328 | static int __vlan_device_event(struct net_device *dev, unsigned long event) |
| 328 | { | 329 | { |
| 330 | int err = 0; | ||
| 331 | |||
| 329 | switch (event) { | 332 | switch (event) { |
| 330 | case NETDEV_CHANGENAME: | 333 | case NETDEV_CHANGENAME: |
| 331 | vlan_proc_rem_dev(dev); | 334 | vlan_proc_rem_dev(dev); |
| 332 | if (vlan_proc_add_dev(dev) < 0) | 335 | err = vlan_proc_add_dev(dev); |
| 333 | pr_warn("failed to change proc name for %s\n", | ||
| 334 | dev->name); | ||
| 335 | break; | 336 | break; |
| 336 | case NETDEV_REGISTER: | 337 | case NETDEV_REGISTER: |
| 337 | if (vlan_proc_add_dev(dev) < 0) | 338 | err = vlan_proc_add_dev(dev); |
| 338 | pr_warn("failed to add proc entry for %s\n", dev->name); | ||
| 339 | break; | 339 | break; |
| 340 | case NETDEV_UNREGISTER: | 340 | case NETDEV_UNREGISTER: |
| 341 | vlan_proc_rem_dev(dev); | 341 | vlan_proc_rem_dev(dev); |
| 342 | break; | 342 | break; |
| 343 | } | 343 | } |
| 344 | |||
| 345 | return err; | ||
| 344 | } | 346 | } |
| 345 | 347 | ||
| 346 | static int vlan_device_event(struct notifier_block *unused, unsigned long event, | 348 | static int vlan_device_event(struct notifier_block *unused, unsigned long event, |
| @@ -355,8 +357,12 @@ static int vlan_device_event(struct notifier_block *unused, unsigned long event, | |||
| 355 | bool last = false; | 357 | bool last = false; |
| 356 | LIST_HEAD(list); | 358 | LIST_HEAD(list); |
| 357 | 359 | ||
| 358 | if (is_vlan_dev(dev)) | 360 | if (is_vlan_dev(dev)) { |
| 359 | __vlan_device_event(dev, event); | 361 | int err = __vlan_device_event(dev, event); |
| 362 | |||
| 363 | if (err) | ||
| 364 | return notifier_from_errno(err); | ||
| 365 | } | ||
| 360 | 366 | ||
| 361 | if ((event == NETDEV_UP) && | 367 | if ((event == NETDEV_UP) && |
| 362 | (dev->features & NETIF_F_HW_VLAN_CTAG_FILTER)) { | 368 | (dev->features & NETIF_F_HW_VLAN_CTAG_FILTER)) { |
diff --git a/net/8021q/vlan_core.c b/net/8021q/vlan_core.c index 75d427763992..90cc2bdd4064 100644 --- a/net/8021q/vlan_core.c +++ b/net/8021q/vlan_core.c | |||
| @@ -112,59 +112,6 @@ __be16 vlan_dev_vlan_proto(const struct net_device *dev) | |||
| 112 | } | 112 | } |
| 113 | EXPORT_SYMBOL(vlan_dev_vlan_proto); | 113 | EXPORT_SYMBOL(vlan_dev_vlan_proto); |
| 114 | 114 | ||
| 115 | static struct sk_buff *vlan_reorder_header(struct sk_buff *skb) | ||
| 116 | { | ||
| 117 | if (skb_cow(skb, skb_headroom(skb)) < 0) { | ||
| 118 | kfree_skb(skb); | ||
| 119 | return NULL; | ||
| 120 | } | ||
| 121 | |||
| 122 | memmove(skb->data - ETH_HLEN, skb->data - VLAN_ETH_HLEN, 2 * ETH_ALEN); | ||
| 123 | skb->mac_header += VLAN_HLEN; | ||
| 124 | return skb; | ||
| 125 | } | ||
| 126 | |||
| 127 | struct sk_buff *vlan_untag(struct sk_buff *skb) | ||
| 128 | { | ||
| 129 | struct vlan_hdr *vhdr; | ||
| 130 | u16 vlan_tci; | ||
| 131 | |||
| 132 | if (unlikely(vlan_tx_tag_present(skb))) { | ||
| 133 | /* vlan_tci is already set-up so leave this for another time */ | ||
| 134 | return skb; | ||
| 135 | } | ||
| 136 | |||
| 137 | skb = skb_share_check(skb, GFP_ATOMIC); | ||
| 138 | if (unlikely(!skb)) | ||
| 139 | goto err_free; | ||
| 140 | |||
| 141 | if (unlikely(!pskb_may_pull(skb, VLAN_HLEN))) | ||
| 142 | goto err_free; | ||
| 143 | |||
| 144 | vhdr = (struct vlan_hdr *) skb->data; | ||
| 145 | vlan_tci = ntohs(vhdr->h_vlan_TCI); | ||
| 146 | __vlan_hwaccel_put_tag(skb, skb->protocol, vlan_tci); | ||
| 147 | |||
| 148 | skb_pull_rcsum(skb, VLAN_HLEN); | ||
| 149 | vlan_set_encap_proto(skb, vhdr); | ||
| 150 | |||
| 151 | skb = vlan_reorder_header(skb); | ||
| 152 | if (unlikely(!skb)) | ||
| 153 | goto err_free; | ||
| 154 | |||
| 155 | skb_reset_network_header(skb); | ||
| 156 | skb_reset_transport_header(skb); | ||
| 157 | skb_reset_mac_len(skb); | ||
| 158 | |||
| 159 | return skb; | ||
| 160 | |||
| 161 | err_free: | ||
| 162 | kfree_skb(skb); | ||
| 163 | return NULL; | ||
| 164 | } | ||
| 165 | EXPORT_SYMBOL(vlan_untag); | ||
| 166 | |||
| 167 | |||
| 168 | /* | 115 | /* |
| 169 | * vlan info and vid list | 116 | * vlan info and vid list |
| 170 | */ | 117 | */ |
diff --git a/net/8021q/vlan_dev.c b/net/8021q/vlan_dev.c index dd11f612e03e..35a6b6b15e8a 100644 --- a/net/8021q/vlan_dev.c +++ b/net/8021q/vlan_dev.c | |||
| @@ -385,6 +385,8 @@ static int vlan_dev_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) | |||
| 385 | case SIOCGMIIPHY: | 385 | case SIOCGMIIPHY: |
| 386 | case SIOCGMIIREG: | 386 | case SIOCGMIIREG: |
| 387 | case SIOCSMIIREG: | 387 | case SIOCSMIIREG: |
| 388 | case SIOCSHWTSTAMP: | ||
| 389 | case SIOCGHWTSTAMP: | ||
| 388 | if (netif_device_present(real_dev) && ops->ndo_do_ioctl) | 390 | if (netif_device_present(real_dev) && ops->ndo_do_ioctl) |
| 389 | err = ops->ndo_do_ioctl(real_dev, &ifrr, cmd); | 391 | err = ops->ndo_do_ioctl(real_dev, &ifrr, cmd); |
| 390 | break; | 392 | break; |
diff --git a/net/8021q/vlanproc.c b/net/8021q/vlanproc.c index 1d0e89213a28..ae63cf72a953 100644 --- a/net/8021q/vlanproc.c +++ b/net/8021q/vlanproc.c | |||
| @@ -171,6 +171,8 @@ int vlan_proc_add_dev(struct net_device *vlandev) | |||
| 171 | struct vlan_dev_priv *vlan = vlan_dev_priv(vlandev); | 171 | struct vlan_dev_priv *vlan = vlan_dev_priv(vlandev); |
| 172 | struct vlan_net *vn = net_generic(dev_net(vlandev), vlan_net_id); | 172 | struct vlan_net *vn = net_generic(dev_net(vlandev), vlan_net_id); |
| 173 | 173 | ||
| 174 | if (!strcmp(vlandev->name, name_conf)) | ||
| 175 | return -EINVAL; | ||
| 174 | vlan->dent = | 176 | vlan->dent = |
| 175 | proc_create_data(vlandev->name, S_IFREG|S_IRUSR|S_IWUSR, | 177 | proc_create_data(vlandev->name, S_IFREG|S_IRUSR|S_IWUSR, |
| 176 | vn->proc_vlan_dir, &vlandev_fops, vlandev); | 178 | vn->proc_vlan_dir, &vlandev_fops, vlandev); |
diff --git a/net/9p/client.c b/net/9p/client.c index 0004cbaac4a4..e86a9bea1d16 100644 --- a/net/9p/client.c +++ b/net/9p/client.c | |||
| @@ -959,7 +959,6 @@ static int p9_client_version(struct p9_client *c) | |||
| 959 | break; | 959 | break; |
| 960 | default: | 960 | default: |
| 961 | return -EINVAL; | 961 | return -EINVAL; |
| 962 | break; | ||
| 963 | } | 962 | } |
| 964 | 963 | ||
| 965 | if (IS_ERR(req)) | 964 | if (IS_ERR(req)) |
diff --git a/net/Kconfig b/net/Kconfig index d92afe4204d9..4051fdfa4367 100644 --- a/net/Kconfig +++ b/net/Kconfig | |||
| @@ -214,6 +214,7 @@ source "drivers/net/appletalk/Kconfig" | |||
| 214 | source "net/x25/Kconfig" | 214 | source "net/x25/Kconfig" |
| 215 | source "net/lapb/Kconfig" | 215 | source "net/lapb/Kconfig" |
| 216 | source "net/phonet/Kconfig" | 216 | source "net/phonet/Kconfig" |
| 217 | source "net/6lowpan/Kconfig" | ||
| 217 | source "net/ieee802154/Kconfig" | 218 | source "net/ieee802154/Kconfig" |
| 218 | source "net/mac802154/Kconfig" | 219 | source "net/mac802154/Kconfig" |
| 219 | source "net/sched/Kconfig" | 220 | source "net/sched/Kconfig" |
diff --git a/net/Makefile b/net/Makefile index cbbbe6d657ca..7ed1970074b0 100644 --- a/net/Makefile +++ b/net/Makefile | |||
| @@ -57,7 +57,8 @@ obj-$(CONFIG_CAIF) += caif/ | |||
| 57 | ifneq ($(CONFIG_DCB),) | 57 | ifneq ($(CONFIG_DCB),) |
| 58 | obj-y += dcb/ | 58 | obj-y += dcb/ |
| 59 | endif | 59 | endif |
| 60 | obj-y += ieee802154/ | 60 | obj-$(CONFIG_6LOWPAN) += 6lowpan/ |
| 61 | obj-$(CONFIG_IEEE802154) += ieee802154/ | ||
| 61 | obj-$(CONFIG_MAC802154) += mac802154/ | 62 | obj-$(CONFIG_MAC802154) += mac802154/ |
| 62 | 63 | ||
| 63 | ifeq ($(CONFIG_NET),y) | 64 | ifeq ($(CONFIG_NET),y) |
diff --git a/net/appletalk/ddp.c b/net/appletalk/ddp.c index bfcf6be1d665..c00897f65a31 100644 --- a/net/appletalk/ddp.c +++ b/net/appletalk/ddp.c | |||
| @@ -1805,7 +1805,7 @@ static int atalk_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg) | |||
| 1805 | long amount = 0; | 1805 | long amount = 0; |
| 1806 | 1806 | ||
| 1807 | if (skb) | 1807 | if (skb) |
| 1808 | amount = skb->len - sizeof(struct ddpehdr); | 1808 | amount = skb->len - sizeof(struct ddpehdr); |
| 1809 | rc = put_user(amount, (int __user *)argp); | 1809 | rc = put_user(amount, (int __user *)argp); |
| 1810 | break; | 1810 | break; |
| 1811 | } | 1811 | } |
diff --git a/net/appletalk/dev.c b/net/appletalk/dev.c index 6c8016f61866..e4158b8b926d 100644 --- a/net/appletalk/dev.c +++ b/net/appletalk/dev.c | |||
| @@ -39,6 +39,7 @@ static void ltalk_setup(struct net_device *dev) | |||
| 39 | 39 | ||
| 40 | struct net_device *alloc_ltalkdev(int sizeof_priv) | 40 | struct net_device *alloc_ltalkdev(int sizeof_priv) |
| 41 | { | 41 | { |
| 42 | return alloc_netdev(sizeof_priv, "lt%d", ltalk_setup); | 42 | return alloc_netdev(sizeof_priv, "lt%d", NET_NAME_UNKNOWN, |
| 43 | ltalk_setup); | ||
| 43 | } | 44 | } |
| 44 | EXPORT_SYMBOL(alloc_ltalkdev); | 45 | EXPORT_SYMBOL(alloc_ltalkdev); |
diff --git a/net/atm/br2684.c b/net/atm/br2684.c index 403e71fa88fe..cc78538d163b 100644 --- a/net/atm/br2684.c +++ b/net/atm/br2684.c | |||
| @@ -682,8 +682,8 @@ static int br2684_create(void __user *arg) | |||
| 682 | 682 | ||
| 683 | netdev = alloc_netdev(sizeof(struct br2684_dev), | 683 | netdev = alloc_netdev(sizeof(struct br2684_dev), |
| 684 | ni.ifname[0] ? ni.ifname : "nas%d", | 684 | ni.ifname[0] ? ni.ifname : "nas%d", |
| 685 | (payload == p_routed) ? | 685 | NET_NAME_UNKNOWN, |
| 686 | br2684_setup_routed : br2684_setup); | 686 | (payload == p_routed) ? br2684_setup_routed : br2684_setup); |
| 687 | if (!netdev) | 687 | if (!netdev) |
| 688 | return -ENOMEM; | 688 | return -ENOMEM; |
| 689 | 689 | ||
diff --git a/net/atm/clip.c b/net/atm/clip.c index ba291ce4bdff..46339040fef0 100644 --- a/net/atm/clip.c +++ b/net/atm/clip.c | |||
| @@ -520,7 +520,8 @@ static int clip_create(int number) | |||
| 520 | if (PRIV(dev)->number >= number) | 520 | if (PRIV(dev)->number >= number) |
| 521 | number = PRIV(dev)->number + 1; | 521 | number = PRIV(dev)->number + 1; |
| 522 | } | 522 | } |
| 523 | dev = alloc_netdev(sizeof(struct clip_priv), "", clip_setup); | 523 | dev = alloc_netdev(sizeof(struct clip_priv), "", NET_NAME_UNKNOWN, |
| 524 | clip_setup); | ||
| 524 | if (!dev) | 525 | if (!dev) |
| 525 | return -ENOMEM; | 526 | return -ENOMEM; |
| 526 | clip_priv = PRIV(dev); | 527 | clip_priv = PRIV(dev); |
diff --git a/net/atm/lec.c b/net/atm/lec.c index 4c5b8ba0f84f..e4853b50cf40 100644 --- a/net/atm/lec.c +++ b/net/atm/lec.c | |||
| @@ -833,7 +833,6 @@ static void *lec_tbl_walk(struct lec_state *state, struct hlist_head *tbl, | |||
| 833 | loff_t *l) | 833 | loff_t *l) |
| 834 | { | 834 | { |
| 835 | struct hlist_node *e = state->node; | 835 | struct hlist_node *e = state->node; |
| 836 | struct lec_arp_table *tmp; | ||
| 837 | 836 | ||
| 838 | if (!e) | 837 | if (!e) |
| 839 | e = tbl->first; | 838 | e = tbl->first; |
| @@ -842,9 +841,7 @@ static void *lec_tbl_walk(struct lec_state *state, struct hlist_head *tbl, | |||
| 842 | --*l; | 841 | --*l; |
| 843 | } | 842 | } |
| 844 | 843 | ||
| 845 | tmp = container_of(e, struct lec_arp_table, next); | 844 | for (; e; e = e->next) { |
| 846 | |||
| 847 | hlist_for_each_entry_from(tmp, next) { | ||
| 848 | if (--*l < 0) | 845 | if (--*l < 0) |
| 849 | break; | 846 | break; |
| 850 | } | 847 | } |
diff --git a/net/atm/svc.c b/net/atm/svc.c index d8e5d0c2ebbc..1ba23f5018e7 100644 --- a/net/atm/svc.c +++ b/net/atm/svc.c | |||
| @@ -50,12 +50,12 @@ static void svc_disconnect(struct atm_vcc *vcc) | |||
| 50 | 50 | ||
| 51 | pr_debug("%p\n", vcc); | 51 | pr_debug("%p\n", vcc); |
| 52 | if (test_bit(ATM_VF_REGIS, &vcc->flags)) { | 52 | if (test_bit(ATM_VF_REGIS, &vcc->flags)) { |
| 53 | prepare_to_wait(sk_sleep(sk), &wait, TASK_UNINTERRUPTIBLE); | ||
| 54 | sigd_enq(vcc, as_close, NULL, NULL, NULL); | 53 | sigd_enq(vcc, as_close, NULL, NULL, NULL); |
| 55 | while (!test_bit(ATM_VF_RELEASED, &vcc->flags) && sigd) { | 54 | for (;;) { |
| 55 | prepare_to_wait(sk_sleep(sk), &wait, TASK_UNINTERRUPTIBLE); | ||
| 56 | if (test_bit(ATM_VF_RELEASED, &vcc->flags) || !sigd) | ||
| 57 | break; | ||
| 56 | schedule(); | 58 | schedule(); |
| 57 | prepare_to_wait(sk_sleep(sk), &wait, | ||
| 58 | TASK_UNINTERRUPTIBLE); | ||
| 59 | } | 59 | } |
| 60 | finish_wait(sk_sleep(sk), &wait); | 60 | finish_wait(sk_sleep(sk), &wait); |
| 61 | } | 61 | } |
| @@ -126,11 +126,12 @@ static int svc_bind(struct socket *sock, struct sockaddr *sockaddr, | |||
| 126 | } | 126 | } |
| 127 | vcc->local = *addr; | 127 | vcc->local = *addr; |
| 128 | set_bit(ATM_VF_WAITING, &vcc->flags); | 128 | set_bit(ATM_VF_WAITING, &vcc->flags); |
| 129 | prepare_to_wait(sk_sleep(sk), &wait, TASK_UNINTERRUPTIBLE); | ||
| 130 | sigd_enq(vcc, as_bind, NULL, NULL, &vcc->local); | 129 | sigd_enq(vcc, as_bind, NULL, NULL, &vcc->local); |
| 131 | while (test_bit(ATM_VF_WAITING, &vcc->flags) && sigd) { | 130 | for (;;) { |
| 132 | schedule(); | ||
| 133 | prepare_to_wait(sk_sleep(sk), &wait, TASK_UNINTERRUPTIBLE); | 131 | prepare_to_wait(sk_sleep(sk), &wait, TASK_UNINTERRUPTIBLE); |
| 132 | if (!test_bit(ATM_VF_WAITING, &vcc->flags) || !sigd) | ||
| 133 | break; | ||
| 134 | schedule(); | ||
| 134 | } | 135 | } |
| 135 | finish_wait(sk_sleep(sk), &wait); | 136 | finish_wait(sk_sleep(sk), &wait); |
| 136 | clear_bit(ATM_VF_REGIS, &vcc->flags); /* doesn't count */ | 137 | clear_bit(ATM_VF_REGIS, &vcc->flags); /* doesn't count */ |
| @@ -202,15 +203,14 @@ static int svc_connect(struct socket *sock, struct sockaddr *sockaddr, | |||
| 202 | } | 203 | } |
| 203 | vcc->remote = *addr; | 204 | vcc->remote = *addr; |
| 204 | set_bit(ATM_VF_WAITING, &vcc->flags); | 205 | set_bit(ATM_VF_WAITING, &vcc->flags); |
| 205 | prepare_to_wait(sk_sleep(sk), &wait, TASK_INTERRUPTIBLE); | ||
| 206 | sigd_enq(vcc, as_connect, NULL, NULL, &vcc->remote); | 206 | sigd_enq(vcc, as_connect, NULL, NULL, &vcc->remote); |
| 207 | if (flags & O_NONBLOCK) { | 207 | if (flags & O_NONBLOCK) { |
| 208 | finish_wait(sk_sleep(sk), &wait); | ||
| 209 | sock->state = SS_CONNECTING; | 208 | sock->state = SS_CONNECTING; |
| 210 | error = -EINPROGRESS; | 209 | error = -EINPROGRESS; |
| 211 | goto out; | 210 | goto out; |
| 212 | } | 211 | } |
| 213 | error = 0; | 212 | error = 0; |
| 213 | prepare_to_wait(sk_sleep(sk), &wait, TASK_INTERRUPTIBLE); | ||
| 214 | while (test_bit(ATM_VF_WAITING, &vcc->flags) && sigd) { | 214 | while (test_bit(ATM_VF_WAITING, &vcc->flags) && sigd) { |
| 215 | schedule(); | 215 | schedule(); |
| 216 | if (!signal_pending(current)) { | 216 | if (!signal_pending(current)) { |
| @@ -297,11 +297,12 @@ static int svc_listen(struct socket *sock, int backlog) | |||
| 297 | goto out; | 297 | goto out; |
| 298 | } | 298 | } |
| 299 | set_bit(ATM_VF_WAITING, &vcc->flags); | 299 | set_bit(ATM_VF_WAITING, &vcc->flags); |
| 300 | prepare_to_wait(sk_sleep(sk), &wait, TASK_UNINTERRUPTIBLE); | ||
| 301 | sigd_enq(vcc, as_listen, NULL, NULL, &vcc->local); | 300 | sigd_enq(vcc, as_listen, NULL, NULL, &vcc->local); |
| 302 | while (test_bit(ATM_VF_WAITING, &vcc->flags) && sigd) { | 301 | for (;;) { |
| 303 | schedule(); | ||
| 304 | prepare_to_wait(sk_sleep(sk), &wait, TASK_UNINTERRUPTIBLE); | 302 | prepare_to_wait(sk_sleep(sk), &wait, TASK_UNINTERRUPTIBLE); |
| 303 | if (!test_bit(ATM_VF_WAITING, &vcc->flags) || !sigd) | ||
| 304 | break; | ||
| 305 | schedule(); | ||
| 305 | } | 306 | } |
| 306 | finish_wait(sk_sleep(sk), &wait); | 307 | finish_wait(sk_sleep(sk), &wait); |
| 307 | if (!sigd) { | 308 | if (!sigd) { |
| @@ -387,15 +388,15 @@ static int svc_accept(struct socket *sock, struct socket *newsock, int flags) | |||
| 387 | } | 388 | } |
| 388 | /* wait should be short, so we ignore the non-blocking flag */ | 389 | /* wait should be short, so we ignore the non-blocking flag */ |
| 389 | set_bit(ATM_VF_WAITING, &new_vcc->flags); | 390 | set_bit(ATM_VF_WAITING, &new_vcc->flags); |
| 390 | prepare_to_wait(sk_sleep(sk_atm(new_vcc)), &wait, | ||
| 391 | TASK_UNINTERRUPTIBLE); | ||
| 392 | sigd_enq(new_vcc, as_accept, old_vcc, NULL, NULL); | 391 | sigd_enq(new_vcc, as_accept, old_vcc, NULL, NULL); |
| 393 | while (test_bit(ATM_VF_WAITING, &new_vcc->flags) && sigd) { | 392 | for (;;) { |
| 393 | prepare_to_wait(sk_sleep(sk_atm(new_vcc)), &wait, | ||
| 394 | TASK_UNINTERRUPTIBLE); | ||
| 395 | if (!test_bit(ATM_VF_WAITING, &new_vcc->flags) || !sigd) | ||
| 396 | break; | ||
| 394 | release_sock(sk); | 397 | release_sock(sk); |
| 395 | schedule(); | 398 | schedule(); |
| 396 | lock_sock(sk); | 399 | lock_sock(sk); |
| 397 | prepare_to_wait(sk_sleep(sk_atm(new_vcc)), &wait, | ||
| 398 | TASK_UNINTERRUPTIBLE); | ||
| 399 | } | 400 | } |
| 400 | finish_wait(sk_sleep(sk_atm(new_vcc)), &wait); | 401 | finish_wait(sk_sleep(sk_atm(new_vcc)), &wait); |
| 401 | if (!sigd) { | 402 | if (!sigd) { |
| @@ -433,12 +434,14 @@ int svc_change_qos(struct atm_vcc *vcc, struct atm_qos *qos) | |||
| 433 | DEFINE_WAIT(wait); | 434 | DEFINE_WAIT(wait); |
| 434 | 435 | ||
| 435 | set_bit(ATM_VF_WAITING, &vcc->flags); | 436 | set_bit(ATM_VF_WAITING, &vcc->flags); |
| 436 | prepare_to_wait(sk_sleep(sk), &wait, TASK_UNINTERRUPTIBLE); | ||
| 437 | sigd_enq2(vcc, as_modify, NULL, NULL, &vcc->local, qos, 0); | 437 | sigd_enq2(vcc, as_modify, NULL, NULL, &vcc->local, qos, 0); |
| 438 | while (test_bit(ATM_VF_WAITING, &vcc->flags) && | 438 | for (;;) { |
| 439 | !test_bit(ATM_VF_RELEASED, &vcc->flags) && sigd) { | ||
| 440 | schedule(); | ||
| 441 | prepare_to_wait(sk_sleep(sk), &wait, TASK_UNINTERRUPTIBLE); | 439 | prepare_to_wait(sk_sleep(sk), &wait, TASK_UNINTERRUPTIBLE); |
| 440 | if (!test_bit(ATM_VF_WAITING, &vcc->flags) || | ||
| 441 | test_bit(ATM_VF_RELEASED, &vcc->flags) || !sigd) { | ||
| 442 | break; | ||
| 443 | } | ||
| 444 | schedule(); | ||
| 442 | } | 445 | } |
| 443 | finish_wait(sk_sleep(sk), &wait); | 446 | finish_wait(sk_sleep(sk), &wait); |
| 444 | if (!sigd) | 447 | if (!sigd) |
| @@ -529,18 +532,18 @@ static int svc_addparty(struct socket *sock, struct sockaddr *sockaddr, | |||
| 529 | 532 | ||
| 530 | lock_sock(sk); | 533 | lock_sock(sk); |
| 531 | set_bit(ATM_VF_WAITING, &vcc->flags); | 534 | set_bit(ATM_VF_WAITING, &vcc->flags); |
| 532 | prepare_to_wait(sk_sleep(sk), &wait, TASK_INTERRUPTIBLE); | ||
| 533 | sigd_enq(vcc, as_addparty, NULL, NULL, | 535 | sigd_enq(vcc, as_addparty, NULL, NULL, |
| 534 | (struct sockaddr_atmsvc *) sockaddr); | 536 | (struct sockaddr_atmsvc *) sockaddr); |
| 535 | if (flags & O_NONBLOCK) { | 537 | if (flags & O_NONBLOCK) { |
| 536 | finish_wait(sk_sleep(sk), &wait); | ||
| 537 | error = -EINPROGRESS; | 538 | error = -EINPROGRESS; |
| 538 | goto out; | 539 | goto out; |
| 539 | } | 540 | } |
| 540 | pr_debug("added wait queue\n"); | 541 | pr_debug("added wait queue\n"); |
| 541 | while (test_bit(ATM_VF_WAITING, &vcc->flags) && sigd) { | 542 | for (;;) { |
| 542 | schedule(); | ||
| 543 | prepare_to_wait(sk_sleep(sk), &wait, TASK_INTERRUPTIBLE); | 543 | prepare_to_wait(sk_sleep(sk), &wait, TASK_INTERRUPTIBLE); |
| 544 | if (!test_bit(ATM_VF_WAITING, &vcc->flags) || !sigd) | ||
| 545 | break; | ||
| 546 | schedule(); | ||
| 544 | } | 547 | } |
| 545 | finish_wait(sk_sleep(sk), &wait); | 548 | finish_wait(sk_sleep(sk), &wait); |
| 546 | error = xchg(&sk->sk_err_soft, 0); | 549 | error = xchg(&sk->sk_err_soft, 0); |
| @@ -558,11 +561,12 @@ static int svc_dropparty(struct socket *sock, int ep_ref) | |||
| 558 | 561 | ||
| 559 | lock_sock(sk); | 562 | lock_sock(sk); |
| 560 | set_bit(ATM_VF_WAITING, &vcc->flags); | 563 | set_bit(ATM_VF_WAITING, &vcc->flags); |
| 561 | prepare_to_wait(sk_sleep(sk), &wait, TASK_INTERRUPTIBLE); | ||
| 562 | sigd_enq2(vcc, as_dropparty, NULL, NULL, NULL, NULL, ep_ref); | 564 | sigd_enq2(vcc, as_dropparty, NULL, NULL, NULL, NULL, ep_ref); |
| 563 | while (test_bit(ATM_VF_WAITING, &vcc->flags) && sigd) { | 565 | for (;;) { |
| 564 | schedule(); | ||
| 565 | prepare_to_wait(sk_sleep(sk), &wait, TASK_INTERRUPTIBLE); | 566 | prepare_to_wait(sk_sleep(sk), &wait, TASK_INTERRUPTIBLE); |
| 567 | if (!test_bit(ATM_VF_WAITING, &vcc->flags) || !sigd) | ||
| 568 | break; | ||
| 569 | schedule(); | ||
| 566 | } | 570 | } |
| 567 | finish_wait(sk_sleep(sk), &wait); | 571 | finish_wait(sk_sleep(sk), &wait); |
| 568 | if (!sigd) { | 572 | if (!sigd) { |
diff --git a/net/batman-adv/bat_iv_ogm.c b/net/batman-adv/bat_iv_ogm.c index f04224c32005..1e8053976e83 100644 --- a/net/batman-adv/bat_iv_ogm.c +++ b/net/batman-adv/bat_iv_ogm.c | |||
| @@ -108,14 +108,15 @@ static int batadv_iv_ogm_orig_add_if(struct batadv_orig_node *orig_node, | |||
| 108 | int max_if_num) | 108 | int max_if_num) |
| 109 | { | 109 | { |
| 110 | void *data_ptr; | 110 | void *data_ptr; |
| 111 | size_t data_size, old_size; | 111 | size_t old_size; |
| 112 | int ret = -ENOMEM; | 112 | int ret = -ENOMEM; |
| 113 | 113 | ||
| 114 | spin_lock_bh(&orig_node->bat_iv.ogm_cnt_lock); | 114 | spin_lock_bh(&orig_node->bat_iv.ogm_cnt_lock); |
| 115 | 115 | ||
| 116 | data_size = max_if_num * sizeof(unsigned long) * BATADV_NUM_WORDS; | ||
| 117 | old_size = (max_if_num - 1) * sizeof(unsigned long) * BATADV_NUM_WORDS; | 116 | old_size = (max_if_num - 1) * sizeof(unsigned long) * BATADV_NUM_WORDS; |
| 118 | data_ptr = kmalloc(data_size, GFP_ATOMIC); | 117 | data_ptr = kmalloc_array(max_if_num, |
| 118 | BATADV_NUM_WORDS * sizeof(unsigned long), | ||
| 119 | GFP_ATOMIC); | ||
| 119 | if (!data_ptr) | 120 | if (!data_ptr) |
| 120 | goto unlock; | 121 | goto unlock; |
| 121 | 122 | ||
| @@ -123,7 +124,7 @@ static int batadv_iv_ogm_orig_add_if(struct batadv_orig_node *orig_node, | |||
| 123 | kfree(orig_node->bat_iv.bcast_own); | 124 | kfree(orig_node->bat_iv.bcast_own); |
| 124 | orig_node->bat_iv.bcast_own = data_ptr; | 125 | orig_node->bat_iv.bcast_own = data_ptr; |
| 125 | 126 | ||
| 126 | data_ptr = kmalloc(max_if_num * sizeof(uint8_t), GFP_ATOMIC); | 127 | data_ptr = kmalloc_array(max_if_num, sizeof(uint8_t), GFP_ATOMIC); |
| 127 | if (!data_ptr) { | 128 | if (!data_ptr) { |
| 128 | kfree(orig_node->bat_iv.bcast_own); | 129 | kfree(orig_node->bat_iv.bcast_own); |
| 129 | goto unlock; | 130 | goto unlock; |
| @@ -164,7 +165,7 @@ static int batadv_iv_ogm_orig_del_if(struct batadv_orig_node *orig_node, | |||
| 164 | goto free_bcast_own; | 165 | goto free_bcast_own; |
| 165 | 166 | ||
| 166 | chunk_size = sizeof(unsigned long) * BATADV_NUM_WORDS; | 167 | chunk_size = sizeof(unsigned long) * BATADV_NUM_WORDS; |
| 167 | data_ptr = kmalloc(max_if_num * chunk_size, GFP_ATOMIC); | 168 | data_ptr = kmalloc_array(max_if_num, chunk_size, GFP_ATOMIC); |
| 168 | if (!data_ptr) | 169 | if (!data_ptr) |
| 169 | goto unlock; | 170 | goto unlock; |
| 170 | 171 | ||
| @@ -183,7 +184,7 @@ free_bcast_own: | |||
| 183 | if (max_if_num == 0) | 184 | if (max_if_num == 0) |
| 184 | goto free_own_sum; | 185 | goto free_own_sum; |
| 185 | 186 | ||
| 186 | data_ptr = kmalloc(max_if_num * sizeof(uint8_t), GFP_ATOMIC); | 187 | data_ptr = kmalloc_array(max_if_num, sizeof(uint8_t), GFP_ATOMIC); |
| 187 | if (!data_ptr) { | 188 | if (!data_ptr) { |
| 188 | kfree(orig_node->bat_iv.bcast_own); | 189 | kfree(orig_node->bat_iv.bcast_own); |
| 189 | goto unlock; | 190 | goto unlock; |
diff --git a/net/batman-adv/distributed-arp-table.c b/net/batman-adv/distributed-arp-table.c index f2c066b21716..b5981113c9a7 100644 --- a/net/batman-adv/distributed-arp-table.c +++ b/net/batman-adv/distributed-arp-table.c | |||
| @@ -537,7 +537,8 @@ batadv_dat_select_candidates(struct batadv_priv *bat_priv, __be32 ip_dst) | |||
| 537 | if (!bat_priv->orig_hash) | 537 | if (!bat_priv->orig_hash) |
| 538 | return NULL; | 538 | return NULL; |
| 539 | 539 | ||
| 540 | res = kmalloc(BATADV_DAT_CANDIDATES_NUM * sizeof(*res), GFP_ATOMIC); | 540 | res = kmalloc_array(BATADV_DAT_CANDIDATES_NUM, sizeof(*res), |
| 541 | GFP_ATOMIC); | ||
| 541 | if (!res) | 542 | if (!res) |
| 542 | return NULL; | 543 | return NULL; |
| 543 | 544 | ||
diff --git a/net/batman-adv/fragmentation.c b/net/batman-adv/fragmentation.c index f14e54a05691..52c43f904220 100644 --- a/net/batman-adv/fragmentation.c +++ b/net/batman-adv/fragmentation.c | |||
| @@ -128,6 +128,7 @@ static bool batadv_frag_insert_packet(struct batadv_orig_node *orig_node, | |||
| 128 | { | 128 | { |
| 129 | struct batadv_frag_table_entry *chain; | 129 | struct batadv_frag_table_entry *chain; |
| 130 | struct batadv_frag_list_entry *frag_entry_new = NULL, *frag_entry_curr; | 130 | struct batadv_frag_list_entry *frag_entry_new = NULL, *frag_entry_curr; |
| 131 | struct batadv_frag_list_entry *frag_entry_last = NULL; | ||
| 131 | struct batadv_frag_packet *frag_packet; | 132 | struct batadv_frag_packet *frag_packet; |
| 132 | uint8_t bucket; | 133 | uint8_t bucket; |
| 133 | uint16_t seqno, hdr_size = sizeof(struct batadv_frag_packet); | 134 | uint16_t seqno, hdr_size = sizeof(struct batadv_frag_packet); |
| @@ -180,11 +181,14 @@ static bool batadv_frag_insert_packet(struct batadv_orig_node *orig_node, | |||
| 180 | ret = true; | 181 | ret = true; |
| 181 | goto out; | 182 | goto out; |
| 182 | } | 183 | } |
| 184 | |||
| 185 | /* store current entry because it could be the last in list */ | ||
| 186 | frag_entry_last = frag_entry_curr; | ||
| 183 | } | 187 | } |
| 184 | 188 | ||
| 185 | /* Reached the end of the list, so insert after 'frag_entry_curr'. */ | 189 | /* Reached the end of the list, so insert after 'frag_entry_last'. */ |
| 186 | if (likely(frag_entry_curr)) { | 190 | if (likely(frag_entry_last)) { |
| 187 | hlist_add_after(&frag_entry_curr->list, &frag_entry_new->list); | 191 | hlist_add_behind(&frag_entry_last->list, &frag_entry_new->list); |
| 188 | chain->size += skb->len - hdr_size; | 192 | chain->size += skb->len - hdr_size; |
| 189 | chain->timestamp = jiffies; | 193 | chain->timestamp = jiffies; |
| 190 | ret = true; | 194 | ret = true; |
diff --git a/net/batman-adv/hash.c b/net/batman-adv/hash.c index 63bdf7e94f1e..7c1c63080e20 100644 --- a/net/batman-adv/hash.c +++ b/net/batman-adv/hash.c | |||
| @@ -46,12 +46,12 @@ struct batadv_hashtable *batadv_hash_new(uint32_t size) | |||
| 46 | if (!hash) | 46 | if (!hash) |
| 47 | return NULL; | 47 | return NULL; |
| 48 | 48 | ||
| 49 | hash->table = kmalloc(sizeof(*hash->table) * size, GFP_ATOMIC); | 49 | hash->table = kmalloc_array(size, sizeof(*hash->table), GFP_ATOMIC); |
| 50 | if (!hash->table) | 50 | if (!hash->table) |
| 51 | goto free_hash; | 51 | goto free_hash; |
| 52 | 52 | ||
| 53 | hash->list_locks = kmalloc(sizeof(*hash->list_locks) * size, | 53 | hash->list_locks = kmalloc_array(size, sizeof(*hash->list_locks), |
| 54 | GFP_ATOMIC); | 54 | GFP_ATOMIC); |
| 55 | if (!hash->list_locks) | 55 | if (!hash->list_locks) |
| 56 | goto free_table; | 56 | goto free_table; |
| 57 | 57 | ||
diff --git a/net/batman-adv/main.h b/net/batman-adv/main.h index 118b990bae25..a1fcd884f0b1 100644 --- a/net/batman-adv/main.h +++ b/net/batman-adv/main.h | |||
| @@ -24,7 +24,7 @@ | |||
| 24 | #define BATADV_DRIVER_DEVICE "batman-adv" | 24 | #define BATADV_DRIVER_DEVICE "batman-adv" |
| 25 | 25 | ||
| 26 | #ifndef BATADV_SOURCE_VERSION | 26 | #ifndef BATADV_SOURCE_VERSION |
| 27 | #define BATADV_SOURCE_VERSION "2014.3.0" | 27 | #define BATADV_SOURCE_VERSION "2014.4.0" |
| 28 | #endif | 28 | #endif |
| 29 | 29 | ||
| 30 | /* B.A.T.M.A.N. parameters */ | 30 | /* B.A.T.M.A.N. parameters */ |
| @@ -238,21 +238,29 @@ enum batadv_dbg_level { | |||
| 238 | int batadv_debug_log(struct batadv_priv *bat_priv, const char *fmt, ...) | 238 | int batadv_debug_log(struct batadv_priv *bat_priv, const char *fmt, ...) |
| 239 | __printf(2, 3); | 239 | __printf(2, 3); |
| 240 | 240 | ||
| 241 | #define batadv_dbg(type, bat_priv, fmt, arg...) \ | 241 | /* possibly ratelimited debug output */ |
| 242 | #define _batadv_dbg(type, bat_priv, ratelimited, fmt, arg...) \ | ||
| 242 | do { \ | 243 | do { \ |
| 243 | if (atomic_read(&bat_priv->log_level) & type) \ | 244 | if (atomic_read(&bat_priv->log_level) & type && \ |
| 245 | (!ratelimited || net_ratelimit())) \ | ||
| 244 | batadv_debug_log(bat_priv, fmt, ## arg);\ | 246 | batadv_debug_log(bat_priv, fmt, ## arg);\ |
| 245 | } \ | 247 | } \ |
| 246 | while (0) | 248 | while (0) |
| 247 | #else /* !CONFIG_BATMAN_ADV_DEBUG */ | 249 | #else /* !CONFIG_BATMAN_ADV_DEBUG */ |
| 248 | __printf(3, 4) | 250 | __printf(4, 5) |
| 249 | static inline void batadv_dbg(int type __always_unused, | 251 | static inline void _batadv_dbg(int type __always_unused, |
| 250 | struct batadv_priv *bat_priv __always_unused, | 252 | struct batadv_priv *bat_priv __always_unused, |
| 251 | const char *fmt __always_unused, ...) | 253 | int ratelimited __always_unused, |
| 254 | const char *fmt __always_unused, ...) | ||
| 252 | { | 255 | { |
| 253 | } | 256 | } |
| 254 | #endif | 257 | #endif |
| 255 | 258 | ||
| 259 | #define batadv_dbg(type, bat_priv, arg...) \ | ||
| 260 | _batadv_dbg(type, bat_priv, 0, ## arg) | ||
| 261 | #define batadv_dbg_ratelimited(type, bat_priv, arg...) \ | ||
| 262 | _batadv_dbg(type, bat_priv, 1, ## arg) | ||
| 263 | |||
| 256 | #define batadv_info(net_dev, fmt, arg...) \ | 264 | #define batadv_info(net_dev, fmt, arg...) \ |
| 257 | do { \ | 265 | do { \ |
| 258 | struct net_device *_netdev = (net_dev); \ | 266 | struct net_device *_netdev = (net_dev); \ |
diff --git a/net/batman-adv/multicast.c b/net/batman-adv/multicast.c index 96b66fd30f96..ab6bb2af1d45 100644 --- a/net/batman-adv/multicast.c +++ b/net/batman-adv/multicast.c | |||
| @@ -20,7 +20,6 @@ | |||
| 20 | #include "originator.h" | 20 | #include "originator.h" |
| 21 | #include "hard-interface.h" | 21 | #include "hard-interface.h" |
| 22 | #include "translation-table.h" | 22 | #include "translation-table.h" |
| 23 | #include "multicast.h" | ||
| 24 | 23 | ||
| 25 | /** | 24 | /** |
| 26 | * batadv_mcast_mla_softif_get - get softif multicast listeners | 25 | * batadv_mcast_mla_softif_get - get softif multicast listeners |
diff --git a/net/batman-adv/routing.c b/net/batman-adv/routing.c index 35141534938e..35f76f2f7824 100644 --- a/net/batman-adv/routing.c +++ b/net/batman-adv/routing.c | |||
| @@ -706,11 +706,11 @@ static int batadv_check_unicast_ttvn(struct batadv_priv *bat_priv, | |||
| 706 | if (batadv_tt_local_client_is_roaming(bat_priv, ethhdr->h_dest, vid)) { | 706 | if (batadv_tt_local_client_is_roaming(bat_priv, ethhdr->h_dest, vid)) { |
| 707 | if (batadv_reroute_unicast_packet(bat_priv, unicast_packet, | 707 | if (batadv_reroute_unicast_packet(bat_priv, unicast_packet, |
| 708 | ethhdr->h_dest, vid)) | 708 | ethhdr->h_dest, vid)) |
| 709 | net_ratelimited_function(batadv_dbg, BATADV_DBG_TT, | 709 | batadv_dbg_ratelimited(BATADV_DBG_TT, |
| 710 | bat_priv, | 710 | bat_priv, |
| 711 | "Rerouting unicast packet to %pM (dst=%pM): Local Roaming\n", | 711 | "Rerouting unicast packet to %pM (dst=%pM): Local Roaming\n", |
| 712 | unicast_packet->dest, | 712 | unicast_packet->dest, |
| 713 | ethhdr->h_dest); | 713 | ethhdr->h_dest); |
| 714 | /* at this point the mesh destination should have been | 714 | /* at this point the mesh destination should have been |
| 715 | * substituted with the originator address found in the global | 715 | * substituted with the originator address found in the global |
| 716 | * table. If not, let the packet go untouched anyway because | 716 | * table. If not, let the packet go untouched anyway because |
| @@ -752,10 +752,10 @@ static int batadv_check_unicast_ttvn(struct batadv_priv *bat_priv, | |||
| 752 | */ | 752 | */ |
| 753 | if (batadv_reroute_unicast_packet(bat_priv, unicast_packet, | 753 | if (batadv_reroute_unicast_packet(bat_priv, unicast_packet, |
| 754 | ethhdr->h_dest, vid)) { | 754 | ethhdr->h_dest, vid)) { |
| 755 | net_ratelimited_function(batadv_dbg, BATADV_DBG_TT, bat_priv, | 755 | batadv_dbg_ratelimited(BATADV_DBG_TT, bat_priv, |
| 756 | "Rerouting unicast packet to %pM (dst=%pM): TTVN mismatch old_ttvn=%u new_ttvn=%u\n", | 756 | "Rerouting unicast packet to %pM (dst=%pM): TTVN mismatch old_ttvn=%u new_ttvn=%u\n", |
| 757 | unicast_packet->dest, ethhdr->h_dest, | 757 | unicast_packet->dest, ethhdr->h_dest, |
| 758 | old_ttvn, curr_ttvn); | 758 | old_ttvn, curr_ttvn); |
| 759 | return 1; | 759 | return 1; |
| 760 | } | 760 | } |
| 761 | 761 | ||
diff --git a/net/batman-adv/soft-interface.c b/net/batman-adv/soft-interface.c index cbd677f48c00..5467955eb27c 100644 --- a/net/batman-adv/soft-interface.c +++ b/net/batman-adv/soft-interface.c | |||
| @@ -751,7 +751,7 @@ static int batadv_softif_init_late(struct net_device *dev) | |||
| 751 | atomic_set(&bat_priv->gw.bandwidth_down, 100); | 751 | atomic_set(&bat_priv->gw.bandwidth_down, 100); |
| 752 | atomic_set(&bat_priv->gw.bandwidth_up, 20); | 752 | atomic_set(&bat_priv->gw.bandwidth_up, 20); |
| 753 | atomic_set(&bat_priv->orig_interval, 1000); | 753 | atomic_set(&bat_priv->orig_interval, 1000); |
| 754 | atomic_set(&bat_priv->hop_penalty, 15); | 754 | atomic_set(&bat_priv->hop_penalty, 30); |
| 755 | #ifdef CONFIG_BATMAN_ADV_DEBUG | 755 | #ifdef CONFIG_BATMAN_ADV_DEBUG |
| 756 | atomic_set(&bat_priv->log_level, 0); | 756 | atomic_set(&bat_priv->log_level, 0); |
| 757 | #endif | 757 | #endif |
| @@ -927,7 +927,7 @@ struct net_device *batadv_softif_create(const char *name) | |||
| 927 | int ret; | 927 | int ret; |
| 928 | 928 | ||
| 929 | soft_iface = alloc_netdev(sizeof(struct batadv_priv), name, | 929 | soft_iface = alloc_netdev(sizeof(struct batadv_priv), name, |
| 930 | batadv_softif_init_early); | 930 | NET_NAME_UNKNOWN, batadv_softif_init_early); |
| 931 | if (!soft_iface) | 931 | if (!soft_iface) |
| 932 | return NULL; | 932 | return NULL; |
| 933 | 933 | ||
diff --git a/net/batman-adv/sysfs.c b/net/batman-adv/sysfs.c index fc47baa888c5..f40cb0436eba 100644 --- a/net/batman-adv/sysfs.c +++ b/net/batman-adv/sysfs.c | |||
| @@ -900,32 +900,24 @@ int batadv_throw_uevent(struct batadv_priv *bat_priv, enum batadv_uev_type type, | |||
| 900 | 900 | ||
| 901 | bat_kobj = &bat_priv->soft_iface->dev.kobj; | 901 | bat_kobj = &bat_priv->soft_iface->dev.kobj; |
| 902 | 902 | ||
| 903 | uevent_env[0] = kmalloc(strlen(BATADV_UEV_TYPE_VAR) + | 903 | uevent_env[0] = kasprintf(GFP_ATOMIC, |
| 904 | strlen(batadv_uev_type_str[type]) + 1, | 904 | "%s%s", BATADV_UEV_TYPE_VAR, |
| 905 | GFP_ATOMIC); | 905 | batadv_uev_type_str[type]); |
| 906 | if (!uevent_env[0]) | 906 | if (!uevent_env[0]) |
| 907 | goto out; | 907 | goto out; |
| 908 | 908 | ||
| 909 | sprintf(uevent_env[0], "%s%s", BATADV_UEV_TYPE_VAR, | 909 | uevent_env[1] = kasprintf(GFP_ATOMIC, |
| 910 | batadv_uev_type_str[type]); | 910 | "%s%s", BATADV_UEV_ACTION_VAR, |
| 911 | 911 | batadv_uev_action_str[action]); | |
| 912 | uevent_env[1] = kmalloc(strlen(BATADV_UEV_ACTION_VAR) + | ||
| 913 | strlen(batadv_uev_action_str[action]) + 1, | ||
| 914 | GFP_ATOMIC); | ||
| 915 | if (!uevent_env[1]) | 912 | if (!uevent_env[1]) |
| 916 | goto out; | 913 | goto out; |
| 917 | 914 | ||
| 918 | sprintf(uevent_env[1], "%s%s", BATADV_UEV_ACTION_VAR, | ||
| 919 | batadv_uev_action_str[action]); | ||
| 920 | |||
| 921 | /* If the event is DEL, ignore the data field */ | 915 | /* If the event is DEL, ignore the data field */ |
| 922 | if (action != BATADV_UEV_DEL) { | 916 | if (action != BATADV_UEV_DEL) { |
| 923 | uevent_env[2] = kmalloc(strlen(BATADV_UEV_DATA_VAR) + | 917 | uevent_env[2] = kasprintf(GFP_ATOMIC, |
| 924 | strlen(data) + 1, GFP_ATOMIC); | 918 | "%s%s", BATADV_UEV_DATA_VAR, data); |
| 925 | if (!uevent_env[2]) | 919 | if (!uevent_env[2]) |
| 926 | goto out; | 920 | goto out; |
| 927 | |||
| 928 | sprintf(uevent_env[2], "%s%s", BATADV_UEV_DATA_VAR, data); | ||
| 929 | } | 921 | } |
| 930 | 922 | ||
| 931 | ret = kobject_uevent_env(bat_kobj, KOBJ_CHANGE, uevent_env); | 923 | ret = kobject_uevent_env(bat_kobj, KOBJ_CHANGE, uevent_env); |
diff --git a/net/bluetooth/6lowpan.c b/net/bluetooth/6lowpan.c index 8796ffa08b43..206b65ccd5b8 100644 --- a/net/bluetooth/6lowpan.c +++ b/net/bluetooth/6lowpan.c | |||
| @@ -1,5 +1,5 @@ | |||
| 1 | /* | 1 | /* |
| 2 | Copyright (c) 2013 Intel Corp. | 2 | Copyright (c) 2013-2014 Intel Corp. |
| 3 | 3 | ||
| 4 | This program is free software; you can redistribute it and/or modify | 4 | This program is free software; you can redistribute it and/or modify |
| 5 | it under the terms of the GNU General Public License version 2 and | 5 | it under the terms of the GNU General Public License version 2 and |
| @@ -14,6 +14,8 @@ | |||
| 14 | #include <linux/if_arp.h> | 14 | #include <linux/if_arp.h> |
| 15 | #include <linux/netdevice.h> | 15 | #include <linux/netdevice.h> |
| 16 | #include <linux/etherdevice.h> | 16 | #include <linux/etherdevice.h> |
| 17 | #include <linux/module.h> | ||
| 18 | #include <linux/debugfs.h> | ||
| 17 | 19 | ||
| 18 | #include <net/ipv6.h> | 20 | #include <net/ipv6.h> |
| 19 | #include <net/ip6_route.h> | 21 | #include <net/ip6_route.h> |
| @@ -25,16 +27,20 @@ | |||
| 25 | #include <net/bluetooth/hci_core.h> | 27 | #include <net/bluetooth/hci_core.h> |
| 26 | #include <net/bluetooth/l2cap.h> | 28 | #include <net/bluetooth/l2cap.h> |
| 27 | 29 | ||
| 28 | #include "6lowpan.h" | ||
| 29 | |||
| 30 | #include <net/6lowpan.h> /* for the compression support */ | 30 | #include <net/6lowpan.h> /* for the compression support */ |
| 31 | 31 | ||
| 32 | #define VERSION "0.1" | ||
| 33 | |||
| 34 | static struct dentry *lowpan_psm_debugfs; | ||
| 35 | static struct dentry *lowpan_control_debugfs; | ||
| 36 | |||
| 32 | #define IFACE_NAME_TEMPLATE "bt%d" | 37 | #define IFACE_NAME_TEMPLATE "bt%d" |
| 33 | #define EUI64_ADDR_LEN 8 | 38 | #define EUI64_ADDR_LEN 8 |
| 34 | 39 | ||
| 35 | struct skb_cb { | 40 | struct skb_cb { |
| 36 | struct in6_addr addr; | 41 | struct in6_addr addr; |
| 37 | struct l2cap_conn *conn; | 42 | struct l2cap_chan *chan; |
| 43 | int status; | ||
| 38 | }; | 44 | }; |
| 39 | #define lowpan_cb(skb) ((struct skb_cb *)((skb)->cb)) | 45 | #define lowpan_cb(skb) ((struct skb_cb *)((skb)->cb)) |
| 40 | 46 | ||
| @@ -48,9 +54,19 @@ struct skb_cb { | |||
| 48 | static LIST_HEAD(bt_6lowpan_devices); | 54 | static LIST_HEAD(bt_6lowpan_devices); |
| 49 | static DEFINE_RWLOCK(devices_lock); | 55 | static DEFINE_RWLOCK(devices_lock); |
| 50 | 56 | ||
| 57 | /* If psm is set to 0 (default value), then 6lowpan is disabled. | ||
| 58 | * Other values are used to indicate a Protocol Service Multiplexer | ||
| 59 | * value for 6lowpan. | ||
| 60 | */ | ||
| 61 | static u16 psm_6lowpan; | ||
| 62 | |||
| 63 | /* We are listening incoming connections via this channel | ||
| 64 | */ | ||
| 65 | static struct l2cap_chan *listen_chan; | ||
| 66 | |||
| 51 | struct lowpan_peer { | 67 | struct lowpan_peer { |
| 52 | struct list_head list; | 68 | struct list_head list; |
| 53 | struct l2cap_conn *conn; | 69 | struct l2cap_chan *chan; |
| 54 | 70 | ||
| 55 | /* peer addresses in various formats */ | 71 | /* peer addresses in various formats */ |
| 56 | unsigned char eui64_addr[EUI64_ADDR_LEN]; | 72 | unsigned char eui64_addr[EUI64_ADDR_LEN]; |
| @@ -84,6 +100,8 @@ static inline bool peer_del(struct lowpan_dev *dev, struct lowpan_peer *peer) | |||
| 84 | { | 100 | { |
| 85 | list_del(&peer->list); | 101 | list_del(&peer->list); |
| 86 | 102 | ||
| 103 | module_put(THIS_MODULE); | ||
| 104 | |||
| 87 | if (atomic_dec_and_test(&dev->peer_count)) { | 105 | if (atomic_dec_and_test(&dev->peer_count)) { |
| 88 | BT_DBG("last peer"); | 106 | BT_DBG("last peer"); |
| 89 | return true; | 107 | return true; |
| @@ -101,13 +119,26 @@ static inline struct lowpan_peer *peer_lookup_ba(struct lowpan_dev *dev, | |||
| 101 | ba, type); | 119 | ba, type); |
| 102 | 120 | ||
| 103 | list_for_each_entry_safe(peer, tmp, &dev->peers, list) { | 121 | list_for_each_entry_safe(peer, tmp, &dev->peers, list) { |
| 104 | BT_DBG("addr %pMR type %d", | 122 | BT_DBG("dst addr %pMR dst type %d", |
| 105 | &peer->conn->hcon->dst, peer->conn->hcon->dst_type); | 123 | &peer->chan->dst, peer->chan->dst_type); |
| 106 | 124 | ||
| 107 | if (bacmp(&peer->conn->hcon->dst, ba)) | 125 | if (bacmp(&peer->chan->dst, ba)) |
| 108 | continue; | 126 | continue; |
| 109 | 127 | ||
| 110 | if (type == peer->conn->hcon->dst_type) | 128 | if (type == peer->chan->dst_type) |
| 129 | return peer; | ||
| 130 | } | ||
| 131 | |||
| 132 | return NULL; | ||
| 133 | } | ||
| 134 | |||
| 135 | static inline struct lowpan_peer *peer_lookup_chan(struct lowpan_dev *dev, | ||
| 136 | struct l2cap_chan *chan) | ||
| 137 | { | ||
| 138 | struct lowpan_peer *peer, *tmp; | ||
| 139 | |||
| 140 | list_for_each_entry_safe(peer, tmp, &dev->peers, list) { | ||
| 141 | if (peer->chan == chan) | ||
| 111 | return peer; | 142 | return peer; |
| 112 | } | 143 | } |
| 113 | 144 | ||
| @@ -120,7 +151,7 @@ static inline struct lowpan_peer *peer_lookup_conn(struct lowpan_dev *dev, | |||
| 120 | struct lowpan_peer *peer, *tmp; | 151 | struct lowpan_peer *peer, *tmp; |
| 121 | 152 | ||
| 122 | list_for_each_entry_safe(peer, tmp, &dev->peers, list) { | 153 | list_for_each_entry_safe(peer, tmp, &dev->peers, list) { |
| 123 | if (peer->conn == conn) | 154 | if (peer->chan->conn == conn) |
| 124 | return peer; | 155 | return peer; |
| 125 | } | 156 | } |
| 126 | 157 | ||
| @@ -176,16 +207,16 @@ static int give_skb_to_upper(struct sk_buff *skb, struct net_device *dev) | |||
| 176 | return -ENOMEM; | 207 | return -ENOMEM; |
| 177 | 208 | ||
| 178 | ret = netif_rx(skb_cp); | 209 | ret = netif_rx(skb_cp); |
| 179 | 210 | if (ret < 0) { | |
| 180 | BT_DBG("receive skb %d", ret); | 211 | BT_DBG("receive skb %d", ret); |
| 181 | if (ret < 0) | ||
| 182 | return NET_RX_DROP; | 212 | return NET_RX_DROP; |
| 213 | } | ||
| 183 | 214 | ||
| 184 | return ret; | 215 | return ret; |
| 185 | } | 216 | } |
| 186 | 217 | ||
| 187 | static int process_data(struct sk_buff *skb, struct net_device *netdev, | 218 | static int process_data(struct sk_buff *skb, struct net_device *netdev, |
| 188 | struct l2cap_conn *conn) | 219 | struct l2cap_chan *chan) |
| 189 | { | 220 | { |
| 190 | const u8 *saddr, *daddr; | 221 | const u8 *saddr, *daddr; |
| 191 | u8 iphc0, iphc1; | 222 | u8 iphc0, iphc1; |
| @@ -196,7 +227,7 @@ static int process_data(struct sk_buff *skb, struct net_device *netdev, | |||
| 196 | dev = lowpan_dev(netdev); | 227 | dev = lowpan_dev(netdev); |
| 197 | 228 | ||
| 198 | read_lock_irqsave(&devices_lock, flags); | 229 | read_lock_irqsave(&devices_lock, flags); |
| 199 | peer = peer_lookup_conn(dev, conn); | 230 | peer = peer_lookup_chan(dev, chan); |
| 200 | read_unlock_irqrestore(&devices_lock, flags); | 231 | read_unlock_irqrestore(&devices_lock, flags); |
| 201 | if (!peer) | 232 | if (!peer) |
| 202 | goto drop; | 233 | goto drop; |
| @@ -225,7 +256,7 @@ drop: | |||
| 225 | } | 256 | } |
| 226 | 257 | ||
| 227 | static int recv_pkt(struct sk_buff *skb, struct net_device *dev, | 258 | static int recv_pkt(struct sk_buff *skb, struct net_device *dev, |
| 228 | struct l2cap_conn *conn) | 259 | struct l2cap_chan *chan) |
| 229 | { | 260 | { |
| 230 | struct sk_buff *local_skb; | 261 | struct sk_buff *local_skb; |
| 231 | int ret; | 262 | int ret; |
| @@ -269,7 +300,7 @@ static int recv_pkt(struct sk_buff *skb, struct net_device *dev, | |||
| 269 | if (!local_skb) | 300 | if (!local_skb) |
| 270 | goto drop; | 301 | goto drop; |
| 271 | 302 | ||
| 272 | ret = process_data(local_skb, dev, conn); | 303 | ret = process_data(local_skb, dev, chan); |
| 273 | if (ret != NET_RX_SUCCESS) | 304 | if (ret != NET_RX_SUCCESS) |
| 274 | goto drop; | 305 | goto drop; |
| 275 | 306 | ||
| @@ -286,147 +317,39 @@ static int recv_pkt(struct sk_buff *skb, struct net_device *dev, | |||
| 286 | return NET_RX_SUCCESS; | 317 | return NET_RX_SUCCESS; |
| 287 | 318 | ||
| 288 | drop: | 319 | drop: |
| 320 | dev->stats.rx_dropped++; | ||
| 289 | kfree_skb(skb); | 321 | kfree_skb(skb); |
| 290 | return NET_RX_DROP; | 322 | return NET_RX_DROP; |
| 291 | } | 323 | } |
| 292 | 324 | ||
| 293 | /* Packet from BT LE device */ | 325 | /* Packet from BT LE device */ |
| 294 | int bt_6lowpan_recv(struct l2cap_conn *conn, struct sk_buff *skb) | 326 | static int chan_recv_cb(struct l2cap_chan *chan, struct sk_buff *skb) |
| 295 | { | 327 | { |
| 296 | struct lowpan_dev *dev; | 328 | struct lowpan_dev *dev; |
| 297 | struct lowpan_peer *peer; | 329 | struct lowpan_peer *peer; |
| 298 | int err; | 330 | int err; |
| 299 | 331 | ||
| 300 | peer = lookup_peer(conn); | 332 | peer = lookup_peer(chan->conn); |
| 301 | if (!peer) | 333 | if (!peer) |
| 302 | return -ENOENT; | 334 | return -ENOENT; |
| 303 | 335 | ||
| 304 | dev = lookup_dev(conn); | 336 | dev = lookup_dev(chan->conn); |
| 305 | if (!dev || !dev->netdev) | 337 | if (!dev || !dev->netdev) |
| 306 | return -ENOENT; | 338 | return -ENOENT; |
| 307 | 339 | ||
| 308 | err = recv_pkt(skb, dev->netdev, conn); | 340 | err = recv_pkt(skb, dev->netdev, chan); |
| 309 | BT_DBG("recv pkt %d", err); | 341 | if (err) { |
| 310 | 342 | BT_DBG("recv pkt %d", err); | |
| 311 | return err; | 343 | err = -EAGAIN; |
| 312 | } | ||
| 313 | |||
| 314 | static inline int skbuff_copy(void *msg, int len, int count, int mtu, | ||
| 315 | struct sk_buff *skb, struct net_device *dev) | ||
| 316 | { | ||
| 317 | struct sk_buff **frag; | ||
| 318 | int sent = 0; | ||
| 319 | |||
| 320 | memcpy(skb_put(skb, count), msg, count); | ||
| 321 | |||
| 322 | sent += count; | ||
| 323 | msg += count; | ||
| 324 | len -= count; | ||
| 325 | |||
| 326 | dev->stats.tx_bytes += count; | ||
| 327 | dev->stats.tx_packets++; | ||
| 328 | |||
| 329 | raw_dump_table(__func__, "Sending", skb->data, skb->len); | ||
| 330 | |||
| 331 | /* Continuation fragments (no L2CAP header) */ | ||
| 332 | frag = &skb_shinfo(skb)->frag_list; | ||
| 333 | while (len > 0) { | ||
| 334 | struct sk_buff *tmp; | ||
| 335 | |||
| 336 | count = min_t(unsigned int, mtu, len); | ||
| 337 | |||
| 338 | tmp = bt_skb_alloc(count, GFP_ATOMIC); | ||
| 339 | if (!tmp) | ||
| 340 | return -ENOMEM; | ||
| 341 | |||
| 342 | *frag = tmp; | ||
| 343 | |||
| 344 | memcpy(skb_put(*frag, count), msg, count); | ||
| 345 | |||
| 346 | raw_dump_table(__func__, "Sending fragment", | ||
| 347 | (*frag)->data, count); | ||
| 348 | |||
| 349 | (*frag)->priority = skb->priority; | ||
| 350 | |||
| 351 | sent += count; | ||
| 352 | msg += count; | ||
| 353 | len -= count; | ||
| 354 | |||
| 355 | skb->len += (*frag)->len; | ||
| 356 | skb->data_len += (*frag)->len; | ||
| 357 | |||
| 358 | frag = &(*frag)->next; | ||
| 359 | |||
| 360 | dev->stats.tx_bytes += count; | ||
| 361 | dev->stats.tx_packets++; | ||
| 362 | } | 344 | } |
| 363 | 345 | ||
| 364 | return sent; | 346 | return err; |
| 365 | } | ||
| 366 | |||
| 367 | static struct sk_buff *create_pdu(struct l2cap_conn *conn, void *msg, | ||
| 368 | size_t len, u32 priority, | ||
| 369 | struct net_device *dev) | ||
| 370 | { | ||
| 371 | struct sk_buff *skb; | ||
| 372 | int err, count; | ||
| 373 | struct l2cap_hdr *lh; | ||
| 374 | |||
| 375 | /* FIXME: This mtu check should be not needed and atm is only used for | ||
| 376 | * testing purposes | ||
| 377 | */ | ||
| 378 | if (conn->mtu > (L2CAP_LE_MIN_MTU + L2CAP_HDR_SIZE)) | ||
| 379 | conn->mtu = L2CAP_LE_MIN_MTU + L2CAP_HDR_SIZE; | ||
| 380 | |||
| 381 | count = min_t(unsigned int, (conn->mtu - L2CAP_HDR_SIZE), len); | ||
| 382 | |||
| 383 | BT_DBG("conn %p len %zu mtu %d count %d", conn, len, conn->mtu, count); | ||
| 384 | |||
| 385 | skb = bt_skb_alloc(count + L2CAP_HDR_SIZE, GFP_ATOMIC); | ||
| 386 | if (!skb) | ||
| 387 | return ERR_PTR(-ENOMEM); | ||
| 388 | |||
| 389 | skb->priority = priority; | ||
| 390 | |||
| 391 | lh = (struct l2cap_hdr *)skb_put(skb, L2CAP_HDR_SIZE); | ||
| 392 | lh->cid = cpu_to_le16(L2CAP_FC_6LOWPAN); | ||
| 393 | lh->len = cpu_to_le16(len); | ||
| 394 | |||
| 395 | err = skbuff_copy(msg, len, count, conn->mtu, skb, dev); | ||
| 396 | if (unlikely(err < 0)) { | ||
| 397 | kfree_skb(skb); | ||
| 398 | BT_DBG("skbuff copy %d failed", err); | ||
| 399 | return ERR_PTR(err); | ||
| 400 | } | ||
| 401 | |||
| 402 | return skb; | ||
| 403 | } | ||
| 404 | |||
| 405 | static int conn_send(struct l2cap_conn *conn, | ||
| 406 | void *msg, size_t len, u32 priority, | ||
| 407 | struct net_device *dev) | ||
| 408 | { | ||
| 409 | struct sk_buff *skb; | ||
| 410 | |||
| 411 | skb = create_pdu(conn, msg, len, priority, dev); | ||
| 412 | if (IS_ERR(skb)) | ||
| 413 | return -EINVAL; | ||
| 414 | |||
| 415 | BT_DBG("conn %p skb %p len %d priority %u", conn, skb, skb->len, | ||
| 416 | skb->priority); | ||
| 417 | |||
| 418 | hci_send_acl(conn->hchan, skb, ACL_START); | ||
| 419 | |||
| 420 | return 0; | ||
| 421 | } | 347 | } |
| 422 | 348 | ||
| 423 | static u8 get_addr_type_from_eui64(u8 byte) | 349 | static u8 get_addr_type_from_eui64(u8 byte) |
| 424 | { | 350 | { |
| 425 | /* Is universal(0) or local(1) bit, */ | 351 | /* Is universal(0) or local(1) bit */ |
| 426 | if (byte & 0x02) | 352 | return ((byte & 0x02) ? BDADDR_LE_RANDOM : BDADDR_LE_PUBLIC); |
| 427 | return ADDR_LE_DEV_RANDOM; | ||
| 428 | |||
| 429 | return ADDR_LE_DEV_PUBLIC; | ||
| 430 | } | 353 | } |
| 431 | 354 | ||
| 432 | static void copy_to_bdaddr(struct in6_addr *ip6_daddr, bdaddr_t *addr) | 355 | static void copy_to_bdaddr(struct in6_addr *ip6_daddr, bdaddr_t *addr) |
| @@ -475,7 +398,7 @@ static int header_create(struct sk_buff *skb, struct net_device *netdev, | |||
| 475 | if (ipv6_addr_is_multicast(&hdr->daddr)) { | 398 | if (ipv6_addr_is_multicast(&hdr->daddr)) { |
| 476 | memcpy(&lowpan_cb(skb)->addr, &hdr->daddr, | 399 | memcpy(&lowpan_cb(skb)->addr, &hdr->daddr, |
| 477 | sizeof(struct in6_addr)); | 400 | sizeof(struct in6_addr)); |
| 478 | lowpan_cb(skb)->conn = NULL; | 401 | lowpan_cb(skb)->chan = NULL; |
| 479 | } else { | 402 | } else { |
| 480 | unsigned long flags; | 403 | unsigned long flags; |
| 481 | 404 | ||
| @@ -484,9 +407,8 @@ static int header_create(struct sk_buff *skb, struct net_device *netdev, | |||
| 484 | */ | 407 | */ |
| 485 | convert_dest_bdaddr(&hdr->daddr, &addr, &addr_type); | 408 | convert_dest_bdaddr(&hdr->daddr, &addr, &addr_type); |
| 486 | 409 | ||
| 487 | BT_DBG("dest addr %pMR type %s IP %pI6c", &addr, | 410 | BT_DBG("dest addr %pMR type %d IP %pI6c", &addr, |
| 488 | addr_type == ADDR_LE_DEV_PUBLIC ? "PUBLIC" : "RANDOM", | 411 | addr_type, &hdr->daddr); |
| 489 | &hdr->daddr); | ||
| 490 | 412 | ||
| 491 | read_lock_irqsave(&devices_lock, flags); | 413 | read_lock_irqsave(&devices_lock, flags); |
| 492 | peer = peer_lookup_ba(dev, &addr, addr_type); | 414 | peer = peer_lookup_ba(dev, &addr, addr_type); |
| @@ -501,7 +423,7 @@ static int header_create(struct sk_buff *skb, struct net_device *netdev, | |||
| 501 | 423 | ||
| 502 | memcpy(&lowpan_cb(skb)->addr, &hdr->daddr, | 424 | memcpy(&lowpan_cb(skb)->addr, &hdr->daddr, |
| 503 | sizeof(struct in6_addr)); | 425 | sizeof(struct in6_addr)); |
| 504 | lowpan_cb(skb)->conn = peer->conn; | 426 | lowpan_cb(skb)->chan = peer->chan; |
| 505 | } | 427 | } |
| 506 | 428 | ||
| 507 | saddr = dev->netdev->dev_addr; | 429 | saddr = dev->netdev->dev_addr; |
| @@ -510,14 +432,42 @@ static int header_create(struct sk_buff *skb, struct net_device *netdev, | |||
| 510 | } | 432 | } |
| 511 | 433 | ||
| 512 | /* Packet to BT LE device */ | 434 | /* Packet to BT LE device */ |
| 513 | static int send_pkt(struct l2cap_conn *conn, const void *saddr, | 435 | static int send_pkt(struct l2cap_chan *chan, struct sk_buff *skb, |
| 514 | const void *daddr, struct sk_buff *skb, | ||
| 515 | struct net_device *netdev) | 436 | struct net_device *netdev) |
| 516 | { | 437 | { |
| 517 | raw_dump_table(__func__, "raw skb data dump before fragmentation", | 438 | struct msghdr msg; |
| 518 | skb->data, skb->len); | 439 | struct kvec iv; |
| 440 | int err; | ||
| 441 | |||
| 442 | /* Remember the skb so that we can send EAGAIN to the caller if | ||
| 443 | * we run out of credits. | ||
| 444 | */ | ||
| 445 | chan->data = skb; | ||
| 446 | |||
| 447 | memset(&msg, 0, sizeof(msg)); | ||
| 448 | msg.msg_iov = (struct iovec *) &iv; | ||
| 449 | msg.msg_iovlen = 1; | ||
| 450 | iv.iov_base = skb->data; | ||
| 451 | iv.iov_len = skb->len; | ||
| 452 | |||
| 453 | err = l2cap_chan_send(chan, &msg, skb->len); | ||
| 454 | if (err > 0) { | ||
| 455 | netdev->stats.tx_bytes += err; | ||
| 456 | netdev->stats.tx_packets++; | ||
| 457 | return 0; | ||
| 458 | } | ||
| 459 | |||
| 460 | if (!err) | ||
| 461 | err = lowpan_cb(skb)->status; | ||
| 519 | 462 | ||
| 520 | return conn_send(conn, skb->data, skb->len, 0, netdev); | 463 | if (err < 0) { |
| 464 | if (err == -EAGAIN) | ||
| 465 | netdev->stats.tx_dropped++; | ||
| 466 | else | ||
| 467 | netdev->stats.tx_errors++; | ||
| 468 | } | ||
| 469 | |||
| 470 | return err; | ||
| 521 | } | 471 | } |
| 522 | 472 | ||
| 523 | static void send_mcast_pkt(struct sk_buff *skb, struct net_device *netdev) | 473 | static void send_mcast_pkt(struct sk_buff *skb, struct net_device *netdev) |
| @@ -540,8 +490,7 @@ static void send_mcast_pkt(struct sk_buff *skb, struct net_device *netdev) | |||
| 540 | list_for_each_entry_safe(pentry, ptmp, &dev->peers, list) { | 490 | list_for_each_entry_safe(pentry, ptmp, &dev->peers, list) { |
| 541 | local_skb = skb_clone(skb, GFP_ATOMIC); | 491 | local_skb = skb_clone(skb, GFP_ATOMIC); |
| 542 | 492 | ||
| 543 | send_pkt(pentry->conn, netdev->dev_addr, | 493 | send_pkt(pentry->chan, local_skb, netdev); |
| 544 | pentry->eui64_addr, local_skb, netdev); | ||
| 545 | 494 | ||
| 546 | kfree_skb(local_skb); | 495 | kfree_skb(local_skb); |
| 547 | } | 496 | } |
| @@ -553,7 +502,6 @@ static void send_mcast_pkt(struct sk_buff *skb, struct net_device *netdev) | |||
| 553 | static netdev_tx_t bt_xmit(struct sk_buff *skb, struct net_device *netdev) | 502 | static netdev_tx_t bt_xmit(struct sk_buff *skb, struct net_device *netdev) |
| 554 | { | 503 | { |
| 555 | int err = 0; | 504 | int err = 0; |
| 556 | unsigned char *eui64_addr; | ||
| 557 | struct lowpan_dev *dev; | 505 | struct lowpan_dev *dev; |
| 558 | struct lowpan_peer *peer; | 506 | struct lowpan_peer *peer; |
| 559 | bdaddr_t addr; | 507 | bdaddr_t addr; |
| @@ -568,21 +516,20 @@ static netdev_tx_t bt_xmit(struct sk_buff *skb, struct net_device *netdev) | |||
| 568 | unsigned long flags; | 516 | unsigned long flags; |
| 569 | 517 | ||
| 570 | convert_dest_bdaddr(&lowpan_cb(skb)->addr, &addr, &addr_type); | 518 | convert_dest_bdaddr(&lowpan_cb(skb)->addr, &addr, &addr_type); |
| 571 | eui64_addr = lowpan_cb(skb)->addr.s6_addr + 8; | ||
| 572 | dev = lowpan_dev(netdev); | 519 | dev = lowpan_dev(netdev); |
| 573 | 520 | ||
| 574 | read_lock_irqsave(&devices_lock, flags); | 521 | read_lock_irqsave(&devices_lock, flags); |
| 575 | peer = peer_lookup_ba(dev, &addr, addr_type); | 522 | peer = peer_lookup_ba(dev, &addr, addr_type); |
| 576 | read_unlock_irqrestore(&devices_lock, flags); | 523 | read_unlock_irqrestore(&devices_lock, flags); |
| 577 | 524 | ||
| 578 | BT_DBG("xmit %s to %pMR type %s IP %pI6c peer %p", | 525 | BT_DBG("xmit %s to %pMR type %d IP %pI6c peer %p", |
| 579 | netdev->name, &addr, | 526 | netdev->name, &addr, addr_type, |
| 580 | addr_type == ADDR_LE_DEV_PUBLIC ? "PUBLIC" : "RANDOM", | ||
| 581 | &lowpan_cb(skb)->addr, peer); | 527 | &lowpan_cb(skb)->addr, peer); |
| 582 | 528 | ||
| 583 | if (peer && peer->conn) | 529 | if (peer && peer->chan) |
| 584 | err = send_pkt(peer->conn, netdev->dev_addr, | 530 | err = send_pkt(peer->chan, skb, netdev); |
| 585 | eui64_addr, skb, netdev); | 531 | else |
| 532 | err = -ENOENT; | ||
| 586 | } | 533 | } |
| 587 | dev_kfree_skb(skb); | 534 | dev_kfree_skb(skb); |
| 588 | 535 | ||
| @@ -634,7 +581,7 @@ static void set_addr(u8 *eui, u8 *addr, u8 addr_type) | |||
| 634 | eui[7] = addr[0]; | 581 | eui[7] = addr[0]; |
| 635 | 582 | ||
| 636 | /* Universal/local bit set, BT 6lowpan draft ch. 3.2.1 */ | 583 | /* Universal/local bit set, BT 6lowpan draft ch. 3.2.1 */ |
| 637 | if (addr_type == ADDR_LE_DEV_PUBLIC) | 584 | if (addr_type == BDADDR_LE_PUBLIC) |
| 638 | eui[0] &= ~0x02; | 585 | eui[0] &= ~0x02; |
| 639 | else | 586 | else |
| 640 | eui[0] |= 0x02; | 587 | eui[0] |= 0x02; |
| @@ -660,6 +607,17 @@ static void ifup(struct net_device *netdev) | |||
| 660 | rtnl_unlock(); | 607 | rtnl_unlock(); |
| 661 | } | 608 | } |
| 662 | 609 | ||
| 610 | static void ifdown(struct net_device *netdev) | ||
| 611 | { | ||
| 612 | int err; | ||
| 613 | |||
| 614 | rtnl_lock(); | ||
| 615 | err = dev_close(netdev); | ||
| 616 | if (err < 0) | ||
| 617 | BT_INFO("iface %s cannot be closed (%d)", netdev->name, err); | ||
| 618 | rtnl_unlock(); | ||
| 619 | } | ||
| 620 | |||
| 663 | static void do_notify_peers(struct work_struct *work) | 621 | static void do_notify_peers(struct work_struct *work) |
| 664 | { | 622 | { |
| 665 | struct lowpan_dev *dev = container_of(work, struct lowpan_dev, | 623 | struct lowpan_dev *dev = container_of(work, struct lowpan_dev, |
| @@ -673,26 +631,64 @@ static bool is_bt_6lowpan(struct hci_conn *hcon) | |||
| 673 | if (hcon->type != LE_LINK) | 631 | if (hcon->type != LE_LINK) |
| 674 | return false; | 632 | return false; |
| 675 | 633 | ||
| 676 | return test_bit(HCI_CONN_6LOWPAN, &hcon->flags); | 634 | if (!psm_6lowpan) |
| 635 | return false; | ||
| 636 | |||
| 637 | return true; | ||
| 638 | } | ||
| 639 | |||
| 640 | static struct l2cap_chan *chan_create(void) | ||
| 641 | { | ||
| 642 | struct l2cap_chan *chan; | ||
| 643 | |||
| 644 | chan = l2cap_chan_create(); | ||
| 645 | if (!chan) | ||
| 646 | return NULL; | ||
| 647 | |||
| 648 | l2cap_chan_set_defaults(chan); | ||
| 649 | |||
| 650 | chan->chan_type = L2CAP_CHAN_CONN_ORIENTED; | ||
| 651 | chan->mode = L2CAP_MODE_LE_FLOWCTL; | ||
| 652 | chan->omtu = 65535; | ||
| 653 | chan->imtu = chan->omtu; | ||
| 654 | |||
| 655 | return chan; | ||
| 677 | } | 656 | } |
| 678 | 657 | ||
| 679 | static int add_peer_conn(struct l2cap_conn *conn, struct lowpan_dev *dev) | 658 | static struct l2cap_chan *chan_open(struct l2cap_chan *pchan) |
| 659 | { | ||
| 660 | struct l2cap_chan *chan; | ||
| 661 | |||
| 662 | chan = chan_create(); | ||
| 663 | if (!chan) | ||
| 664 | return NULL; | ||
| 665 | |||
| 666 | chan->remote_mps = chan->omtu; | ||
| 667 | chan->mps = chan->omtu; | ||
| 668 | |||
| 669 | chan->state = BT_CONNECTED; | ||
| 670 | |||
| 671 | return chan; | ||
| 672 | } | ||
| 673 | |||
| 674 | static struct l2cap_chan *add_peer_chan(struct l2cap_chan *chan, | ||
| 675 | struct lowpan_dev *dev) | ||
| 680 | { | 676 | { |
| 681 | struct lowpan_peer *peer; | 677 | struct lowpan_peer *peer; |
| 682 | unsigned long flags; | 678 | unsigned long flags; |
| 683 | 679 | ||
| 684 | peer = kzalloc(sizeof(*peer), GFP_ATOMIC); | 680 | peer = kzalloc(sizeof(*peer), GFP_ATOMIC); |
| 685 | if (!peer) | 681 | if (!peer) |
| 686 | return -ENOMEM; | 682 | return NULL; |
| 687 | 683 | ||
| 688 | peer->conn = conn; | 684 | peer->chan = chan; |
| 689 | memset(&peer->peer_addr, 0, sizeof(struct in6_addr)); | 685 | memset(&peer->peer_addr, 0, sizeof(struct in6_addr)); |
| 690 | 686 | ||
| 691 | /* RFC 2464 ch. 5 */ | 687 | /* RFC 2464 ch. 5 */ |
| 692 | peer->peer_addr.s6_addr[0] = 0xFE; | 688 | peer->peer_addr.s6_addr[0] = 0xFE; |
| 693 | peer->peer_addr.s6_addr[1] = 0x80; | 689 | peer->peer_addr.s6_addr[1] = 0x80; |
| 694 | set_addr((u8 *)&peer->peer_addr.s6_addr + 8, conn->hcon->dst.b, | 690 | set_addr((u8 *)&peer->peer_addr.s6_addr + 8, chan->dst.b, |
| 695 | conn->hcon->dst_type); | 691 | chan->dst_type); |
| 696 | 692 | ||
| 697 | memcpy(&peer->eui64_addr, (u8 *)&peer->peer_addr.s6_addr + 8, | 693 | memcpy(&peer->eui64_addr, (u8 *)&peer->peer_addr.s6_addr + 8, |
| 698 | EUI64_ADDR_LEN); | 694 | EUI64_ADDR_LEN); |
| @@ -706,40 +702,24 @@ static int add_peer_conn(struct l2cap_conn *conn, struct lowpan_dev *dev) | |||
| 706 | INIT_DELAYED_WORK(&dev->notify_peers, do_notify_peers); | 702 | INIT_DELAYED_WORK(&dev->notify_peers, do_notify_peers); |
| 707 | schedule_delayed_work(&dev->notify_peers, msecs_to_jiffies(100)); | 703 | schedule_delayed_work(&dev->notify_peers, msecs_to_jiffies(100)); |
| 708 | 704 | ||
| 709 | return 0; | 705 | return peer->chan; |
| 710 | } | 706 | } |
| 711 | 707 | ||
| 712 | /* This gets called when BT LE 6LoWPAN device is connected. We then | 708 | static int setup_netdev(struct l2cap_chan *chan, struct lowpan_dev **dev) |
| 713 | * create network device that acts as a proxy between BT LE device | ||
| 714 | * and kernel network stack. | ||
| 715 | */ | ||
| 716 | int bt_6lowpan_add_conn(struct l2cap_conn *conn) | ||
| 717 | { | 709 | { |
| 718 | struct lowpan_peer *peer = NULL; | ||
| 719 | struct lowpan_dev *dev; | ||
| 720 | struct net_device *netdev; | 710 | struct net_device *netdev; |
| 721 | int err = 0; | 711 | int err = 0; |
| 722 | unsigned long flags; | 712 | unsigned long flags; |
| 723 | 713 | ||
| 724 | if (!is_bt_6lowpan(conn->hcon)) | 714 | netdev = alloc_netdev(sizeof(struct lowpan_dev), IFACE_NAME_TEMPLATE, |
| 725 | return 0; | 715 | NET_NAME_UNKNOWN, netdev_setup); |
| 726 | |||
| 727 | peer = lookup_peer(conn); | ||
| 728 | if (peer) | ||
| 729 | return -EEXIST; | ||
| 730 | |||
| 731 | dev = lookup_dev(conn); | ||
| 732 | if (dev) | ||
| 733 | return add_peer_conn(conn, dev); | ||
| 734 | |||
| 735 | netdev = alloc_netdev(sizeof(*dev), IFACE_NAME_TEMPLATE, netdev_setup); | ||
| 736 | if (!netdev) | 716 | if (!netdev) |
| 737 | return -ENOMEM; | 717 | return -ENOMEM; |
| 738 | 718 | ||
| 739 | set_dev_addr(netdev, &conn->hcon->src, conn->hcon->src_type); | 719 | set_dev_addr(netdev, &chan->src, chan->src_type); |
| 740 | 720 | ||
| 741 | netdev->netdev_ops = &netdev_ops; | 721 | netdev->netdev_ops = &netdev_ops; |
| 742 | SET_NETDEV_DEV(netdev, &conn->hcon->dev); | 722 | SET_NETDEV_DEV(netdev, &chan->conn->hcon->dev); |
| 743 | SET_NETDEV_DEVTYPE(netdev, &bt_type); | 723 | SET_NETDEV_DEVTYPE(netdev, &bt_type); |
| 744 | 724 | ||
| 745 | err = register_netdev(netdev); | 725 | err = register_netdev(netdev); |
| @@ -749,28 +729,61 @@ int bt_6lowpan_add_conn(struct l2cap_conn *conn) | |||
| 749 | goto out; | 729 | goto out; |
| 750 | } | 730 | } |
| 751 | 731 | ||
| 752 | BT_DBG("ifindex %d peer bdaddr %pMR my addr %pMR", | 732 | BT_DBG("ifindex %d peer bdaddr %pMR type %d my addr %pMR type %d", |
| 753 | netdev->ifindex, &conn->hcon->dst, &conn->hcon->src); | 733 | netdev->ifindex, &chan->dst, chan->dst_type, |
| 734 | &chan->src, chan->src_type); | ||
| 754 | set_bit(__LINK_STATE_PRESENT, &netdev->state); | 735 | set_bit(__LINK_STATE_PRESENT, &netdev->state); |
| 755 | 736 | ||
| 756 | dev = netdev_priv(netdev); | 737 | *dev = netdev_priv(netdev); |
| 757 | dev->netdev = netdev; | 738 | (*dev)->netdev = netdev; |
| 758 | dev->hdev = conn->hcon->hdev; | 739 | (*dev)->hdev = chan->conn->hcon->hdev; |
| 759 | INIT_LIST_HEAD(&dev->peers); | 740 | INIT_LIST_HEAD(&(*dev)->peers); |
| 760 | 741 | ||
| 761 | write_lock_irqsave(&devices_lock, flags); | 742 | write_lock_irqsave(&devices_lock, flags); |
| 762 | INIT_LIST_HEAD(&dev->list); | 743 | INIT_LIST_HEAD(&(*dev)->list); |
| 763 | list_add(&dev->list, &bt_6lowpan_devices); | 744 | list_add(&(*dev)->list, &bt_6lowpan_devices); |
| 764 | write_unlock_irqrestore(&devices_lock, flags); | 745 | write_unlock_irqrestore(&devices_lock, flags); |
| 765 | 746 | ||
| 766 | ifup(netdev); | 747 | return 0; |
| 767 | |||
| 768 | return add_peer_conn(conn, dev); | ||
| 769 | 748 | ||
| 770 | out: | 749 | out: |
| 771 | return err; | 750 | return err; |
| 772 | } | 751 | } |
| 773 | 752 | ||
| 753 | static inline void chan_ready_cb(struct l2cap_chan *chan) | ||
| 754 | { | ||
| 755 | struct lowpan_dev *dev; | ||
| 756 | |||
| 757 | dev = lookup_dev(chan->conn); | ||
| 758 | |||
| 759 | BT_DBG("chan %p conn %p dev %p", chan, chan->conn, dev); | ||
| 760 | |||
| 761 | if (!dev) { | ||
| 762 | if (setup_netdev(chan, &dev) < 0) { | ||
| 763 | l2cap_chan_del(chan, -ENOENT); | ||
| 764 | return; | ||
| 765 | } | ||
| 766 | } | ||
| 767 | |||
| 768 | if (!try_module_get(THIS_MODULE)) | ||
| 769 | return; | ||
| 770 | |||
| 771 | add_peer_chan(chan, dev); | ||
| 772 | ifup(dev->netdev); | ||
| 773 | } | ||
| 774 | |||
| 775 | static inline struct l2cap_chan *chan_new_conn_cb(struct l2cap_chan *chan) | ||
| 776 | { | ||
| 777 | struct l2cap_chan *pchan; | ||
| 778 | |||
| 779 | pchan = chan_open(chan); | ||
| 780 | pchan->ops = chan->ops; | ||
| 781 | |||
| 782 | BT_DBG("chan %p pchan %p", chan, pchan); | ||
| 783 | |||
| 784 | return pchan; | ||
| 785 | } | ||
| 786 | |||
| 774 | static void delete_netdev(struct work_struct *work) | 787 | static void delete_netdev(struct work_struct *work) |
| 775 | { | 788 | { |
| 776 | struct lowpan_dev *entry = container_of(work, struct lowpan_dev, | 789 | struct lowpan_dev *entry = container_of(work, struct lowpan_dev, |
| @@ -781,26 +794,43 @@ static void delete_netdev(struct work_struct *work) | |||
| 781 | /* The entry pointer is deleted in device_event() */ | 794 | /* The entry pointer is deleted in device_event() */ |
| 782 | } | 795 | } |
| 783 | 796 | ||
| 784 | int bt_6lowpan_del_conn(struct l2cap_conn *conn) | 797 | static void chan_close_cb(struct l2cap_chan *chan) |
| 785 | { | 798 | { |
| 786 | struct lowpan_dev *entry, *tmp; | 799 | struct lowpan_dev *entry, *tmp; |
| 787 | struct lowpan_dev *dev = NULL; | 800 | struct lowpan_dev *dev = NULL; |
| 788 | struct lowpan_peer *peer; | 801 | struct lowpan_peer *peer; |
| 789 | int err = -ENOENT; | 802 | int err = -ENOENT; |
| 790 | unsigned long flags; | 803 | unsigned long flags; |
| 791 | bool last = false; | 804 | bool last = false, removed = true; |
| 792 | 805 | ||
| 793 | if (!conn || !is_bt_6lowpan(conn->hcon)) | 806 | BT_DBG("chan %p conn %p", chan, chan->conn); |
| 794 | return 0; | 807 | |
| 808 | if (chan->conn && chan->conn->hcon) { | ||
| 809 | if (!is_bt_6lowpan(chan->conn->hcon)) | ||
| 810 | return; | ||
| 811 | |||
| 812 | /* If conn is set, then the netdev is also there and we should | ||
| 813 | * not remove it. | ||
| 814 | */ | ||
| 815 | removed = false; | ||
| 816 | } | ||
| 795 | 817 | ||
| 796 | write_lock_irqsave(&devices_lock, flags); | 818 | write_lock_irqsave(&devices_lock, flags); |
| 797 | 819 | ||
| 798 | list_for_each_entry_safe(entry, tmp, &bt_6lowpan_devices, list) { | 820 | list_for_each_entry_safe(entry, tmp, &bt_6lowpan_devices, list) { |
| 799 | dev = lowpan_dev(entry->netdev); | 821 | dev = lowpan_dev(entry->netdev); |
| 800 | peer = peer_lookup_conn(dev, conn); | 822 | peer = peer_lookup_chan(dev, chan); |
| 801 | if (peer) { | 823 | if (peer) { |
| 802 | last = peer_del(dev, peer); | 824 | last = peer_del(dev, peer); |
| 803 | err = 0; | 825 | err = 0; |
| 826 | |||
| 827 | BT_DBG("dev %p removing %speer %p", dev, | ||
| 828 | last ? "last " : "1 ", peer); | ||
| 829 | BT_DBG("chan %p orig refcnt %d", chan, | ||
| 830 | atomic_read(&chan->kref.refcount)); | ||
| 831 | |||
| 832 | l2cap_chan_put(chan); | ||
| 833 | kfree(peer); | ||
| 804 | break; | 834 | break; |
| 805 | } | 835 | } |
| 806 | } | 836 | } |
| @@ -810,18 +840,402 @@ int bt_6lowpan_del_conn(struct l2cap_conn *conn) | |||
| 810 | 840 | ||
| 811 | cancel_delayed_work_sync(&dev->notify_peers); | 841 | cancel_delayed_work_sync(&dev->notify_peers); |
| 812 | 842 | ||
| 813 | /* bt_6lowpan_del_conn() is called with hci dev lock held which | 843 | ifdown(dev->netdev); |
| 814 | * means that we must delete the netdevice in worker thread. | 844 | |
| 815 | */ | 845 | if (!removed) { |
| 816 | INIT_WORK(&entry->delete_netdev, delete_netdev); | 846 | INIT_WORK(&entry->delete_netdev, delete_netdev); |
| 817 | schedule_work(&entry->delete_netdev); | 847 | schedule_work(&entry->delete_netdev); |
| 848 | } | ||
| 818 | } else { | 849 | } else { |
| 819 | write_unlock_irqrestore(&devices_lock, flags); | 850 | write_unlock_irqrestore(&devices_lock, flags); |
| 820 | } | 851 | } |
| 821 | 852 | ||
| 853 | return; | ||
| 854 | } | ||
| 855 | |||
| 856 | static void chan_state_change_cb(struct l2cap_chan *chan, int state, int err) | ||
| 857 | { | ||
| 858 | BT_DBG("chan %p conn %p state %s err %d", chan, chan->conn, | ||
| 859 | state_to_string(state), err); | ||
| 860 | } | ||
| 861 | |||
| 862 | static struct sk_buff *chan_alloc_skb_cb(struct l2cap_chan *chan, | ||
| 863 | unsigned long hdr_len, | ||
| 864 | unsigned long len, int nb) | ||
| 865 | { | ||
| 866 | /* Note that we must allocate using GFP_ATOMIC here as | ||
| 867 | * this function is called originally from netdev hard xmit | ||
| 868 | * function in atomic context. | ||
| 869 | */ | ||
| 870 | return bt_skb_alloc(hdr_len + len, GFP_ATOMIC); | ||
| 871 | } | ||
| 872 | |||
| 873 | static void chan_suspend_cb(struct l2cap_chan *chan) | ||
| 874 | { | ||
| 875 | struct sk_buff *skb = chan->data; | ||
| 876 | |||
| 877 | BT_DBG("chan %p conn %p skb %p", chan, chan->conn, skb); | ||
| 878 | |||
| 879 | lowpan_cb(skb)->status = -EAGAIN; | ||
| 880 | } | ||
| 881 | |||
| 882 | static void chan_resume_cb(struct l2cap_chan *chan) | ||
| 883 | { | ||
| 884 | struct sk_buff *skb = chan->data; | ||
| 885 | |||
| 886 | BT_DBG("chan %p conn %p skb %p", chan, chan->conn, skb); | ||
| 887 | |||
| 888 | lowpan_cb(skb)->status = 0; | ||
| 889 | } | ||
| 890 | |||
| 891 | static long chan_get_sndtimeo_cb(struct l2cap_chan *chan) | ||
| 892 | { | ||
| 893 | return msecs_to_jiffies(1000); | ||
| 894 | } | ||
| 895 | |||
| 896 | static const struct l2cap_ops bt_6lowpan_chan_ops = { | ||
| 897 | .name = "L2CAP 6LoWPAN channel", | ||
| 898 | .new_connection = chan_new_conn_cb, | ||
| 899 | .recv = chan_recv_cb, | ||
| 900 | .close = chan_close_cb, | ||
| 901 | .state_change = chan_state_change_cb, | ||
| 902 | .ready = chan_ready_cb, | ||
| 903 | .resume = chan_resume_cb, | ||
| 904 | .suspend = chan_suspend_cb, | ||
| 905 | .get_sndtimeo = chan_get_sndtimeo_cb, | ||
| 906 | .alloc_skb = chan_alloc_skb_cb, | ||
| 907 | .memcpy_fromiovec = l2cap_chan_no_memcpy_fromiovec, | ||
| 908 | |||
| 909 | .teardown = l2cap_chan_no_teardown, | ||
| 910 | .defer = l2cap_chan_no_defer, | ||
| 911 | .set_shutdown = l2cap_chan_no_set_shutdown, | ||
| 912 | }; | ||
| 913 | |||
| 914 | static inline __u8 bdaddr_type(__u8 type) | ||
| 915 | { | ||
| 916 | if (type == ADDR_LE_DEV_PUBLIC) | ||
| 917 | return BDADDR_LE_PUBLIC; | ||
| 918 | else | ||
| 919 | return BDADDR_LE_RANDOM; | ||
| 920 | } | ||
| 921 | |||
| 922 | static struct l2cap_chan *chan_get(void) | ||
| 923 | { | ||
| 924 | struct l2cap_chan *pchan; | ||
| 925 | |||
| 926 | pchan = chan_create(); | ||
| 927 | if (!pchan) | ||
| 928 | return NULL; | ||
| 929 | |||
| 930 | pchan->ops = &bt_6lowpan_chan_ops; | ||
| 931 | |||
| 932 | return pchan; | ||
| 933 | } | ||
| 934 | |||
| 935 | static int bt_6lowpan_connect(bdaddr_t *addr, u8 dst_type) | ||
| 936 | { | ||
| 937 | struct l2cap_chan *pchan; | ||
| 938 | int err; | ||
| 939 | |||
| 940 | pchan = chan_get(); | ||
| 941 | if (!pchan) | ||
| 942 | return -EINVAL; | ||
| 943 | |||
| 944 | err = l2cap_chan_connect(pchan, cpu_to_le16(psm_6lowpan), 0, | ||
| 945 | addr, dst_type); | ||
| 946 | |||
| 947 | BT_DBG("chan %p err %d", pchan, err); | ||
| 948 | if (err < 0) | ||
| 949 | l2cap_chan_put(pchan); | ||
| 950 | |||
| 822 | return err; | 951 | return err; |
| 823 | } | 952 | } |
| 824 | 953 | ||
| 954 | static int bt_6lowpan_disconnect(struct l2cap_conn *conn, u8 dst_type) | ||
| 955 | { | ||
| 956 | struct lowpan_peer *peer; | ||
| 957 | |||
| 958 | BT_DBG("conn %p dst type %d", conn, dst_type); | ||
| 959 | |||
| 960 | peer = lookup_peer(conn); | ||
| 961 | if (!peer) | ||
| 962 | return -ENOENT; | ||
| 963 | |||
| 964 | BT_DBG("peer %p chan %p", peer, peer->chan); | ||
| 965 | |||
| 966 | l2cap_chan_close(peer->chan, ENOENT); | ||
| 967 | |||
| 968 | return 0; | ||
| 969 | } | ||
| 970 | |||
| 971 | static struct l2cap_chan *bt_6lowpan_listen(void) | ||
| 972 | { | ||
| 973 | bdaddr_t *addr = BDADDR_ANY; | ||
| 974 | struct l2cap_chan *pchan; | ||
| 975 | int err; | ||
| 976 | |||
| 977 | if (psm_6lowpan == 0) | ||
| 978 | return NULL; | ||
| 979 | |||
| 980 | pchan = chan_get(); | ||
| 981 | if (!pchan) | ||
| 982 | return NULL; | ||
| 983 | |||
| 984 | pchan->state = BT_LISTEN; | ||
| 985 | pchan->src_type = BDADDR_LE_PUBLIC; | ||
| 986 | |||
| 987 | BT_DBG("psm 0x%04x chan %p src type %d", psm_6lowpan, pchan, | ||
| 988 | pchan->src_type); | ||
| 989 | |||
| 990 | err = l2cap_add_psm(pchan, addr, cpu_to_le16(psm_6lowpan)); | ||
| 991 | if (err) { | ||
| 992 | l2cap_chan_put(pchan); | ||
| 993 | BT_ERR("psm cannot be added err %d", err); | ||
| 994 | return NULL; | ||
| 995 | } | ||
| 996 | |||
| 997 | return pchan; | ||
| 998 | } | ||
| 999 | |||
| 1000 | static int get_l2cap_conn(char *buf, bdaddr_t *addr, u8 *addr_type, | ||
| 1001 | struct l2cap_conn **conn) | ||
| 1002 | { | ||
| 1003 | struct hci_conn *hcon; | ||
| 1004 | struct hci_dev *hdev; | ||
| 1005 | bdaddr_t *src = BDADDR_ANY; | ||
| 1006 | int n; | ||
| 1007 | |||
| 1008 | n = sscanf(buf, "%hhx:%hhx:%hhx:%hhx:%hhx:%hhx %hhu", | ||
| 1009 | &addr->b[5], &addr->b[4], &addr->b[3], | ||
| 1010 | &addr->b[2], &addr->b[1], &addr->b[0], | ||
| 1011 | addr_type); | ||
| 1012 | |||
| 1013 | if (n < 7) | ||
| 1014 | return -EINVAL; | ||
| 1015 | |||
| 1016 | hdev = hci_get_route(addr, src); | ||
| 1017 | if (!hdev) | ||
| 1018 | return -ENOENT; | ||
| 1019 | |||
| 1020 | hci_dev_lock(hdev); | ||
| 1021 | hcon = hci_conn_hash_lookup_ba(hdev, LE_LINK, addr); | ||
| 1022 | hci_dev_unlock(hdev); | ||
| 1023 | |||
| 1024 | if (!hcon) | ||
| 1025 | return -ENOENT; | ||
| 1026 | |||
| 1027 | *conn = (struct l2cap_conn *)hcon->l2cap_data; | ||
| 1028 | |||
| 1029 | BT_DBG("conn %p dst %pMR type %d", *conn, &hcon->dst, hcon->dst_type); | ||
| 1030 | |||
| 1031 | return 0; | ||
| 1032 | } | ||
| 1033 | |||
| 1034 | static void disconnect_all_peers(void) | ||
| 1035 | { | ||
| 1036 | struct lowpan_dev *entry, *tmp_dev; | ||
| 1037 | struct lowpan_peer *peer, *tmp_peer, *new_peer; | ||
| 1038 | struct list_head peers; | ||
| 1039 | unsigned long flags; | ||
| 1040 | |||
| 1041 | INIT_LIST_HEAD(&peers); | ||
| 1042 | |||
| 1043 | /* We make a separate list of peers as the close_cb() will | ||
| 1044 | * modify the device peers list so it is better not to mess | ||
| 1045 | * with the same list at the same time. | ||
| 1046 | */ | ||
| 1047 | |||
| 1048 | read_lock_irqsave(&devices_lock, flags); | ||
| 1049 | |||
| 1050 | list_for_each_entry_safe(entry, tmp_dev, &bt_6lowpan_devices, list) { | ||
| 1051 | list_for_each_entry_safe(peer, tmp_peer, &entry->peers, list) { | ||
| 1052 | new_peer = kmalloc(sizeof(*new_peer), GFP_ATOMIC); | ||
| 1053 | if (!new_peer) | ||
| 1054 | break; | ||
| 1055 | |||
| 1056 | new_peer->chan = peer->chan; | ||
| 1057 | INIT_LIST_HEAD(&new_peer->list); | ||
| 1058 | |||
| 1059 | list_add(&new_peer->list, &peers); | ||
| 1060 | } | ||
| 1061 | } | ||
| 1062 | |||
| 1063 | read_unlock_irqrestore(&devices_lock, flags); | ||
| 1064 | |||
| 1065 | list_for_each_entry_safe(peer, tmp_peer, &peers, list) { | ||
| 1066 | l2cap_chan_close(peer->chan, ENOENT); | ||
| 1067 | kfree(peer); | ||
| 1068 | } | ||
| 1069 | } | ||
| 1070 | |||
| 1071 | static int lowpan_psm_set(void *data, u64 val) | ||
| 1072 | { | ||
| 1073 | u16 psm; | ||
| 1074 | |||
| 1075 | psm = val; | ||
| 1076 | if (psm == 0 || psm_6lowpan != psm) | ||
| 1077 | /* Disconnect existing connections if 6lowpan is | ||
| 1078 | * disabled (psm = 0), or if psm changes. | ||
| 1079 | */ | ||
| 1080 | disconnect_all_peers(); | ||
| 1081 | |||
| 1082 | psm_6lowpan = psm; | ||
| 1083 | |||
| 1084 | if (listen_chan) { | ||
| 1085 | l2cap_chan_close(listen_chan, 0); | ||
| 1086 | l2cap_chan_put(listen_chan); | ||
| 1087 | } | ||
| 1088 | |||
| 1089 | listen_chan = bt_6lowpan_listen(); | ||
| 1090 | |||
| 1091 | return 0; | ||
| 1092 | } | ||
| 1093 | |||
| 1094 | static int lowpan_psm_get(void *data, u64 *val) | ||
| 1095 | { | ||
| 1096 | *val = psm_6lowpan; | ||
| 1097 | return 0; | ||
| 1098 | } | ||
| 1099 | |||
| 1100 | DEFINE_SIMPLE_ATTRIBUTE(lowpan_psm_fops, lowpan_psm_get, | ||
| 1101 | lowpan_psm_set, "%llu\n"); | ||
| 1102 | |||
| 1103 | static ssize_t lowpan_control_write(struct file *fp, | ||
| 1104 | const char __user *user_buffer, | ||
| 1105 | size_t count, | ||
| 1106 | loff_t *position) | ||
| 1107 | { | ||
| 1108 | char buf[32]; | ||
| 1109 | size_t buf_size = min(count, sizeof(buf) - 1); | ||
| 1110 | int ret; | ||
| 1111 | bdaddr_t addr; | ||
| 1112 | u8 addr_type; | ||
| 1113 | struct l2cap_conn *conn = NULL; | ||
| 1114 | |||
| 1115 | if (copy_from_user(buf, user_buffer, buf_size)) | ||
| 1116 | return -EFAULT; | ||
| 1117 | |||
| 1118 | buf[buf_size] = '\0'; | ||
| 1119 | |||
| 1120 | if (memcmp(buf, "connect ", 8) == 0) { | ||
| 1121 | ret = get_l2cap_conn(&buf[8], &addr, &addr_type, &conn); | ||
| 1122 | if (ret == -EINVAL) | ||
| 1123 | return ret; | ||
| 1124 | |||
| 1125 | if (listen_chan) { | ||
| 1126 | l2cap_chan_close(listen_chan, 0); | ||
| 1127 | l2cap_chan_put(listen_chan); | ||
| 1128 | listen_chan = NULL; | ||
| 1129 | } | ||
| 1130 | |||
| 1131 | if (conn) { | ||
| 1132 | struct lowpan_peer *peer; | ||
| 1133 | |||
| 1134 | if (!is_bt_6lowpan(conn->hcon)) | ||
| 1135 | return -EINVAL; | ||
| 1136 | |||
| 1137 | peer = lookup_peer(conn); | ||
| 1138 | if (peer) { | ||
| 1139 | BT_DBG("6LoWPAN connection already exists"); | ||
| 1140 | return -EALREADY; | ||
| 1141 | } | ||
| 1142 | |||
| 1143 | BT_DBG("conn %p dst %pMR type %d user %d", conn, | ||
| 1144 | &conn->hcon->dst, conn->hcon->dst_type, | ||
| 1145 | addr_type); | ||
| 1146 | } | ||
| 1147 | |||
| 1148 | ret = bt_6lowpan_connect(&addr, addr_type); | ||
| 1149 | if (ret < 0) | ||
| 1150 | return ret; | ||
| 1151 | |||
| 1152 | return count; | ||
| 1153 | } | ||
| 1154 | |||
| 1155 | if (memcmp(buf, "disconnect ", 11) == 0) { | ||
| 1156 | ret = get_l2cap_conn(&buf[11], &addr, &addr_type, &conn); | ||
| 1157 | if (ret < 0) | ||
| 1158 | return ret; | ||
| 1159 | |||
| 1160 | ret = bt_6lowpan_disconnect(conn, addr_type); | ||
| 1161 | if (ret < 0) | ||
| 1162 | return ret; | ||
| 1163 | |||
| 1164 | return count; | ||
| 1165 | } | ||
| 1166 | |||
| 1167 | return count; | ||
| 1168 | } | ||
| 1169 | |||
| 1170 | static int lowpan_control_show(struct seq_file *f, void *ptr) | ||
| 1171 | { | ||
| 1172 | struct lowpan_dev *entry, *tmp_dev; | ||
| 1173 | struct lowpan_peer *peer, *tmp_peer; | ||
| 1174 | unsigned long flags; | ||
| 1175 | |||
| 1176 | read_lock_irqsave(&devices_lock, flags); | ||
| 1177 | |||
| 1178 | list_for_each_entry_safe(entry, tmp_dev, &bt_6lowpan_devices, list) { | ||
| 1179 | list_for_each_entry_safe(peer, tmp_peer, &entry->peers, list) | ||
| 1180 | seq_printf(f, "%pMR (type %u)\n", | ||
| 1181 | &peer->chan->dst, peer->chan->dst_type); | ||
| 1182 | } | ||
| 1183 | |||
| 1184 | read_unlock_irqrestore(&devices_lock, flags); | ||
| 1185 | |||
| 1186 | return 0; | ||
| 1187 | } | ||
| 1188 | |||
| 1189 | static int lowpan_control_open(struct inode *inode, struct file *file) | ||
| 1190 | { | ||
| 1191 | return single_open(file, lowpan_control_show, inode->i_private); | ||
| 1192 | } | ||
| 1193 | |||
| 1194 | static const struct file_operations lowpan_control_fops = { | ||
| 1195 | .open = lowpan_control_open, | ||
| 1196 | .read = seq_read, | ||
| 1197 | .write = lowpan_control_write, | ||
| 1198 | .llseek = seq_lseek, | ||
| 1199 | .release = single_release, | ||
| 1200 | }; | ||
| 1201 | |||
| 1202 | static void disconnect_devices(void) | ||
| 1203 | { | ||
| 1204 | struct lowpan_dev *entry, *tmp, *new_dev; | ||
| 1205 | struct list_head devices; | ||
| 1206 | unsigned long flags; | ||
| 1207 | |||
| 1208 | INIT_LIST_HEAD(&devices); | ||
| 1209 | |||
| 1210 | /* We make a separate list of devices because the unregister_netdev() | ||
| 1211 | * will call device_event() which will also want to modify the same | ||
| 1212 | * devices list. | ||
| 1213 | */ | ||
| 1214 | |||
| 1215 | read_lock_irqsave(&devices_lock, flags); | ||
| 1216 | |||
| 1217 | list_for_each_entry_safe(entry, tmp, &bt_6lowpan_devices, list) { | ||
| 1218 | new_dev = kmalloc(sizeof(*new_dev), GFP_ATOMIC); | ||
| 1219 | if (!new_dev) | ||
| 1220 | break; | ||
| 1221 | |||
| 1222 | new_dev->netdev = entry->netdev; | ||
| 1223 | INIT_LIST_HEAD(&new_dev->list); | ||
| 1224 | |||
| 1225 | list_add(&new_dev->list, &devices); | ||
| 1226 | } | ||
| 1227 | |||
| 1228 | read_unlock_irqrestore(&devices_lock, flags); | ||
| 1229 | |||
| 1230 | list_for_each_entry_safe(entry, tmp, &devices, list) { | ||
| 1231 | ifdown(entry->netdev); | ||
| 1232 | BT_DBG("Unregistering netdev %s %p", | ||
| 1233 | entry->netdev->name, entry->netdev); | ||
| 1234 | unregister_netdev(entry->netdev); | ||
| 1235 | kfree(entry); | ||
| 1236 | } | ||
| 1237 | } | ||
| 1238 | |||
| 825 | static int device_event(struct notifier_block *unused, | 1239 | static int device_event(struct notifier_block *unused, |
| 826 | unsigned long event, void *ptr) | 1240 | unsigned long event, void *ptr) |
| 827 | { | 1241 | { |
| @@ -838,6 +1252,8 @@ static int device_event(struct notifier_block *unused, | |||
| 838 | list_for_each_entry_safe(entry, tmp, &bt_6lowpan_devices, | 1252 | list_for_each_entry_safe(entry, tmp, &bt_6lowpan_devices, |
| 839 | list) { | 1253 | list) { |
| 840 | if (entry->netdev == netdev) { | 1254 | if (entry->netdev == netdev) { |
| 1255 | BT_DBG("Unregistered netdev %s %p", | ||
| 1256 | netdev->name, netdev); | ||
| 841 | list_del(&entry->list); | 1257 | list_del(&entry->list); |
| 842 | kfree(entry); | 1258 | kfree(entry); |
| 843 | break; | 1259 | break; |
| @@ -854,12 +1270,37 @@ static struct notifier_block bt_6lowpan_dev_notifier = { | |||
| 854 | .notifier_call = device_event, | 1270 | .notifier_call = device_event, |
| 855 | }; | 1271 | }; |
| 856 | 1272 | ||
| 857 | int bt_6lowpan_init(void) | 1273 | static int __init bt_6lowpan_init(void) |
| 858 | { | 1274 | { |
| 1275 | lowpan_psm_debugfs = debugfs_create_file("6lowpan_psm", 0644, | ||
| 1276 | bt_debugfs, NULL, | ||
| 1277 | &lowpan_psm_fops); | ||
| 1278 | lowpan_control_debugfs = debugfs_create_file("6lowpan_control", 0644, | ||
| 1279 | bt_debugfs, NULL, | ||
| 1280 | &lowpan_control_fops); | ||
| 1281 | |||
| 859 | return register_netdevice_notifier(&bt_6lowpan_dev_notifier); | 1282 | return register_netdevice_notifier(&bt_6lowpan_dev_notifier); |
| 860 | } | 1283 | } |
| 861 | 1284 | ||
| 862 | void bt_6lowpan_cleanup(void) | 1285 | static void __exit bt_6lowpan_exit(void) |
| 863 | { | 1286 | { |
| 1287 | debugfs_remove(lowpan_psm_debugfs); | ||
| 1288 | debugfs_remove(lowpan_control_debugfs); | ||
| 1289 | |||
| 1290 | if (listen_chan) { | ||
| 1291 | l2cap_chan_close(listen_chan, 0); | ||
| 1292 | l2cap_chan_put(listen_chan); | ||
| 1293 | } | ||
| 1294 | |||
| 1295 | disconnect_devices(); | ||
| 1296 | |||
| 864 | unregister_netdevice_notifier(&bt_6lowpan_dev_notifier); | 1297 | unregister_netdevice_notifier(&bt_6lowpan_dev_notifier); |
| 865 | } | 1298 | } |
| 1299 | |||
| 1300 | module_init(bt_6lowpan_init); | ||
| 1301 | module_exit(bt_6lowpan_exit); | ||
| 1302 | |||
| 1303 | MODULE_AUTHOR("Jukka Rissanen <jukka.rissanen@linux.intel.com>"); | ||
| 1304 | MODULE_DESCRIPTION("Bluetooth 6LoWPAN"); | ||
| 1305 | MODULE_VERSION(VERSION); | ||
| 1306 | MODULE_LICENSE("GPL"); | ||
diff --git a/net/bluetooth/6lowpan.h b/net/bluetooth/6lowpan.h deleted file mode 100644 index 5d281f1eaf55..000000000000 --- a/net/bluetooth/6lowpan.h +++ /dev/null | |||
| @@ -1,47 +0,0 @@ | |||
| 1 | /* | ||
| 2 | Copyright (c) 2013 Intel Corp. | ||
| 3 | |||
| 4 | This program is free software; you can redistribute it and/or modify | ||
| 5 | it under the terms of the GNU General Public License version 2 and | ||
| 6 | only version 2 as published by the Free Software Foundation. | ||
| 7 | |||
| 8 | This program is distributed in the hope that it will be useful, | ||
| 9 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 10 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 11 | GNU General Public License for more details. | ||
| 12 | */ | ||
| 13 | |||
| 14 | #ifndef __6LOWPAN_H | ||
| 15 | #define __6LOWPAN_H | ||
| 16 | |||
| 17 | #include <linux/errno.h> | ||
| 18 | #include <linux/skbuff.h> | ||
| 19 | #include <net/bluetooth/l2cap.h> | ||
| 20 | |||
| 21 | #if IS_ENABLED(CONFIG_BT_6LOWPAN) | ||
| 22 | int bt_6lowpan_recv(struct l2cap_conn *conn, struct sk_buff *skb); | ||
| 23 | int bt_6lowpan_add_conn(struct l2cap_conn *conn); | ||
| 24 | int bt_6lowpan_del_conn(struct l2cap_conn *conn); | ||
| 25 | int bt_6lowpan_init(void); | ||
| 26 | void bt_6lowpan_cleanup(void); | ||
| 27 | #else | ||
| 28 | static int bt_6lowpan_recv(struct l2cap_conn *conn, struct sk_buff *skb) | ||
| 29 | { | ||
| 30 | return -EOPNOTSUPP; | ||
| 31 | } | ||
| 32 | static int bt_6lowpan_add_conn(struct l2cap_conn *conn) | ||
| 33 | { | ||
| 34 | return -EOPNOTSUPP; | ||
| 35 | } | ||
| 36 | int bt_6lowpan_del_conn(struct l2cap_conn *conn) | ||
| 37 | { | ||
| 38 | return -EOPNOTSUPP; | ||
| 39 | } | ||
| 40 | static int bt_6lowpan_init(void) | ||
| 41 | { | ||
| 42 | return -EOPNOTSUPP; | ||
| 43 | } | ||
| 44 | static void bt_6lowpan_cleanup(void) { } | ||
| 45 | #endif | ||
| 46 | |||
| 47 | #endif /* __6LOWPAN_H */ | ||
diff --git a/net/bluetooth/Kconfig b/net/bluetooth/Kconfig index 06ec14499ca1..600fb29288f4 100644 --- a/net/bluetooth/Kconfig +++ b/net/bluetooth/Kconfig | |||
| @@ -6,7 +6,6 @@ menuconfig BT | |||
| 6 | tristate "Bluetooth subsystem support" | 6 | tristate "Bluetooth subsystem support" |
| 7 | depends on NET && !S390 | 7 | depends on NET && !S390 |
| 8 | depends on RFKILL || !RFKILL | 8 | depends on RFKILL || !RFKILL |
| 9 | select 6LOWPAN_IPHC if BT_6LOWPAN | ||
| 10 | select CRC16 | 9 | select CRC16 |
| 11 | select CRYPTO | 10 | select CRYPTO |
| 12 | select CRYPTO_BLKCIPHER | 11 | select CRYPTO_BLKCIPHER |
| @@ -41,10 +40,10 @@ menuconfig BT | |||
| 41 | more information, see <http://www.bluez.org/>. | 40 | more information, see <http://www.bluez.org/>. |
| 42 | 41 | ||
| 43 | config BT_6LOWPAN | 42 | config BT_6LOWPAN |
| 44 | bool "Bluetooth 6LoWPAN support" | 43 | tristate "Bluetooth 6LoWPAN support" |
| 45 | depends on BT && IPV6 | 44 | depends on BT && 6LOWPAN |
| 46 | help | 45 | help |
| 47 | IPv6 compression over Bluetooth. | 46 | IPv6 compression over Bluetooth Low Energy. |
| 48 | 47 | ||
| 49 | source "net/bluetooth/rfcomm/Kconfig" | 48 | source "net/bluetooth/rfcomm/Kconfig" |
| 50 | 49 | ||
diff --git a/net/bluetooth/Makefile b/net/bluetooth/Makefile index ca51246b1016..886e9aa3ecf1 100644 --- a/net/bluetooth/Makefile +++ b/net/bluetooth/Makefile | |||
| @@ -7,10 +7,12 @@ obj-$(CONFIG_BT_RFCOMM) += rfcomm/ | |||
| 7 | obj-$(CONFIG_BT_BNEP) += bnep/ | 7 | obj-$(CONFIG_BT_BNEP) += bnep/ |
| 8 | obj-$(CONFIG_BT_CMTP) += cmtp/ | 8 | obj-$(CONFIG_BT_CMTP) += cmtp/ |
| 9 | obj-$(CONFIG_BT_HIDP) += hidp/ | 9 | obj-$(CONFIG_BT_HIDP) += hidp/ |
| 10 | obj-$(CONFIG_BT_6LOWPAN) += bluetooth_6lowpan.o | ||
| 11 | |||
| 12 | bluetooth_6lowpan-y := 6lowpan.o | ||
| 10 | 13 | ||
| 11 | bluetooth-y := af_bluetooth.o hci_core.o hci_conn.o hci_event.o mgmt.o \ | 14 | bluetooth-y := af_bluetooth.o hci_core.o hci_conn.o hci_event.o mgmt.o \ |
| 12 | hci_sock.o hci_sysfs.o l2cap_core.o l2cap_sock.o smp.o sco.o lib.o \ | 15 | hci_sock.o hci_sysfs.o l2cap_core.o l2cap_sock.o smp.o sco.o lib.o \ |
| 13 | a2mp.o amp.o | 16 | a2mp.o amp.o |
| 14 | bluetooth-$(CONFIG_BT_6LOWPAN) += 6lowpan.o | ||
| 15 | 17 | ||
| 16 | subdir-ccflags-y += -D__CHECK_ENDIAN__ | 18 | subdir-ccflags-y += -D__CHECK_ENDIAN__ |
diff --git a/net/bluetooth/a2mp.c b/net/bluetooth/a2mp.c index 9514cc9e850c..5dcade511fdb 100644 --- a/net/bluetooth/a2mp.c +++ b/net/bluetooth/a2mp.c | |||
| @@ -63,7 +63,7 @@ void a2mp_send(struct amp_mgr *mgr, u8 code, u8 ident, u16 len, void *data) | |||
| 63 | msg.msg_iov = (struct iovec *) &iv; | 63 | msg.msg_iov = (struct iovec *) &iv; |
| 64 | msg.msg_iovlen = 1; | 64 | msg.msg_iovlen = 1; |
| 65 | 65 | ||
| 66 | l2cap_chan_send(chan, &msg, total_len, 0); | 66 | l2cap_chan_send(chan, &msg, total_len); |
| 67 | 67 | ||
| 68 | kfree(cmd); | 68 | kfree(cmd); |
| 69 | } | 69 | } |
| @@ -693,18 +693,19 @@ static void a2mp_chan_state_change_cb(struct l2cap_chan *chan, int state, | |||
| 693 | } | 693 | } |
| 694 | 694 | ||
| 695 | static struct sk_buff *a2mp_chan_alloc_skb_cb(struct l2cap_chan *chan, | 695 | static struct sk_buff *a2mp_chan_alloc_skb_cb(struct l2cap_chan *chan, |
| 696 | unsigned long hdr_len, | ||
| 696 | unsigned long len, int nb) | 697 | unsigned long len, int nb) |
| 697 | { | 698 | { |
| 698 | struct sk_buff *skb; | 699 | struct sk_buff *skb; |
| 699 | 700 | ||
| 700 | skb = bt_skb_alloc(len, GFP_KERNEL); | 701 | skb = bt_skb_alloc(hdr_len + len, GFP_KERNEL); |
| 701 | if (!skb) | 702 | if (!skb) |
| 702 | return ERR_PTR(-ENOMEM); | 703 | return ERR_PTR(-ENOMEM); |
| 703 | 704 | ||
| 704 | return skb; | 705 | return skb; |
| 705 | } | 706 | } |
| 706 | 707 | ||
| 707 | static struct l2cap_ops a2mp_chan_ops = { | 708 | static const struct l2cap_ops a2mp_chan_ops = { |
| 708 | .name = "L2CAP A2MP channel", | 709 | .name = "L2CAP A2MP channel", |
| 709 | .recv = a2mp_chan_recv_cb, | 710 | .recv = a2mp_chan_recv_cb, |
| 710 | .close = a2mp_chan_close_cb, | 711 | .close = a2mp_chan_close_cb, |
| @@ -719,6 +720,7 @@ static struct l2cap_ops a2mp_chan_ops = { | |||
| 719 | .resume = l2cap_chan_no_resume, | 720 | .resume = l2cap_chan_no_resume, |
| 720 | .set_shutdown = l2cap_chan_no_set_shutdown, | 721 | .set_shutdown = l2cap_chan_no_set_shutdown, |
| 721 | .get_sndtimeo = l2cap_chan_no_get_sndtimeo, | 722 | .get_sndtimeo = l2cap_chan_no_get_sndtimeo, |
| 723 | .memcpy_fromiovec = l2cap_chan_no_memcpy_fromiovec, | ||
| 722 | }; | 724 | }; |
| 723 | 725 | ||
| 724 | static struct l2cap_chan *a2mp_chan_open(struct l2cap_conn *conn, bool locked) | 726 | static struct l2cap_chan *a2mp_chan_open(struct l2cap_conn *conn, bool locked) |
diff --git a/net/bluetooth/af_bluetooth.c b/net/bluetooth/af_bluetooth.c index 2021c481cdb6..4dca0299ed96 100644 --- a/net/bluetooth/af_bluetooth.c +++ b/net/bluetooth/af_bluetooth.c | |||
| @@ -639,7 +639,7 @@ static int bt_seq_show(struct seq_file *seq, void *v) | |||
| 639 | return 0; | 639 | return 0; |
| 640 | } | 640 | } |
| 641 | 641 | ||
| 642 | static struct seq_operations bt_seq_ops = { | 642 | static const struct seq_operations bt_seq_ops = { |
| 643 | .start = bt_seq_start, | 643 | .start = bt_seq_start, |
| 644 | .next = bt_seq_next, | 644 | .next = bt_seq_next, |
| 645 | .stop = bt_seq_stop, | 645 | .stop = bt_seq_stop, |
diff --git a/net/bluetooth/amp.c b/net/bluetooth/amp.c index bb39509b3f06..016cdb66df6c 100644 --- a/net/bluetooth/amp.c +++ b/net/bluetooth/amp.c | |||
| @@ -113,8 +113,9 @@ struct hci_conn *phylink_add(struct hci_dev *hdev, struct amp_mgr *mgr, | |||
| 113 | { | 113 | { |
| 114 | bdaddr_t *dst = &mgr->l2cap_conn->hcon->dst; | 114 | bdaddr_t *dst = &mgr->l2cap_conn->hcon->dst; |
| 115 | struct hci_conn *hcon; | 115 | struct hci_conn *hcon; |
| 116 | u8 role = out ? HCI_ROLE_MASTER : HCI_ROLE_SLAVE; | ||
| 116 | 117 | ||
| 117 | hcon = hci_conn_add(hdev, AMP_LINK, dst); | 118 | hcon = hci_conn_add(hdev, AMP_LINK, dst, role); |
| 118 | if (!hcon) | 119 | if (!hcon) |
| 119 | return NULL; | 120 | return NULL; |
| 120 | 121 | ||
| @@ -125,7 +126,6 @@ struct hci_conn *phylink_add(struct hci_dev *hdev, struct amp_mgr *mgr, | |||
| 125 | hcon->handle = __next_handle(mgr); | 126 | hcon->handle = __next_handle(mgr); |
| 126 | hcon->remote_id = remote_id; | 127 | hcon->remote_id = remote_id; |
| 127 | hcon->amp_mgr = amp_mgr_get(mgr); | 128 | hcon->amp_mgr = amp_mgr_get(mgr); |
| 128 | hcon->out = out; | ||
| 129 | 129 | ||
| 130 | return hcon; | 130 | return hcon; |
| 131 | } | 131 | } |
| @@ -133,8 +133,8 @@ struct hci_conn *phylink_add(struct hci_dev *hdev, struct amp_mgr *mgr, | |||
| 133 | /* AMP crypto key generation interface */ | 133 | /* AMP crypto key generation interface */ |
| 134 | static int hmac_sha256(u8 *key, u8 ksize, char *plaintext, u8 psize, u8 *output) | 134 | static int hmac_sha256(u8 *key, u8 ksize, char *plaintext, u8 psize, u8 *output) |
| 135 | { | 135 | { |
| 136 | int ret = 0; | ||
| 137 | struct crypto_shash *tfm; | 136 | struct crypto_shash *tfm; |
| 137 | int ret; | ||
| 138 | 138 | ||
| 139 | if (!ksize) | 139 | if (!ksize) |
| 140 | return -EINVAL; | 140 | return -EINVAL; |
diff --git a/net/bluetooth/bnep/core.c b/net/bluetooth/bnep/core.c index a841d3e776c5..85bcc21e84d2 100644 --- a/net/bluetooth/bnep/core.c +++ b/net/bluetooth/bnep/core.c | |||
| @@ -538,8 +538,9 @@ int bnep_add_connection(struct bnep_connadd_req *req, struct socket *sock) | |||
| 538 | 538 | ||
| 539 | /* session struct allocated as private part of net_device */ | 539 | /* session struct allocated as private part of net_device */ |
| 540 | dev = alloc_netdev(sizeof(struct bnep_session), | 540 | dev = alloc_netdev(sizeof(struct bnep_session), |
| 541 | (*req->device) ? req->device : "bnep%d", | 541 | (*req->device) ? req->device : "bnep%d", |
| 542 | bnep_net_setup); | 542 | NET_NAME_UNKNOWN, |
| 543 | bnep_net_setup); | ||
| 543 | if (!dev) | 544 | if (!dev) |
| 544 | return -ENOMEM; | 545 | return -ENOMEM; |
| 545 | 546 | ||
diff --git a/net/bluetooth/cmtp/capi.c b/net/bluetooth/cmtp/capi.c index cd75e4d64b90..1ca8a87a0787 100644 --- a/net/bluetooth/cmtp/capi.c +++ b/net/bluetooth/cmtp/capi.c | |||
| @@ -362,12 +362,6 @@ void cmtp_recv_capimsg(struct cmtp_session *session, struct sk_buff *skb) | |||
| 362 | CAPIMSG_SETCONTROL(skb->data, contr); | 362 | CAPIMSG_SETCONTROL(skb->data, contr); |
| 363 | } | 363 | } |
| 364 | 364 | ||
| 365 | if (!ctrl) { | ||
| 366 | BT_ERR("Can't find controller %d for message", session->num); | ||
| 367 | kfree_skb(skb); | ||
| 368 | return; | ||
| 369 | } | ||
| 370 | |||
| 371 | capi_ctr_handle_message(ctrl, appl, skb); | 365 | capi_ctr_handle_message(ctrl, appl, skb); |
| 372 | } | 366 | } |
| 373 | 367 | ||
diff --git a/net/bluetooth/hci_conn.c b/net/bluetooth/hci_conn.c index a7a27bc2c0b1..b50dabb3f86a 100644 --- a/net/bluetooth/hci_conn.c +++ b/net/bluetooth/hci_conn.c | |||
| @@ -66,8 +66,7 @@ static void hci_acl_create_connection(struct hci_conn *conn) | |||
| 66 | 66 | ||
| 67 | conn->state = BT_CONNECT; | 67 | conn->state = BT_CONNECT; |
| 68 | conn->out = true; | 68 | conn->out = true; |
| 69 | 69 | conn->role = HCI_ROLE_MASTER; | |
| 70 | conn->link_mode = HCI_LM_MASTER; | ||
| 71 | 70 | ||
| 72 | conn->attempt++; | 71 | conn->attempt++; |
| 73 | 72 | ||
| @@ -136,7 +135,7 @@ void hci_disconnect(struct hci_conn *conn, __u8 reason) | |||
| 136 | hci_send_cmd(conn->hdev, HCI_OP_DISCONNECT, sizeof(cp), &cp); | 135 | hci_send_cmd(conn->hdev, HCI_OP_DISCONNECT, sizeof(cp), &cp); |
| 137 | } | 136 | } |
| 138 | 137 | ||
| 139 | static void hci_amp_disconn(struct hci_conn *conn, __u8 reason) | 138 | static void hci_amp_disconn(struct hci_conn *conn) |
| 140 | { | 139 | { |
| 141 | struct hci_cp_disconn_phy_link cp; | 140 | struct hci_cp_disconn_phy_link cp; |
| 142 | 141 | ||
| @@ -145,7 +144,7 @@ static void hci_amp_disconn(struct hci_conn *conn, __u8 reason) | |||
| 145 | conn->state = BT_DISCONN; | 144 | conn->state = BT_DISCONN; |
| 146 | 145 | ||
| 147 | cp.phy_handle = HCI_PHY_HANDLE(conn->handle); | 146 | cp.phy_handle = HCI_PHY_HANDLE(conn->handle); |
| 148 | cp.reason = reason; | 147 | cp.reason = hci_proto_disconn_ind(conn); |
| 149 | hci_send_cmd(conn->hdev, HCI_OP_DISCONN_PHY_LINK, | 148 | hci_send_cmd(conn->hdev, HCI_OP_DISCONN_PHY_LINK, |
| 150 | sizeof(cp), &cp); | 149 | sizeof(cp), &cp); |
| 151 | } | 150 | } |
| @@ -213,14 +212,26 @@ bool hci_setup_sync(struct hci_conn *conn, __u16 handle) | |||
| 213 | return true; | 212 | return true; |
| 214 | } | 213 | } |
| 215 | 214 | ||
| 216 | void hci_le_conn_update(struct hci_conn *conn, u16 min, u16 max, | 215 | u8 hci_le_conn_update(struct hci_conn *conn, u16 min, u16 max, u16 latency, |
| 217 | u16 latency, u16 to_multiplier) | 216 | u16 to_multiplier) |
| 218 | { | 217 | { |
| 219 | struct hci_cp_le_conn_update cp; | ||
| 220 | struct hci_dev *hdev = conn->hdev; | 218 | struct hci_dev *hdev = conn->hdev; |
| 219 | struct hci_conn_params *params; | ||
| 220 | struct hci_cp_le_conn_update cp; | ||
| 221 | 221 | ||
| 222 | memset(&cp, 0, sizeof(cp)); | 222 | hci_dev_lock(hdev); |
| 223 | 223 | ||
| 224 | params = hci_conn_params_lookup(hdev, &conn->dst, conn->dst_type); | ||
| 225 | if (params) { | ||
| 226 | params->conn_min_interval = min; | ||
| 227 | params->conn_max_interval = max; | ||
| 228 | params->conn_latency = latency; | ||
| 229 | params->supervision_timeout = to_multiplier; | ||
| 230 | } | ||
| 231 | |||
| 232 | hci_dev_unlock(hdev); | ||
| 233 | |||
| 234 | memset(&cp, 0, sizeof(cp)); | ||
| 224 | cp.handle = cpu_to_le16(conn->handle); | 235 | cp.handle = cpu_to_le16(conn->handle); |
| 225 | cp.conn_interval_min = cpu_to_le16(min); | 236 | cp.conn_interval_min = cpu_to_le16(min); |
| 226 | cp.conn_interval_max = cpu_to_le16(max); | 237 | cp.conn_interval_max = cpu_to_le16(max); |
| @@ -230,6 +241,11 @@ void hci_le_conn_update(struct hci_conn *conn, u16 min, u16 max, | |||
| 230 | cp.max_ce_len = cpu_to_le16(0x0000); | 241 | cp.max_ce_len = cpu_to_le16(0x0000); |
| 231 | 242 | ||
| 232 | hci_send_cmd(hdev, HCI_OP_LE_CONN_UPDATE, sizeof(cp), &cp); | 243 | hci_send_cmd(hdev, HCI_OP_LE_CONN_UPDATE, sizeof(cp), &cp); |
| 244 | |||
| 245 | if (params) | ||
| 246 | return 0x01; | ||
| 247 | |||
| 248 | return 0x00; | ||
| 233 | } | 249 | } |
| 234 | 250 | ||
| 235 | void hci_le_start_enc(struct hci_conn *conn, __le16 ediv, __le64 rand, | 251 | void hci_le_start_enc(struct hci_conn *conn, __le16 ediv, __le64 rand, |
| @@ -271,20 +287,6 @@ void hci_sco_setup(struct hci_conn *conn, __u8 status) | |||
| 271 | } | 287 | } |
| 272 | } | 288 | } |
| 273 | 289 | ||
| 274 | static void hci_conn_disconnect(struct hci_conn *conn) | ||
| 275 | { | ||
| 276 | __u8 reason = hci_proto_disconn_ind(conn); | ||
| 277 | |||
| 278 | switch (conn->type) { | ||
| 279 | case AMP_LINK: | ||
| 280 | hci_amp_disconn(conn, reason); | ||
| 281 | break; | ||
| 282 | default: | ||
| 283 | hci_disconnect(conn, reason); | ||
| 284 | break; | ||
| 285 | } | ||
| 286 | } | ||
| 287 | |||
| 288 | static void hci_conn_timeout(struct work_struct *work) | 290 | static void hci_conn_timeout(struct work_struct *work) |
| 289 | { | 291 | { |
| 290 | struct hci_conn *conn = container_of(work, struct hci_conn, | 292 | struct hci_conn *conn = container_of(work, struct hci_conn, |
| @@ -319,7 +321,31 @@ static void hci_conn_timeout(struct work_struct *work) | |||
| 319 | break; | 321 | break; |
| 320 | case BT_CONFIG: | 322 | case BT_CONFIG: |
| 321 | case BT_CONNECTED: | 323 | case BT_CONNECTED: |
| 322 | hci_conn_disconnect(conn); | 324 | if (conn->type == AMP_LINK) { |
| 325 | hci_amp_disconn(conn); | ||
| 326 | } else { | ||
| 327 | __u8 reason = hci_proto_disconn_ind(conn); | ||
| 328 | |||
| 329 | /* When we are master of an established connection | ||
| 330 | * and it enters the disconnect timeout, then go | ||
| 331 | * ahead and try to read the current clock offset. | ||
| 332 | * | ||
| 333 | * Processing of the result is done within the | ||
| 334 | * event handling and hci_clock_offset_evt function. | ||
| 335 | */ | ||
| 336 | if (conn->type == ACL_LINK && | ||
| 337 | conn->role == HCI_ROLE_MASTER) { | ||
| 338 | struct hci_dev *hdev = conn->hdev; | ||
| 339 | struct hci_cp_read_clock_offset cp; | ||
| 340 | |||
| 341 | cp.handle = cpu_to_le16(conn->handle); | ||
| 342 | |||
| 343 | hci_send_cmd(hdev, HCI_OP_READ_CLOCK_OFFSET, | ||
| 344 | sizeof(cp), &cp); | ||
| 345 | } | ||
| 346 | |||
| 347 | hci_disconnect(conn, reason); | ||
| 348 | } | ||
| 323 | break; | 349 | break; |
| 324 | default: | 350 | default: |
| 325 | conn->state = BT_CLOSED; | 351 | conn->state = BT_CLOSED; |
| @@ -336,9 +362,6 @@ static void hci_conn_idle(struct work_struct *work) | |||
| 336 | 362 | ||
| 337 | BT_DBG("hcon %p mode %d", conn, conn->mode); | 363 | BT_DBG("hcon %p mode %d", conn, conn->mode); |
| 338 | 364 | ||
| 339 | if (test_bit(HCI_RAW, &hdev->flags)) | ||
| 340 | return; | ||
| 341 | |||
| 342 | if (!lmp_sniff_capable(hdev) || !lmp_sniff_capable(conn)) | 365 | if (!lmp_sniff_capable(hdev) || !lmp_sniff_capable(conn)) |
| 343 | return; | 366 | return; |
| 344 | 367 | ||
| @@ -398,13 +421,14 @@ static void le_conn_timeout(struct work_struct *work) | |||
| 398 | hci_le_create_connection_cancel(conn); | 421 | hci_le_create_connection_cancel(conn); |
| 399 | } | 422 | } |
| 400 | 423 | ||
| 401 | struct hci_conn *hci_conn_add(struct hci_dev *hdev, int type, bdaddr_t *dst) | 424 | struct hci_conn *hci_conn_add(struct hci_dev *hdev, int type, bdaddr_t *dst, |
| 425 | u8 role) | ||
| 402 | { | 426 | { |
| 403 | struct hci_conn *conn; | 427 | struct hci_conn *conn; |
| 404 | 428 | ||
| 405 | BT_DBG("%s dst %pMR", hdev->name, dst); | 429 | BT_DBG("%s dst %pMR", hdev->name, dst); |
| 406 | 430 | ||
| 407 | conn = kzalloc(sizeof(struct hci_conn), GFP_KERNEL); | 431 | conn = kzalloc(sizeof(*conn), GFP_KERNEL); |
| 408 | if (!conn) | 432 | if (!conn) |
| 409 | return NULL; | 433 | return NULL; |
| 410 | 434 | ||
| @@ -412,6 +436,7 @@ struct hci_conn *hci_conn_add(struct hci_dev *hdev, int type, bdaddr_t *dst) | |||
| 412 | bacpy(&conn->src, &hdev->bdaddr); | 436 | bacpy(&conn->src, &hdev->bdaddr); |
| 413 | conn->hdev = hdev; | 437 | conn->hdev = hdev; |
| 414 | conn->type = type; | 438 | conn->type = type; |
| 439 | conn->role = role; | ||
| 415 | conn->mode = HCI_CM_ACTIVE; | 440 | conn->mode = HCI_CM_ACTIVE; |
| 416 | conn->state = BT_OPEN; | 441 | conn->state = BT_OPEN; |
| 417 | conn->auth_type = HCI_AT_GENERAL_BONDING; | 442 | conn->auth_type = HCI_AT_GENERAL_BONDING; |
| @@ -424,6 +449,9 @@ struct hci_conn *hci_conn_add(struct hci_dev *hdev, int type, bdaddr_t *dst) | |||
| 424 | set_bit(HCI_CONN_POWER_SAVE, &conn->flags); | 449 | set_bit(HCI_CONN_POWER_SAVE, &conn->flags); |
| 425 | conn->disc_timeout = HCI_DISCONN_TIMEOUT; | 450 | conn->disc_timeout = HCI_DISCONN_TIMEOUT; |
| 426 | 451 | ||
| 452 | if (conn->role == HCI_ROLE_MASTER) | ||
| 453 | conn->out = true; | ||
| 454 | |||
| 427 | switch (type) { | 455 | switch (type) { |
| 428 | case ACL_LINK: | 456 | case ACL_LINK: |
| 429 | conn->pkt_type = hdev->pkt_type & ACL_PTYPE_MASK; | 457 | conn->pkt_type = hdev->pkt_type & ACL_PTYPE_MASK; |
| @@ -529,7 +557,6 @@ struct hci_dev *hci_get_route(bdaddr_t *dst, bdaddr_t *src) | |||
| 529 | 557 | ||
| 530 | list_for_each_entry(d, &hci_dev_list, list) { | 558 | list_for_each_entry(d, &hci_dev_list, list) { |
| 531 | if (!test_bit(HCI_UP, &d->flags) || | 559 | if (!test_bit(HCI_UP, &d->flags) || |
| 532 | test_bit(HCI_RAW, &d->flags) || | ||
| 533 | test_bit(HCI_USER_CHANNEL, &d->dev_flags) || | 560 | test_bit(HCI_USER_CHANNEL, &d->dev_flags) || |
| 534 | d->dev_type != HCI_BREDR) | 561 | d->dev_type != HCI_BREDR) |
| 535 | continue; | 562 | continue; |
| @@ -627,7 +654,8 @@ static void hci_req_add_le_create_conn(struct hci_request *req, | |||
| 627 | cp.own_address_type = own_addr_type; | 654 | cp.own_address_type = own_addr_type; |
| 628 | cp.conn_interval_min = cpu_to_le16(conn->le_conn_min_interval); | 655 | cp.conn_interval_min = cpu_to_le16(conn->le_conn_min_interval); |
| 629 | cp.conn_interval_max = cpu_to_le16(conn->le_conn_max_interval); | 656 | cp.conn_interval_max = cpu_to_le16(conn->le_conn_max_interval); |
| 630 | cp.supervision_timeout = cpu_to_le16(0x002a); | 657 | cp.conn_latency = cpu_to_le16(conn->le_conn_latency); |
| 658 | cp.supervision_timeout = cpu_to_le16(conn->le_supv_timeout); | ||
| 631 | cp.min_ce_len = cpu_to_le16(0x0000); | 659 | cp.min_ce_len = cpu_to_le16(0x0000); |
| 632 | cp.max_ce_len = cpu_to_le16(0x0000); | 660 | cp.max_ce_len = cpu_to_le16(0x0000); |
| 633 | 661 | ||
| @@ -644,15 +672,12 @@ static void hci_req_directed_advertising(struct hci_request *req, | |||
| 644 | u8 own_addr_type; | 672 | u8 own_addr_type; |
| 645 | u8 enable; | 673 | u8 enable; |
| 646 | 674 | ||
| 647 | enable = 0x00; | 675 | /* Clear the HCI_LE_ADV bit temporarily so that the |
| 648 | hci_req_add(req, HCI_OP_LE_SET_ADV_ENABLE, sizeof(enable), &enable); | ||
| 649 | |||
| 650 | /* Clear the HCI_ADVERTISING bit temporarily so that the | ||
| 651 | * hci_update_random_address knows that it's safe to go ahead | 676 | * hci_update_random_address knows that it's safe to go ahead |
| 652 | * and write a new random address. The flag will be set back on | 677 | * and write a new random address. The flag will be set back on |
| 653 | * as soon as the SET_ADV_ENABLE HCI command completes. | 678 | * as soon as the SET_ADV_ENABLE HCI command completes. |
| 654 | */ | 679 | */ |
| 655 | clear_bit(HCI_ADVERTISING, &hdev->dev_flags); | 680 | clear_bit(HCI_LE_ADV, &hdev->dev_flags); |
| 656 | 681 | ||
| 657 | /* Set require_privacy to false so that the remote device has a | 682 | /* Set require_privacy to false so that the remote device has a |
| 658 | * chance of identifying us. | 683 | * chance of identifying us. |
| @@ -676,7 +701,8 @@ static void hci_req_directed_advertising(struct hci_request *req, | |||
| 676 | } | 701 | } |
| 677 | 702 | ||
| 678 | struct hci_conn *hci_connect_le(struct hci_dev *hdev, bdaddr_t *dst, | 703 | struct hci_conn *hci_connect_le(struct hci_dev *hdev, bdaddr_t *dst, |
| 679 | u8 dst_type, u8 sec_level, u8 auth_type) | 704 | u8 dst_type, u8 sec_level, u16 conn_timeout, |
| 705 | u8 role) | ||
| 680 | { | 706 | { |
| 681 | struct hci_conn_params *params; | 707 | struct hci_conn_params *params; |
| 682 | struct hci_conn *conn; | 708 | struct hci_conn *conn; |
| @@ -696,7 +722,6 @@ struct hci_conn *hci_connect_le(struct hci_dev *hdev, bdaddr_t *dst, | |||
| 696 | conn = hci_conn_hash_lookup_ba(hdev, LE_LINK, dst); | 722 | conn = hci_conn_hash_lookup_ba(hdev, LE_LINK, dst); |
| 697 | if (conn) { | 723 | if (conn) { |
| 698 | conn->pending_sec_level = sec_level; | 724 | conn->pending_sec_level = sec_level; |
| 699 | conn->auth_type = auth_type; | ||
| 700 | goto done; | 725 | goto done; |
| 701 | } | 726 | } |
| 702 | 727 | ||
| @@ -726,32 +751,56 @@ struct hci_conn *hci_connect_le(struct hci_dev *hdev, bdaddr_t *dst, | |||
| 726 | dst_type = ADDR_LE_DEV_RANDOM; | 751 | dst_type = ADDR_LE_DEV_RANDOM; |
| 727 | } | 752 | } |
| 728 | 753 | ||
| 729 | conn = hci_conn_add(hdev, LE_LINK, dst); | 754 | conn = hci_conn_add(hdev, LE_LINK, dst, role); |
| 730 | if (!conn) | 755 | if (!conn) |
| 731 | return ERR_PTR(-ENOMEM); | 756 | return ERR_PTR(-ENOMEM); |
| 732 | 757 | ||
| 733 | conn->dst_type = dst_type; | 758 | conn->dst_type = dst_type; |
| 734 | conn->sec_level = BT_SECURITY_LOW; | 759 | conn->sec_level = BT_SECURITY_LOW; |
| 735 | conn->pending_sec_level = sec_level; | 760 | conn->pending_sec_level = sec_level; |
| 736 | conn->auth_type = auth_type; | 761 | conn->conn_timeout = conn_timeout; |
| 737 | 762 | ||
| 738 | hci_req_init(&req, hdev); | 763 | hci_req_init(&req, hdev); |
| 739 | 764 | ||
| 740 | if (test_bit(HCI_ADVERTISING, &hdev->dev_flags)) { | 765 | /* Disable advertising if we're active. For master role |
| 766 | * connections most controllers will refuse to connect if | ||
| 767 | * advertising is enabled, and for slave role connections we | ||
| 768 | * anyway have to disable it in order to start directed | ||
| 769 | * advertising. | ||
| 770 | */ | ||
| 771 | if (test_bit(HCI_LE_ADV, &hdev->dev_flags)) { | ||
| 772 | u8 enable = 0x00; | ||
| 773 | hci_req_add(&req, HCI_OP_LE_SET_ADV_ENABLE, sizeof(enable), | ||
| 774 | &enable); | ||
| 775 | } | ||
| 776 | |||
| 777 | /* If requested to connect as slave use directed advertising */ | ||
| 778 | if (conn->role == HCI_ROLE_SLAVE) { | ||
| 779 | /* If we're active scanning most controllers are unable | ||
| 780 | * to initiate advertising. Simply reject the attempt. | ||
| 781 | */ | ||
| 782 | if (test_bit(HCI_LE_SCAN, &hdev->dev_flags) && | ||
| 783 | hdev->le_scan_type == LE_SCAN_ACTIVE) { | ||
| 784 | skb_queue_purge(&req.cmd_q); | ||
| 785 | hci_conn_del(conn); | ||
| 786 | return ERR_PTR(-EBUSY); | ||
| 787 | } | ||
| 788 | |||
| 741 | hci_req_directed_advertising(&req, conn); | 789 | hci_req_directed_advertising(&req, conn); |
| 742 | goto create_conn; | 790 | goto create_conn; |
| 743 | } | 791 | } |
| 744 | 792 | ||
| 745 | conn->out = true; | ||
| 746 | conn->link_mode |= HCI_LM_MASTER; | ||
| 747 | |||
| 748 | params = hci_conn_params_lookup(hdev, &conn->dst, conn->dst_type); | 793 | params = hci_conn_params_lookup(hdev, &conn->dst, conn->dst_type); |
| 749 | if (params) { | 794 | if (params) { |
| 750 | conn->le_conn_min_interval = params->conn_min_interval; | 795 | conn->le_conn_min_interval = params->conn_min_interval; |
| 751 | conn->le_conn_max_interval = params->conn_max_interval; | 796 | conn->le_conn_max_interval = params->conn_max_interval; |
| 797 | conn->le_conn_latency = params->conn_latency; | ||
| 798 | conn->le_supv_timeout = params->supervision_timeout; | ||
| 752 | } else { | 799 | } else { |
| 753 | conn->le_conn_min_interval = hdev->le_conn_min_interval; | 800 | conn->le_conn_min_interval = hdev->le_conn_min_interval; |
| 754 | conn->le_conn_max_interval = hdev->le_conn_max_interval; | 801 | conn->le_conn_max_interval = hdev->le_conn_max_interval; |
| 802 | conn->le_conn_latency = hdev->le_conn_latency; | ||
| 803 | conn->le_supv_timeout = hdev->le_supv_timeout; | ||
| 755 | } | 804 | } |
| 756 | 805 | ||
| 757 | /* If controller is scanning, we stop it since some controllers are | 806 | /* If controller is scanning, we stop it since some controllers are |
| @@ -785,11 +834,11 @@ struct hci_conn *hci_connect_acl(struct hci_dev *hdev, bdaddr_t *dst, | |||
| 785 | struct hci_conn *acl; | 834 | struct hci_conn *acl; |
| 786 | 835 | ||
| 787 | if (!test_bit(HCI_BREDR_ENABLED, &hdev->dev_flags)) | 836 | if (!test_bit(HCI_BREDR_ENABLED, &hdev->dev_flags)) |
| 788 | return ERR_PTR(-ENOTSUPP); | 837 | return ERR_PTR(-EOPNOTSUPP); |
| 789 | 838 | ||
| 790 | acl = hci_conn_hash_lookup_ba(hdev, ACL_LINK, dst); | 839 | acl = hci_conn_hash_lookup_ba(hdev, ACL_LINK, dst); |
| 791 | if (!acl) { | 840 | if (!acl) { |
| 792 | acl = hci_conn_add(hdev, ACL_LINK, dst); | 841 | acl = hci_conn_add(hdev, ACL_LINK, dst, HCI_ROLE_MASTER); |
| 793 | if (!acl) | 842 | if (!acl) |
| 794 | return ERR_PTR(-ENOMEM); | 843 | return ERR_PTR(-ENOMEM); |
| 795 | } | 844 | } |
| @@ -818,7 +867,7 @@ struct hci_conn *hci_connect_sco(struct hci_dev *hdev, int type, bdaddr_t *dst, | |||
| 818 | 867 | ||
| 819 | sco = hci_conn_hash_lookup_ba(hdev, type, dst); | 868 | sco = hci_conn_hash_lookup_ba(hdev, type, dst); |
| 820 | if (!sco) { | 869 | if (!sco) { |
| 821 | sco = hci_conn_add(hdev, type, dst); | 870 | sco = hci_conn_add(hdev, type, dst, HCI_ROLE_MASTER); |
| 822 | if (!sco) { | 871 | if (!sco) { |
| 823 | hci_conn_drop(acl); | 872 | hci_conn_drop(acl); |
| 824 | return ERR_PTR(-ENOMEM); | 873 | return ERR_PTR(-ENOMEM); |
| @@ -865,7 +914,8 @@ int hci_conn_check_link_mode(struct hci_conn *conn) | |||
| 865 | return 0; | 914 | return 0; |
| 866 | } | 915 | } |
| 867 | 916 | ||
| 868 | if (hci_conn_ssp_enabled(conn) && !(conn->link_mode & HCI_LM_ENCRYPT)) | 917 | if (hci_conn_ssp_enabled(conn) && |
| 918 | !test_bit(HCI_CONN_ENCRYPT, &conn->flags)) | ||
| 869 | return 0; | 919 | return 0; |
| 870 | 920 | ||
| 871 | return 1; | 921 | return 1; |
| @@ -881,7 +931,7 @@ static int hci_conn_auth(struct hci_conn *conn, __u8 sec_level, __u8 auth_type) | |||
| 881 | 931 | ||
| 882 | if (sec_level > conn->sec_level) | 932 | if (sec_level > conn->sec_level) |
| 883 | conn->pending_sec_level = sec_level; | 933 | conn->pending_sec_level = sec_level; |
| 884 | else if (conn->link_mode & HCI_LM_AUTH) | 934 | else if (test_bit(HCI_CONN_AUTH, &conn->flags)) |
| 885 | return 1; | 935 | return 1; |
| 886 | 936 | ||
| 887 | /* Make sure we preserve an existing MITM requirement*/ | 937 | /* Make sure we preserve an existing MITM requirement*/ |
| @@ -899,7 +949,7 @@ static int hci_conn_auth(struct hci_conn *conn, __u8 sec_level, __u8 auth_type) | |||
| 899 | /* If we're already encrypted set the REAUTH_PEND flag, | 949 | /* If we're already encrypted set the REAUTH_PEND flag, |
| 900 | * otherwise set the ENCRYPT_PEND. | 950 | * otherwise set the ENCRYPT_PEND. |
| 901 | */ | 951 | */ |
| 902 | if (conn->link_mode & HCI_LM_ENCRYPT) | 952 | if (test_bit(HCI_CONN_ENCRYPT, &conn->flags)) |
| 903 | set_bit(HCI_CONN_REAUTH_PEND, &conn->flags); | 953 | set_bit(HCI_CONN_REAUTH_PEND, &conn->flags); |
| 904 | else | 954 | else |
| 905 | set_bit(HCI_CONN_ENCRYPT_PEND, &conn->flags); | 955 | set_bit(HCI_CONN_ENCRYPT_PEND, &conn->flags); |
| @@ -923,7 +973,8 @@ static void hci_conn_encrypt(struct hci_conn *conn) | |||
| 923 | } | 973 | } |
| 924 | 974 | ||
| 925 | /* Enable security */ | 975 | /* Enable security */ |
| 926 | int hci_conn_security(struct hci_conn *conn, __u8 sec_level, __u8 auth_type) | 976 | int hci_conn_security(struct hci_conn *conn, __u8 sec_level, __u8 auth_type, |
| 977 | bool initiator) | ||
| 927 | { | 978 | { |
| 928 | BT_DBG("hcon %p", conn); | 979 | BT_DBG("hcon %p", conn); |
| 929 | 980 | ||
| @@ -940,7 +991,7 @@ int hci_conn_security(struct hci_conn *conn, __u8 sec_level, __u8 auth_type) | |||
| 940 | return 1; | 991 | return 1; |
| 941 | 992 | ||
| 942 | /* For other security levels we need the link key. */ | 993 | /* For other security levels we need the link key. */ |
| 943 | if (!(conn->link_mode & HCI_LM_AUTH)) | 994 | if (!test_bit(HCI_CONN_AUTH, &conn->flags)) |
| 944 | goto auth; | 995 | goto auth; |
| 945 | 996 | ||
| 946 | /* An authenticated FIPS approved combination key has sufficient | 997 | /* An authenticated FIPS approved combination key has sufficient |
| @@ -976,11 +1027,14 @@ auth: | |||
| 976 | if (test_bit(HCI_CONN_ENCRYPT_PEND, &conn->flags)) | 1027 | if (test_bit(HCI_CONN_ENCRYPT_PEND, &conn->flags)) |
| 977 | return 0; | 1028 | return 0; |
| 978 | 1029 | ||
| 1030 | if (initiator) | ||
| 1031 | set_bit(HCI_CONN_AUTH_INITIATOR, &conn->flags); | ||
| 1032 | |||
| 979 | if (!hci_conn_auth(conn, sec_level, auth_type)) | 1033 | if (!hci_conn_auth(conn, sec_level, auth_type)) |
| 980 | return 0; | 1034 | return 0; |
| 981 | 1035 | ||
| 982 | encrypt: | 1036 | encrypt: |
| 983 | if (conn->link_mode & HCI_LM_ENCRYPT) | 1037 | if (test_bit(HCI_CONN_ENCRYPT, &conn->flags)) |
| 984 | return 1; | 1038 | return 1; |
| 985 | 1039 | ||
| 986 | hci_conn_encrypt(conn); | 1040 | hci_conn_encrypt(conn); |
| @@ -1027,7 +1081,7 @@ int hci_conn_switch_role(struct hci_conn *conn, __u8 role) | |||
| 1027 | { | 1081 | { |
| 1028 | BT_DBG("hcon %p", conn); | 1082 | BT_DBG("hcon %p", conn); |
| 1029 | 1083 | ||
| 1030 | if (!role && conn->link_mode & HCI_LM_MASTER) | 1084 | if (role == conn->role) |
| 1031 | return 1; | 1085 | return 1; |
| 1032 | 1086 | ||
| 1033 | if (!test_and_set_bit(HCI_CONN_RSWITCH_PEND, &conn->flags)) { | 1087 | if (!test_and_set_bit(HCI_CONN_RSWITCH_PEND, &conn->flags)) { |
| @@ -1048,9 +1102,6 @@ void hci_conn_enter_active_mode(struct hci_conn *conn, __u8 force_active) | |||
| 1048 | 1102 | ||
| 1049 | BT_DBG("hcon %p mode %d", conn, conn->mode); | 1103 | BT_DBG("hcon %p mode %d", conn, conn->mode); |
| 1050 | 1104 | ||
| 1051 | if (test_bit(HCI_RAW, &hdev->flags)) | ||
| 1052 | return; | ||
| 1053 | |||
| 1054 | if (conn->mode != HCI_CM_SNIFF) | 1105 | if (conn->mode != HCI_CM_SNIFF) |
| 1055 | goto timer; | 1106 | goto timer; |
| 1056 | 1107 | ||
| @@ -1101,6 +1152,28 @@ void hci_conn_check_pending(struct hci_dev *hdev) | |||
| 1101 | hci_dev_unlock(hdev); | 1152 | hci_dev_unlock(hdev); |
| 1102 | } | 1153 | } |
| 1103 | 1154 | ||
| 1155 | static u32 get_link_mode(struct hci_conn *conn) | ||
| 1156 | { | ||
| 1157 | u32 link_mode = 0; | ||
| 1158 | |||
| 1159 | if (conn->role == HCI_ROLE_MASTER) | ||
| 1160 | link_mode |= HCI_LM_MASTER; | ||
| 1161 | |||
| 1162 | if (test_bit(HCI_CONN_ENCRYPT, &conn->flags)) | ||
| 1163 | link_mode |= HCI_LM_ENCRYPT; | ||
| 1164 | |||
| 1165 | if (test_bit(HCI_CONN_AUTH, &conn->flags)) | ||
| 1166 | link_mode |= HCI_LM_AUTH; | ||
| 1167 | |||
| 1168 | if (test_bit(HCI_CONN_SECURE, &conn->flags)) | ||
| 1169 | link_mode |= HCI_LM_SECURE; | ||
| 1170 | |||
| 1171 | if (test_bit(HCI_CONN_FIPS, &conn->flags)) | ||
| 1172 | link_mode |= HCI_LM_FIPS; | ||
| 1173 | |||
| 1174 | return link_mode; | ||
| 1175 | } | ||
| 1176 | |||
| 1104 | int hci_get_conn_list(void __user *arg) | 1177 | int hci_get_conn_list(void __user *arg) |
| 1105 | { | 1178 | { |
| 1106 | struct hci_conn *c; | 1179 | struct hci_conn *c; |
| @@ -1136,7 +1209,7 @@ int hci_get_conn_list(void __user *arg) | |||
| 1136 | (ci + n)->type = c->type; | 1209 | (ci + n)->type = c->type; |
| 1137 | (ci + n)->out = c->out; | 1210 | (ci + n)->out = c->out; |
| 1138 | (ci + n)->state = c->state; | 1211 | (ci + n)->state = c->state; |
| 1139 | (ci + n)->link_mode = c->link_mode; | 1212 | (ci + n)->link_mode = get_link_mode(c); |
| 1140 | if (++n >= req.conn_num) | 1213 | if (++n >= req.conn_num) |
| 1141 | break; | 1214 | break; |
| 1142 | } | 1215 | } |
| @@ -1172,7 +1245,7 @@ int hci_get_conn_info(struct hci_dev *hdev, void __user *arg) | |||
| 1172 | ci.type = conn->type; | 1245 | ci.type = conn->type; |
| 1173 | ci.out = conn->out; | 1246 | ci.out = conn->out; |
| 1174 | ci.state = conn->state; | 1247 | ci.state = conn->state; |
| 1175 | ci.link_mode = conn->link_mode; | 1248 | ci.link_mode = get_link_mode(conn); |
| 1176 | } | 1249 | } |
| 1177 | hci_dev_unlock(hdev); | 1250 | hci_dev_unlock(hdev); |
| 1178 | 1251 | ||
| @@ -1209,7 +1282,7 @@ struct hci_chan *hci_chan_create(struct hci_conn *conn) | |||
| 1209 | 1282 | ||
| 1210 | BT_DBG("%s hcon %p", hdev->name, conn); | 1283 | BT_DBG("%s hcon %p", hdev->name, conn); |
| 1211 | 1284 | ||
| 1212 | chan = kzalloc(sizeof(struct hci_chan), GFP_KERNEL); | 1285 | chan = kzalloc(sizeof(*chan), GFP_KERNEL); |
| 1213 | if (!chan) | 1286 | if (!chan) |
| 1214 | return NULL; | 1287 | return NULL; |
| 1215 | 1288 | ||
diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c index 0a43cce9a914..c32d361c0cf7 100644 --- a/net/bluetooth/hci_core.c +++ b/net/bluetooth/hci_core.c | |||
| @@ -35,6 +35,7 @@ | |||
| 35 | #include <net/bluetooth/bluetooth.h> | 35 | #include <net/bluetooth/bluetooth.h> |
| 36 | #include <net/bluetooth/hci_core.h> | 36 | #include <net/bluetooth/hci_core.h> |
| 37 | #include <net/bluetooth/l2cap.h> | 37 | #include <net/bluetooth/l2cap.h> |
| 38 | #include <net/bluetooth/mgmt.h> | ||
| 38 | 39 | ||
| 39 | #include "smp.h" | 40 | #include "smp.h" |
| 40 | 41 | ||
| @@ -53,6 +54,15 @@ DEFINE_RWLOCK(hci_cb_list_lock); | |||
| 53 | /* HCI ID Numbering */ | 54 | /* HCI ID Numbering */ |
| 54 | static DEFINE_IDA(hci_index_ida); | 55 | static DEFINE_IDA(hci_index_ida); |
| 55 | 56 | ||
| 57 | /* ----- HCI requests ----- */ | ||
| 58 | |||
| 59 | #define HCI_REQ_DONE 0 | ||
| 60 | #define HCI_REQ_PEND 1 | ||
| 61 | #define HCI_REQ_CANCELED 2 | ||
| 62 | |||
| 63 | #define hci_req_lock(d) mutex_lock(&d->req_lock) | ||
| 64 | #define hci_req_unlock(d) mutex_unlock(&d->req_lock) | ||
| 65 | |||
| 56 | /* ---- HCI notifications ---- */ | 66 | /* ---- HCI notifications ---- */ |
| 57 | 67 | ||
| 58 | static void hci_notify(struct hci_dev *hdev, int event) | 68 | static void hci_notify(struct hci_dev *hdev, int event) |
| @@ -68,7 +78,7 @@ static ssize_t dut_mode_read(struct file *file, char __user *user_buf, | |||
| 68 | struct hci_dev *hdev = file->private_data; | 78 | struct hci_dev *hdev = file->private_data; |
| 69 | char buf[3]; | 79 | char buf[3]; |
| 70 | 80 | ||
| 71 | buf[0] = test_bit(HCI_DUT_MODE, &hdev->dev_flags) ? 'Y': 'N'; | 81 | buf[0] = test_bit(HCI_DUT_MODE, &hdev->dbg_flags) ? 'Y': 'N'; |
| 72 | buf[1] = '\n'; | 82 | buf[1] = '\n'; |
| 73 | buf[2] = '\0'; | 83 | buf[2] = '\0'; |
| 74 | return simple_read_from_buffer(user_buf, count, ppos, buf, 2); | 84 | return simple_read_from_buffer(user_buf, count, ppos, buf, 2); |
| @@ -94,7 +104,7 @@ static ssize_t dut_mode_write(struct file *file, const char __user *user_buf, | |||
| 94 | if (strtobool(buf, &enable)) | 104 | if (strtobool(buf, &enable)) |
| 95 | return -EINVAL; | 105 | return -EINVAL; |
| 96 | 106 | ||
| 97 | if (enable == test_bit(HCI_DUT_MODE, &hdev->dev_flags)) | 107 | if (enable == test_bit(HCI_DUT_MODE, &hdev->dbg_flags)) |
| 98 | return -EALREADY; | 108 | return -EALREADY; |
| 99 | 109 | ||
| 100 | hci_req_lock(hdev); | 110 | hci_req_lock(hdev); |
| @@ -115,7 +125,7 @@ static ssize_t dut_mode_write(struct file *file, const char __user *user_buf, | |||
| 115 | if (err < 0) | 125 | if (err < 0) |
| 116 | return err; | 126 | return err; |
| 117 | 127 | ||
| 118 | change_bit(HCI_DUT_MODE, &hdev->dev_flags); | 128 | change_bit(HCI_DUT_MODE, &hdev->dbg_flags); |
| 119 | 129 | ||
| 120 | return count; | 130 | return count; |
| 121 | } | 131 | } |
| @@ -190,6 +200,31 @@ static const struct file_operations blacklist_fops = { | |||
| 190 | .release = single_release, | 200 | .release = single_release, |
| 191 | }; | 201 | }; |
| 192 | 202 | ||
| 203 | static int whitelist_show(struct seq_file *f, void *p) | ||
| 204 | { | ||
| 205 | struct hci_dev *hdev = f->private; | ||
| 206 | struct bdaddr_list *b; | ||
| 207 | |||
| 208 | hci_dev_lock(hdev); | ||
| 209 | list_for_each_entry(b, &hdev->whitelist, list) | ||
| 210 | seq_printf(f, "%pMR (type %u)\n", &b->bdaddr, b->bdaddr_type); | ||
| 211 | hci_dev_unlock(hdev); | ||
| 212 | |||
| 213 | return 0; | ||
| 214 | } | ||
| 215 | |||
| 216 | static int whitelist_open(struct inode *inode, struct file *file) | ||
| 217 | { | ||
| 218 | return single_open(file, whitelist_show, inode->i_private); | ||
| 219 | } | ||
| 220 | |||
| 221 | static const struct file_operations whitelist_fops = { | ||
| 222 | .open = whitelist_open, | ||
| 223 | .read = seq_read, | ||
| 224 | .llseek = seq_lseek, | ||
| 225 | .release = single_release, | ||
| 226 | }; | ||
| 227 | |||
| 193 | static int uuids_show(struct seq_file *f, void *p) | 228 | static int uuids_show(struct seq_file *f, void *p) |
| 194 | { | 229 | { |
| 195 | struct hci_dev *hdev = f->private; | 230 | struct hci_dev *hdev = f->private; |
| @@ -352,62 +387,13 @@ static int auto_accept_delay_get(void *data, u64 *val) | |||
| 352 | DEFINE_SIMPLE_ATTRIBUTE(auto_accept_delay_fops, auto_accept_delay_get, | 387 | DEFINE_SIMPLE_ATTRIBUTE(auto_accept_delay_fops, auto_accept_delay_get, |
| 353 | auto_accept_delay_set, "%llu\n"); | 388 | auto_accept_delay_set, "%llu\n"); |
| 354 | 389 | ||
| 355 | static int ssp_debug_mode_set(void *data, u64 val) | ||
| 356 | { | ||
| 357 | struct hci_dev *hdev = data; | ||
| 358 | struct sk_buff *skb; | ||
| 359 | __u8 mode; | ||
| 360 | int err; | ||
| 361 | |||
| 362 | if (val != 0 && val != 1) | ||
| 363 | return -EINVAL; | ||
| 364 | |||
| 365 | if (!test_bit(HCI_UP, &hdev->flags)) | ||
| 366 | return -ENETDOWN; | ||
| 367 | |||
| 368 | hci_req_lock(hdev); | ||
| 369 | mode = val; | ||
| 370 | skb = __hci_cmd_sync(hdev, HCI_OP_WRITE_SSP_DEBUG_MODE, sizeof(mode), | ||
| 371 | &mode, HCI_CMD_TIMEOUT); | ||
| 372 | hci_req_unlock(hdev); | ||
| 373 | |||
| 374 | if (IS_ERR(skb)) | ||
| 375 | return PTR_ERR(skb); | ||
| 376 | |||
| 377 | err = -bt_to_errno(skb->data[0]); | ||
| 378 | kfree_skb(skb); | ||
| 379 | |||
| 380 | if (err < 0) | ||
| 381 | return err; | ||
| 382 | |||
| 383 | hci_dev_lock(hdev); | ||
| 384 | hdev->ssp_debug_mode = val; | ||
| 385 | hci_dev_unlock(hdev); | ||
| 386 | |||
| 387 | return 0; | ||
| 388 | } | ||
| 389 | |||
| 390 | static int ssp_debug_mode_get(void *data, u64 *val) | ||
| 391 | { | ||
| 392 | struct hci_dev *hdev = data; | ||
| 393 | |||
| 394 | hci_dev_lock(hdev); | ||
| 395 | *val = hdev->ssp_debug_mode; | ||
| 396 | hci_dev_unlock(hdev); | ||
| 397 | |||
| 398 | return 0; | ||
| 399 | } | ||
| 400 | |||
| 401 | DEFINE_SIMPLE_ATTRIBUTE(ssp_debug_mode_fops, ssp_debug_mode_get, | ||
| 402 | ssp_debug_mode_set, "%llu\n"); | ||
| 403 | |||
| 404 | static ssize_t force_sc_support_read(struct file *file, char __user *user_buf, | 390 | static ssize_t force_sc_support_read(struct file *file, char __user *user_buf, |
| 405 | size_t count, loff_t *ppos) | 391 | size_t count, loff_t *ppos) |
| 406 | { | 392 | { |
| 407 | struct hci_dev *hdev = file->private_data; | 393 | struct hci_dev *hdev = file->private_data; |
| 408 | char buf[3]; | 394 | char buf[3]; |
| 409 | 395 | ||
| 410 | buf[0] = test_bit(HCI_FORCE_SC, &hdev->dev_flags) ? 'Y': 'N'; | 396 | buf[0] = test_bit(HCI_FORCE_SC, &hdev->dbg_flags) ? 'Y': 'N'; |
| 411 | buf[1] = '\n'; | 397 | buf[1] = '\n'; |
| 412 | buf[2] = '\0'; | 398 | buf[2] = '\0'; |
| 413 | return simple_read_from_buffer(user_buf, count, ppos, buf, 2); | 399 | return simple_read_from_buffer(user_buf, count, ppos, buf, 2); |
| @@ -432,10 +418,10 @@ static ssize_t force_sc_support_write(struct file *file, | |||
| 432 | if (strtobool(buf, &enable)) | 418 | if (strtobool(buf, &enable)) |
| 433 | return -EINVAL; | 419 | return -EINVAL; |
| 434 | 420 | ||
| 435 | if (enable == test_bit(HCI_FORCE_SC, &hdev->dev_flags)) | 421 | if (enable == test_bit(HCI_FORCE_SC, &hdev->dbg_flags)) |
| 436 | return -EALREADY; | 422 | return -EALREADY; |
| 437 | 423 | ||
| 438 | change_bit(HCI_FORCE_SC, &hdev->dev_flags); | 424 | change_bit(HCI_FORCE_SC, &hdev->dbg_flags); |
| 439 | 425 | ||
| 440 | return count; | 426 | return count; |
| 441 | } | 427 | } |
| @@ -719,7 +705,7 @@ static ssize_t force_static_address_read(struct file *file, | |||
| 719 | struct hci_dev *hdev = file->private_data; | 705 | struct hci_dev *hdev = file->private_data; |
| 720 | char buf[3]; | 706 | char buf[3]; |
| 721 | 707 | ||
| 722 | buf[0] = test_bit(HCI_FORCE_STATIC_ADDR, &hdev->dev_flags) ? 'Y': 'N'; | 708 | buf[0] = test_bit(HCI_FORCE_STATIC_ADDR, &hdev->dbg_flags) ? 'Y': 'N'; |
| 723 | buf[1] = '\n'; | 709 | buf[1] = '\n'; |
| 724 | buf[2] = '\0'; | 710 | buf[2] = '\0'; |
| 725 | return simple_read_from_buffer(user_buf, count, ppos, buf, 2); | 711 | return simple_read_from_buffer(user_buf, count, ppos, buf, 2); |
| @@ -744,10 +730,10 @@ static ssize_t force_static_address_write(struct file *file, | |||
| 744 | if (strtobool(buf, &enable)) | 730 | if (strtobool(buf, &enable)) |
| 745 | return -EINVAL; | 731 | return -EINVAL; |
| 746 | 732 | ||
| 747 | if (enable == test_bit(HCI_FORCE_STATIC_ADDR, &hdev->dev_flags)) | 733 | if (enable == test_bit(HCI_FORCE_STATIC_ADDR, &hdev->dbg_flags)) |
| 748 | return -EALREADY; | 734 | return -EALREADY; |
| 749 | 735 | ||
| 750 | change_bit(HCI_FORCE_STATIC_ADDR, &hdev->dev_flags); | 736 | change_bit(HCI_FORCE_STATIC_ADDR, &hdev->dbg_flags); |
| 751 | 737 | ||
| 752 | return count; | 738 | return count; |
| 753 | } | 739 | } |
| @@ -900,177 +886,169 @@ static int conn_max_interval_get(void *data, u64 *val) | |||
| 900 | DEFINE_SIMPLE_ATTRIBUTE(conn_max_interval_fops, conn_max_interval_get, | 886 | DEFINE_SIMPLE_ATTRIBUTE(conn_max_interval_fops, conn_max_interval_get, |
| 901 | conn_max_interval_set, "%llu\n"); | 887 | conn_max_interval_set, "%llu\n"); |
| 902 | 888 | ||
| 903 | static int adv_channel_map_set(void *data, u64 val) | 889 | static int conn_latency_set(void *data, u64 val) |
| 904 | { | 890 | { |
| 905 | struct hci_dev *hdev = data; | 891 | struct hci_dev *hdev = data; |
| 906 | 892 | ||
| 907 | if (val < 0x01 || val > 0x07) | 893 | if (val > 0x01f3) |
| 908 | return -EINVAL; | 894 | return -EINVAL; |
| 909 | 895 | ||
| 910 | hci_dev_lock(hdev); | 896 | hci_dev_lock(hdev); |
| 911 | hdev->le_adv_channel_map = val; | 897 | hdev->le_conn_latency = val; |
| 912 | hci_dev_unlock(hdev); | 898 | hci_dev_unlock(hdev); |
| 913 | 899 | ||
| 914 | return 0; | 900 | return 0; |
| 915 | } | 901 | } |
| 916 | 902 | ||
| 917 | static int adv_channel_map_get(void *data, u64 *val) | 903 | static int conn_latency_get(void *data, u64 *val) |
| 918 | { | 904 | { |
| 919 | struct hci_dev *hdev = data; | 905 | struct hci_dev *hdev = data; |
| 920 | 906 | ||
| 921 | hci_dev_lock(hdev); | 907 | hci_dev_lock(hdev); |
| 922 | *val = hdev->le_adv_channel_map; | 908 | *val = hdev->le_conn_latency; |
| 923 | hci_dev_unlock(hdev); | 909 | hci_dev_unlock(hdev); |
| 924 | 910 | ||
| 925 | return 0; | 911 | return 0; |
| 926 | } | 912 | } |
| 927 | 913 | ||
| 928 | DEFINE_SIMPLE_ATTRIBUTE(adv_channel_map_fops, adv_channel_map_get, | 914 | DEFINE_SIMPLE_ATTRIBUTE(conn_latency_fops, conn_latency_get, |
| 929 | adv_channel_map_set, "%llu\n"); | 915 | conn_latency_set, "%llu\n"); |
| 930 | 916 | ||
| 931 | static ssize_t lowpan_read(struct file *file, char __user *user_buf, | 917 | static int supervision_timeout_set(void *data, u64 val) |
| 932 | size_t count, loff_t *ppos) | ||
| 933 | { | 918 | { |
| 934 | struct hci_dev *hdev = file->private_data; | 919 | struct hci_dev *hdev = data; |
| 935 | char buf[3]; | ||
| 936 | 920 | ||
| 937 | buf[0] = test_bit(HCI_6LOWPAN_ENABLED, &hdev->dev_flags) ? 'Y' : 'N'; | 921 | if (val < 0x000a || val > 0x0c80) |
| 938 | buf[1] = '\n'; | 922 | return -EINVAL; |
| 939 | buf[2] = '\0'; | 923 | |
| 940 | return simple_read_from_buffer(user_buf, count, ppos, buf, 2); | 924 | hci_dev_lock(hdev); |
| 925 | hdev->le_supv_timeout = val; | ||
| 926 | hci_dev_unlock(hdev); | ||
| 927 | |||
| 928 | return 0; | ||
| 941 | } | 929 | } |
| 942 | 930 | ||
| 943 | static ssize_t lowpan_write(struct file *fp, const char __user *user_buffer, | 931 | static int supervision_timeout_get(void *data, u64 *val) |
| 944 | size_t count, loff_t *position) | ||
| 945 | { | 932 | { |
| 946 | struct hci_dev *hdev = fp->private_data; | 933 | struct hci_dev *hdev = data; |
| 947 | bool enable; | ||
| 948 | char buf[32]; | ||
| 949 | size_t buf_size = min(count, (sizeof(buf)-1)); | ||
| 950 | 934 | ||
| 951 | if (copy_from_user(buf, user_buffer, buf_size)) | 935 | hci_dev_lock(hdev); |
| 952 | return -EFAULT; | 936 | *val = hdev->le_supv_timeout; |
| 937 | hci_dev_unlock(hdev); | ||
| 953 | 938 | ||
| 954 | buf[buf_size] = '\0'; | 939 | return 0; |
| 940 | } | ||
| 955 | 941 | ||
| 956 | if (strtobool(buf, &enable) < 0) | 942 | DEFINE_SIMPLE_ATTRIBUTE(supervision_timeout_fops, supervision_timeout_get, |
| 957 | return -EINVAL; | 943 | supervision_timeout_set, "%llu\n"); |
| 958 | 944 | ||
| 959 | if (enable == test_bit(HCI_6LOWPAN_ENABLED, &hdev->dev_flags)) | 945 | static int adv_channel_map_set(void *data, u64 val) |
| 960 | return -EALREADY; | 946 | { |
| 947 | struct hci_dev *hdev = data; | ||
| 961 | 948 | ||
| 962 | change_bit(HCI_6LOWPAN_ENABLED, &hdev->dev_flags); | 949 | if (val < 0x01 || val > 0x07) |
| 950 | return -EINVAL; | ||
| 963 | 951 | ||
| 964 | return count; | 952 | hci_dev_lock(hdev); |
| 965 | } | 953 | hdev->le_adv_channel_map = val; |
| 954 | hci_dev_unlock(hdev); | ||
| 966 | 955 | ||
| 967 | static const struct file_operations lowpan_debugfs_fops = { | 956 | return 0; |
| 968 | .open = simple_open, | 957 | } |
| 969 | .read = lowpan_read, | ||
| 970 | .write = lowpan_write, | ||
| 971 | .llseek = default_llseek, | ||
| 972 | }; | ||
| 973 | 958 | ||
| 974 | static int le_auto_conn_show(struct seq_file *sf, void *ptr) | 959 | static int adv_channel_map_get(void *data, u64 *val) |
| 975 | { | 960 | { |
| 976 | struct hci_dev *hdev = sf->private; | 961 | struct hci_dev *hdev = data; |
| 977 | struct hci_conn_params *p; | ||
| 978 | 962 | ||
| 979 | hci_dev_lock(hdev); | 963 | hci_dev_lock(hdev); |
| 964 | *val = hdev->le_adv_channel_map; | ||
| 965 | hci_dev_unlock(hdev); | ||
| 980 | 966 | ||
| 981 | list_for_each_entry(p, &hdev->le_conn_params, list) { | 967 | return 0; |
| 982 | seq_printf(sf, "%pMR %u %u\n", &p->addr, p->addr_type, | 968 | } |
| 983 | p->auto_connect); | 969 | |
| 984 | } | 970 | DEFINE_SIMPLE_ATTRIBUTE(adv_channel_map_fops, adv_channel_map_get, |
| 971 | adv_channel_map_set, "%llu\n"); | ||
| 985 | 972 | ||
| 973 | static int adv_min_interval_set(void *data, u64 val) | ||
| 974 | { | ||
| 975 | struct hci_dev *hdev = data; | ||
| 976 | |||
| 977 | if (val < 0x0020 || val > 0x4000 || val > hdev->le_adv_max_interval) | ||
| 978 | return -EINVAL; | ||
| 979 | |||
| 980 | hci_dev_lock(hdev); | ||
| 981 | hdev->le_adv_min_interval = val; | ||
| 986 | hci_dev_unlock(hdev); | 982 | hci_dev_unlock(hdev); |
| 987 | 983 | ||
| 988 | return 0; | 984 | return 0; |
| 989 | } | 985 | } |
| 990 | 986 | ||
| 991 | static int le_auto_conn_open(struct inode *inode, struct file *file) | 987 | static int adv_min_interval_get(void *data, u64 *val) |
| 992 | { | 988 | { |
| 993 | return single_open(file, le_auto_conn_show, inode->i_private); | 989 | struct hci_dev *hdev = data; |
| 990 | |||
| 991 | hci_dev_lock(hdev); | ||
| 992 | *val = hdev->le_adv_min_interval; | ||
| 993 | hci_dev_unlock(hdev); | ||
| 994 | |||
| 995 | return 0; | ||
| 994 | } | 996 | } |
| 995 | 997 | ||
| 996 | static ssize_t le_auto_conn_write(struct file *file, const char __user *data, | 998 | DEFINE_SIMPLE_ATTRIBUTE(adv_min_interval_fops, adv_min_interval_get, |
| 997 | size_t count, loff_t *offset) | 999 | adv_min_interval_set, "%llu\n"); |
| 1000 | |||
| 1001 | static int adv_max_interval_set(void *data, u64 val) | ||
| 998 | { | 1002 | { |
| 999 | struct seq_file *sf = file->private_data; | 1003 | struct hci_dev *hdev = data; |
| 1000 | struct hci_dev *hdev = sf->private; | ||
| 1001 | u8 auto_connect = 0; | ||
| 1002 | bdaddr_t addr; | ||
| 1003 | u8 addr_type; | ||
| 1004 | char *buf; | ||
| 1005 | int err = 0; | ||
| 1006 | int n; | ||
| 1007 | 1004 | ||
| 1008 | /* Don't allow partial write */ | 1005 | if (val < 0x0020 || val > 0x4000 || val < hdev->le_adv_min_interval) |
| 1009 | if (*offset != 0) | ||
| 1010 | return -EINVAL; | 1006 | return -EINVAL; |
| 1011 | 1007 | ||
| 1012 | if (count < 3) | 1008 | hci_dev_lock(hdev); |
| 1013 | return -EINVAL; | 1009 | hdev->le_adv_max_interval = val; |
| 1010 | hci_dev_unlock(hdev); | ||
| 1014 | 1011 | ||
| 1015 | buf = memdup_user(data, count); | 1012 | return 0; |
| 1016 | if (IS_ERR(buf)) | 1013 | } |
| 1017 | return PTR_ERR(buf); | ||
| 1018 | 1014 | ||
| 1019 | if (memcmp(buf, "add", 3) == 0) { | 1015 | static int adv_max_interval_get(void *data, u64 *val) |
| 1020 | n = sscanf(&buf[4], "%hhx:%hhx:%hhx:%hhx:%hhx:%hhx %hhu %hhu", | 1016 | { |
| 1021 | &addr.b[5], &addr.b[4], &addr.b[3], &addr.b[2], | 1017 | struct hci_dev *hdev = data; |
| 1022 | &addr.b[1], &addr.b[0], &addr_type, | ||
| 1023 | &auto_connect); | ||
| 1024 | 1018 | ||
| 1025 | if (n < 7) { | 1019 | hci_dev_lock(hdev); |
| 1026 | err = -EINVAL; | 1020 | *val = hdev->le_adv_max_interval; |
| 1027 | goto done; | 1021 | hci_dev_unlock(hdev); |
| 1028 | } | ||
| 1029 | 1022 | ||
| 1030 | hci_dev_lock(hdev); | 1023 | return 0; |
| 1031 | err = hci_conn_params_add(hdev, &addr, addr_type, auto_connect, | 1024 | } |
| 1032 | hdev->le_conn_min_interval, | ||
| 1033 | hdev->le_conn_max_interval); | ||
| 1034 | hci_dev_unlock(hdev); | ||
| 1035 | 1025 | ||
| 1036 | if (err) | 1026 | DEFINE_SIMPLE_ATTRIBUTE(adv_max_interval_fops, adv_max_interval_get, |
| 1037 | goto done; | 1027 | adv_max_interval_set, "%llu\n"); |
| 1038 | } else if (memcmp(buf, "del", 3) == 0) { | ||
| 1039 | n = sscanf(&buf[4], "%hhx:%hhx:%hhx:%hhx:%hhx:%hhx %hhu", | ||
| 1040 | &addr.b[5], &addr.b[4], &addr.b[3], &addr.b[2], | ||
| 1041 | &addr.b[1], &addr.b[0], &addr_type); | ||
| 1042 | 1028 | ||
| 1043 | if (n < 7) { | 1029 | static int device_list_show(struct seq_file *f, void *ptr) |
| 1044 | err = -EINVAL; | 1030 | { |
| 1045 | goto done; | 1031 | struct hci_dev *hdev = f->private; |
| 1046 | } | 1032 | struct hci_conn_params *p; |
| 1047 | 1033 | ||
| 1048 | hci_dev_lock(hdev); | 1034 | hci_dev_lock(hdev); |
| 1049 | hci_conn_params_del(hdev, &addr, addr_type); | 1035 | list_for_each_entry(p, &hdev->le_conn_params, list) { |
| 1050 | hci_dev_unlock(hdev); | 1036 | seq_printf(f, "%pMR %u %u\n", &p->addr, p->addr_type, |
| 1051 | } else if (memcmp(buf, "clr", 3) == 0) { | 1037 | p->auto_connect); |
| 1052 | hci_dev_lock(hdev); | ||
| 1053 | hci_conn_params_clear(hdev); | ||
| 1054 | hci_pend_le_conns_clear(hdev); | ||
| 1055 | hci_update_background_scan(hdev); | ||
| 1056 | hci_dev_unlock(hdev); | ||
| 1057 | } else { | ||
| 1058 | err = -EINVAL; | ||
| 1059 | } | 1038 | } |
| 1039 | hci_dev_unlock(hdev); | ||
| 1060 | 1040 | ||
| 1061 | done: | 1041 | return 0; |
| 1062 | kfree(buf); | 1042 | } |
| 1063 | 1043 | ||
| 1064 | if (err) | 1044 | static int device_list_open(struct inode *inode, struct file *file) |
| 1065 | return err; | 1045 | { |
| 1066 | else | 1046 | return single_open(file, device_list_show, inode->i_private); |
| 1067 | return count; | ||
| 1068 | } | 1047 | } |
| 1069 | 1048 | ||
| 1070 | static const struct file_operations le_auto_conn_fops = { | 1049 | static const struct file_operations device_list_fops = { |
| 1071 | .open = le_auto_conn_open, | 1050 | .open = device_list_open, |
| 1072 | .read = seq_read, | 1051 | .read = seq_read, |
| 1073 | .write = le_auto_conn_write, | ||
| 1074 | .llseek = seq_lseek, | 1052 | .llseek = seq_lseek, |
| 1075 | .release = single_release, | 1053 | .release = single_release, |
| 1076 | }; | 1054 | }; |
| @@ -1426,9 +1404,6 @@ static void le_setup(struct hci_request *req) | |||
| 1426 | /* Read LE Supported States */ | 1404 | /* Read LE Supported States */ |
| 1427 | hci_req_add(req, HCI_OP_LE_READ_SUPPORTED_STATES, 0, NULL); | 1405 | hci_req_add(req, HCI_OP_LE_READ_SUPPORTED_STATES, 0, NULL); |
| 1428 | 1406 | ||
| 1429 | /* Read LE Advertising Channel TX Power */ | ||
| 1430 | hci_req_add(req, HCI_OP_LE_READ_ADV_TX_POWER, 0, NULL); | ||
| 1431 | |||
| 1432 | /* Read LE White List Size */ | 1407 | /* Read LE White List Size */ |
| 1433 | hci_req_add(req, HCI_OP_LE_READ_WHITE_LIST_SIZE, 0, NULL); | 1408 | hci_req_add(req, HCI_OP_LE_READ_WHITE_LIST_SIZE, 0, NULL); |
| 1434 | 1409 | ||
| @@ -1503,14 +1478,17 @@ static void hci_setup_event_mask(struct hci_request *req) | |||
| 1503 | /* Use a different default for LE-only devices */ | 1478 | /* Use a different default for LE-only devices */ |
| 1504 | memset(events, 0, sizeof(events)); | 1479 | memset(events, 0, sizeof(events)); |
| 1505 | events[0] |= 0x10; /* Disconnection Complete */ | 1480 | events[0] |= 0x10; /* Disconnection Complete */ |
| 1506 | events[0] |= 0x80; /* Encryption Change */ | ||
| 1507 | events[1] |= 0x08; /* Read Remote Version Information Complete */ | 1481 | events[1] |= 0x08; /* Read Remote Version Information Complete */ |
| 1508 | events[1] |= 0x20; /* Command Complete */ | 1482 | events[1] |= 0x20; /* Command Complete */ |
| 1509 | events[1] |= 0x40; /* Command Status */ | 1483 | events[1] |= 0x40; /* Command Status */ |
| 1510 | events[1] |= 0x80; /* Hardware Error */ | 1484 | events[1] |= 0x80; /* Hardware Error */ |
| 1511 | events[2] |= 0x04; /* Number of Completed Packets */ | 1485 | events[2] |= 0x04; /* Number of Completed Packets */ |
| 1512 | events[3] |= 0x02; /* Data Buffer Overflow */ | 1486 | events[3] |= 0x02; /* Data Buffer Overflow */ |
| 1513 | events[5] |= 0x80; /* Encryption Key Refresh Complete */ | 1487 | |
| 1488 | if (hdev->le_features[0] & HCI_LE_ENCRYPTION) { | ||
| 1489 | events[0] |= 0x80; /* Encryption Change */ | ||
| 1490 | events[5] |= 0x80; /* Encryption Key Refresh Complete */ | ||
| 1491 | } | ||
| 1514 | } | 1492 | } |
| 1515 | 1493 | ||
| 1516 | if (lmp_inq_rssi_capable(hdev)) | 1494 | if (lmp_inq_rssi_capable(hdev)) |
| @@ -1549,13 +1527,6 @@ static void hci_setup_event_mask(struct hci_request *req) | |||
| 1549 | events[7] |= 0x20; /* LE Meta-Event */ | 1527 | events[7] |= 0x20; /* LE Meta-Event */ |
| 1550 | 1528 | ||
| 1551 | hci_req_add(req, HCI_OP_SET_EVENT_MASK, sizeof(events), events); | 1529 | hci_req_add(req, HCI_OP_SET_EVENT_MASK, sizeof(events), events); |
| 1552 | |||
| 1553 | if (lmp_le_capable(hdev)) { | ||
| 1554 | memset(events, 0, sizeof(events)); | ||
| 1555 | events[0] = 0x1f; | ||
| 1556 | hci_req_add(req, HCI_OP_LE_SET_EVENT_MASK, | ||
| 1557 | sizeof(events), events); | ||
| 1558 | } | ||
| 1559 | } | 1530 | } |
| 1560 | 1531 | ||
| 1561 | static void hci_init2_req(struct hci_request *req, unsigned long opt) | 1532 | static void hci_init2_req(struct hci_request *req, unsigned long opt) |
| @@ -1570,8 +1541,6 @@ static void hci_init2_req(struct hci_request *req, unsigned long opt) | |||
| 1570 | if (lmp_le_capable(hdev)) | 1541 | if (lmp_le_capable(hdev)) |
| 1571 | le_setup(req); | 1542 | le_setup(req); |
| 1572 | 1543 | ||
| 1573 | hci_setup_event_mask(req); | ||
| 1574 | |||
| 1575 | /* AVM Berlin (31), aka "BlueFRITZ!", doesn't support the read | 1544 | /* AVM Berlin (31), aka "BlueFRITZ!", doesn't support the read |
| 1576 | * local supported commands HCI command. | 1545 | * local supported commands HCI command. |
| 1577 | */ | 1546 | */ |
| @@ -1654,7 +1623,7 @@ static void hci_set_le_support(struct hci_request *req) | |||
| 1654 | 1623 | ||
| 1655 | if (test_bit(HCI_LE_ENABLED, &hdev->dev_flags)) { | 1624 | if (test_bit(HCI_LE_ENABLED, &hdev->dev_flags)) { |
| 1656 | cp.le = 0x01; | 1625 | cp.le = 0x01; |
| 1657 | cp.simul = lmp_le_br_capable(hdev); | 1626 | cp.simul = 0x00; |
| 1658 | } | 1627 | } |
| 1659 | 1628 | ||
| 1660 | if (cp.le != lmp_host_le_capable(hdev)) | 1629 | if (cp.le != lmp_host_le_capable(hdev)) |
| @@ -1688,7 +1657,7 @@ static void hci_set_event_mask_page_2(struct hci_request *req) | |||
| 1688 | } | 1657 | } |
| 1689 | 1658 | ||
| 1690 | /* Enable Authenticated Payload Timeout Expired event if supported */ | 1659 | /* Enable Authenticated Payload Timeout Expired event if supported */ |
| 1691 | if (lmp_ping_capable(hdev)) | 1660 | if (lmp_ping_capable(hdev) || hdev->le_features[0] & HCI_LE_PING) |
| 1692 | events[2] |= 0x80; | 1661 | events[2] |= 0x80; |
| 1693 | 1662 | ||
| 1694 | hci_req_add(req, HCI_OP_SET_EVENT_MASK_PAGE_2, sizeof(events), events); | 1663 | hci_req_add(req, HCI_OP_SET_EVENT_MASK_PAGE_2, sizeof(events), events); |
| @@ -1699,6 +1668,8 @@ static void hci_init3_req(struct hci_request *req, unsigned long opt) | |||
| 1699 | struct hci_dev *hdev = req->hdev; | 1668 | struct hci_dev *hdev = req->hdev; |
| 1700 | u8 p; | 1669 | u8 p; |
| 1701 | 1670 | ||
| 1671 | hci_setup_event_mask(req); | ||
| 1672 | |||
| 1702 | /* Some Broadcom based Bluetooth controllers do not support the | 1673 | /* Some Broadcom based Bluetooth controllers do not support the |
| 1703 | * Delete Stored Link Key command. They are clearly indicating its | 1674 | * Delete Stored Link Key command. They are clearly indicating its |
| 1704 | * absence in the bit mask of supported commands. | 1675 | * absence in the bit mask of supported commands. |
| @@ -1725,8 +1696,33 @@ static void hci_init3_req(struct hci_request *req, unsigned long opt) | |||
| 1725 | if (hdev->commands[5] & 0x10) | 1696 | if (hdev->commands[5] & 0x10) |
| 1726 | hci_setup_link_policy(req); | 1697 | hci_setup_link_policy(req); |
| 1727 | 1698 | ||
| 1728 | if (lmp_le_capable(hdev)) | 1699 | if (lmp_le_capable(hdev)) { |
| 1700 | u8 events[8]; | ||
| 1701 | |||
| 1702 | memset(events, 0, sizeof(events)); | ||
| 1703 | events[0] = 0x0f; | ||
| 1704 | |||
| 1705 | if (hdev->le_features[0] & HCI_LE_ENCRYPTION) | ||
| 1706 | events[0] |= 0x10; /* LE Long Term Key Request */ | ||
| 1707 | |||
| 1708 | /* If controller supports the Connection Parameters Request | ||
| 1709 | * Link Layer Procedure, enable the corresponding event. | ||
| 1710 | */ | ||
| 1711 | if (hdev->le_features[0] & HCI_LE_CONN_PARAM_REQ_PROC) | ||
| 1712 | events[0] |= 0x20; /* LE Remote Connection | ||
| 1713 | * Parameter Request | ||
| 1714 | */ | ||
| 1715 | |||
| 1716 | hci_req_add(req, HCI_OP_LE_SET_EVENT_MASK, sizeof(events), | ||
| 1717 | events); | ||
| 1718 | |||
| 1719 | if (hdev->commands[25] & 0x40) { | ||
| 1720 | /* Read LE Advertising Channel TX Power */ | ||
| 1721 | hci_req_add(req, HCI_OP_LE_READ_ADV_TX_POWER, 0, NULL); | ||
| 1722 | } | ||
| 1723 | |||
| 1729 | hci_set_le_support(req); | 1724 | hci_set_le_support(req); |
| 1725 | } | ||
| 1730 | 1726 | ||
| 1731 | /* Read features beyond page 1 if available */ | 1727 | /* Read features beyond page 1 if available */ |
| 1732 | for (p = 2; p < HCI_MAX_PAGES && p <= hdev->max_page; p++) { | 1728 | for (p = 2; p < HCI_MAX_PAGES && p <= hdev->max_page; p++) { |
| @@ -1746,13 +1742,21 @@ static void hci_init4_req(struct hci_request *req, unsigned long opt) | |||
| 1746 | if (hdev->commands[22] & 0x04) | 1742 | if (hdev->commands[22] & 0x04) |
| 1747 | hci_set_event_mask_page_2(req); | 1743 | hci_set_event_mask_page_2(req); |
| 1748 | 1744 | ||
| 1745 | /* Read local codec list if the HCI command is supported */ | ||
| 1746 | if (hdev->commands[29] & 0x20) | ||
| 1747 | hci_req_add(req, HCI_OP_READ_LOCAL_CODECS, 0, NULL); | ||
| 1748 | |||
| 1749 | /* Get MWS transport configuration if the HCI command is supported */ | ||
| 1750 | if (hdev->commands[30] & 0x08) | ||
| 1751 | hci_req_add(req, HCI_OP_GET_MWS_TRANSPORT_CONFIG, 0, NULL); | ||
| 1752 | |||
| 1749 | /* Check for Synchronization Train support */ | 1753 | /* Check for Synchronization Train support */ |
| 1750 | if (lmp_sync_train_capable(hdev)) | 1754 | if (lmp_sync_train_capable(hdev)) |
| 1751 | hci_req_add(req, HCI_OP_READ_SYNC_TRAIN_PARAMS, 0, NULL); | 1755 | hci_req_add(req, HCI_OP_READ_SYNC_TRAIN_PARAMS, 0, NULL); |
| 1752 | 1756 | ||
| 1753 | /* Enable Secure Connections if supported and configured */ | 1757 | /* Enable Secure Connections if supported and configured */ |
| 1754 | if ((lmp_sc_capable(hdev) || | 1758 | if ((lmp_sc_capable(hdev) || |
| 1755 | test_bit(HCI_FORCE_SC, &hdev->dev_flags)) && | 1759 | test_bit(HCI_FORCE_SC, &hdev->dbg_flags)) && |
| 1756 | test_bit(HCI_SC_ENABLED, &hdev->dev_flags)) { | 1760 | test_bit(HCI_SC_ENABLED, &hdev->dev_flags)) { |
| 1757 | u8 support = 0x01; | 1761 | u8 support = 0x01; |
| 1758 | hci_req_add(req, HCI_OP_WRITE_SC_SUPPORT, | 1762 | hci_req_add(req, HCI_OP_WRITE_SC_SUPPORT, |
| @@ -1809,6 +1813,8 @@ static int __hci_init(struct hci_dev *hdev) | |||
| 1809 | debugfs_create_u16("hci_revision", 0444, hdev->debugfs, &hdev->hci_rev); | 1813 | debugfs_create_u16("hci_revision", 0444, hdev->debugfs, &hdev->hci_rev); |
| 1810 | debugfs_create_file("blacklist", 0444, hdev->debugfs, hdev, | 1814 | debugfs_create_file("blacklist", 0444, hdev->debugfs, hdev, |
| 1811 | &blacklist_fops); | 1815 | &blacklist_fops); |
| 1816 | debugfs_create_file("whitelist", 0444, hdev->debugfs, hdev, | ||
| 1817 | &whitelist_fops); | ||
| 1812 | debugfs_create_file("uuids", 0444, hdev->debugfs, hdev, &uuids_fops); | 1818 | debugfs_create_file("uuids", 0444, hdev->debugfs, hdev, &uuids_fops); |
| 1813 | 1819 | ||
| 1814 | debugfs_create_file("conn_info_min_age", 0644, hdev->debugfs, hdev, | 1820 | debugfs_create_file("conn_info_min_age", 0644, hdev->debugfs, hdev, |
| @@ -1830,8 +1836,6 @@ static int __hci_init(struct hci_dev *hdev) | |||
| 1830 | if (lmp_ssp_capable(hdev)) { | 1836 | if (lmp_ssp_capable(hdev)) { |
| 1831 | debugfs_create_file("auto_accept_delay", 0644, hdev->debugfs, | 1837 | debugfs_create_file("auto_accept_delay", 0644, hdev->debugfs, |
| 1832 | hdev, &auto_accept_delay_fops); | 1838 | hdev, &auto_accept_delay_fops); |
| 1833 | debugfs_create_file("ssp_debug_mode", 0644, hdev->debugfs, | ||
| 1834 | hdev, &ssp_debug_mode_fops); | ||
| 1835 | debugfs_create_file("force_sc_support", 0644, hdev->debugfs, | 1839 | debugfs_create_file("force_sc_support", 0644, hdev->debugfs, |
| 1836 | hdev, &force_sc_support_fops); | 1840 | hdev, &force_sc_support_fops); |
| 1837 | debugfs_create_file("sc_only_mode", 0444, hdev->debugfs, | 1841 | debugfs_create_file("sc_only_mode", 0444, hdev->debugfs, |
| @@ -1879,12 +1883,18 @@ static int __hci_init(struct hci_dev *hdev) | |||
| 1879 | hdev, &conn_min_interval_fops); | 1883 | hdev, &conn_min_interval_fops); |
| 1880 | debugfs_create_file("conn_max_interval", 0644, hdev->debugfs, | 1884 | debugfs_create_file("conn_max_interval", 0644, hdev->debugfs, |
| 1881 | hdev, &conn_max_interval_fops); | 1885 | hdev, &conn_max_interval_fops); |
| 1886 | debugfs_create_file("conn_latency", 0644, hdev->debugfs, | ||
| 1887 | hdev, &conn_latency_fops); | ||
| 1888 | debugfs_create_file("supervision_timeout", 0644, hdev->debugfs, | ||
| 1889 | hdev, &supervision_timeout_fops); | ||
| 1882 | debugfs_create_file("adv_channel_map", 0644, hdev->debugfs, | 1890 | debugfs_create_file("adv_channel_map", 0644, hdev->debugfs, |
| 1883 | hdev, &adv_channel_map_fops); | 1891 | hdev, &adv_channel_map_fops); |
| 1884 | debugfs_create_file("6lowpan", 0644, hdev->debugfs, hdev, | 1892 | debugfs_create_file("adv_min_interval", 0644, hdev->debugfs, |
| 1885 | &lowpan_debugfs_fops); | 1893 | hdev, &adv_min_interval_fops); |
| 1886 | debugfs_create_file("le_auto_conn", 0644, hdev->debugfs, hdev, | 1894 | debugfs_create_file("adv_max_interval", 0644, hdev->debugfs, |
| 1887 | &le_auto_conn_fops); | 1895 | hdev, &adv_max_interval_fops); |
| 1896 | debugfs_create_file("device_list", 0444, hdev->debugfs, hdev, | ||
| 1897 | &device_list_fops); | ||
| 1888 | debugfs_create_u16("discov_interleaved_timeout", 0644, | 1898 | debugfs_create_u16("discov_interleaved_timeout", 0644, |
| 1889 | hdev->debugfs, | 1899 | hdev->debugfs, |
| 1890 | &hdev->discov_interleaved_timeout); | 1900 | &hdev->discov_interleaved_timeout); |
| @@ -1893,6 +1903,38 @@ static int __hci_init(struct hci_dev *hdev) | |||
| 1893 | return 0; | 1903 | return 0; |
| 1894 | } | 1904 | } |
| 1895 | 1905 | ||
| 1906 | static void hci_init0_req(struct hci_request *req, unsigned long opt) | ||
| 1907 | { | ||
| 1908 | struct hci_dev *hdev = req->hdev; | ||
| 1909 | |||
| 1910 | BT_DBG("%s %ld", hdev->name, opt); | ||
| 1911 | |||
| 1912 | /* Reset */ | ||
| 1913 | if (!test_bit(HCI_QUIRK_RESET_ON_CLOSE, &hdev->quirks)) | ||
| 1914 | hci_reset_req(req, 0); | ||
| 1915 | |||
| 1916 | /* Read Local Version */ | ||
| 1917 | hci_req_add(req, HCI_OP_READ_LOCAL_VERSION, 0, NULL); | ||
| 1918 | |||
| 1919 | /* Read BD Address */ | ||
| 1920 | if (hdev->set_bdaddr) | ||
| 1921 | hci_req_add(req, HCI_OP_READ_BD_ADDR, 0, NULL); | ||
| 1922 | } | ||
| 1923 | |||
| 1924 | static int __hci_unconf_init(struct hci_dev *hdev) | ||
| 1925 | { | ||
| 1926 | int err; | ||
| 1927 | |||
| 1928 | if (test_bit(HCI_QUIRK_RAW_DEVICE, &hdev->quirks)) | ||
| 1929 | return 0; | ||
| 1930 | |||
| 1931 | err = __hci_req_sync(hdev, hci_init0_req, 0, HCI_INIT_TIMEOUT); | ||
| 1932 | if (err < 0) | ||
| 1933 | return err; | ||
| 1934 | |||
| 1935 | return 0; | ||
| 1936 | } | ||
| 1937 | |||
| 1896 | static void hci_scan_req(struct hci_request *req, unsigned long opt) | 1938 | static void hci_scan_req(struct hci_request *req, unsigned long opt) |
| 1897 | { | 1939 | { |
| 1898 | __u8 scan = opt; | 1940 | __u8 scan = opt; |
| @@ -1973,16 +2015,20 @@ bool hci_discovery_active(struct hci_dev *hdev) | |||
| 1973 | 2015 | ||
| 1974 | void hci_discovery_set_state(struct hci_dev *hdev, int state) | 2016 | void hci_discovery_set_state(struct hci_dev *hdev, int state) |
| 1975 | { | 2017 | { |
| 2018 | int old_state = hdev->discovery.state; | ||
| 2019 | |||
| 1976 | BT_DBG("%s state %u -> %u", hdev->name, hdev->discovery.state, state); | 2020 | BT_DBG("%s state %u -> %u", hdev->name, hdev->discovery.state, state); |
| 1977 | 2021 | ||
| 1978 | if (hdev->discovery.state == state) | 2022 | if (old_state == state) |
| 1979 | return; | 2023 | return; |
| 1980 | 2024 | ||
| 2025 | hdev->discovery.state = state; | ||
| 2026 | |||
| 1981 | switch (state) { | 2027 | switch (state) { |
| 1982 | case DISCOVERY_STOPPED: | 2028 | case DISCOVERY_STOPPED: |
| 1983 | hci_update_background_scan(hdev); | 2029 | hci_update_background_scan(hdev); |
| 1984 | 2030 | ||
| 1985 | if (hdev->discovery.state != DISCOVERY_STARTING) | 2031 | if (old_state != DISCOVERY_STARTING) |
| 1986 | mgmt_discovering(hdev, 0); | 2032 | mgmt_discovering(hdev, 0); |
| 1987 | break; | 2033 | break; |
| 1988 | case DISCOVERY_STARTING: | 2034 | case DISCOVERY_STARTING: |
| @@ -1995,8 +2041,6 @@ void hci_discovery_set_state(struct hci_dev *hdev, int state) | |||
| 1995 | case DISCOVERY_STOPPING: | 2041 | case DISCOVERY_STOPPING: |
| 1996 | break; | 2042 | break; |
| 1997 | } | 2043 | } |
| 1998 | |||
| 1999 | hdev->discovery.state = state; | ||
| 2000 | } | 2044 | } |
| 2001 | 2045 | ||
| 2002 | void hci_inquiry_cache_flush(struct hci_dev *hdev) | 2046 | void hci_inquiry_cache_flush(struct hci_dev *hdev) |
| @@ -2083,22 +2127,24 @@ void hci_inquiry_cache_update_resolve(struct hci_dev *hdev, | |||
| 2083 | list_add(&ie->list, pos); | 2127 | list_add(&ie->list, pos); |
| 2084 | } | 2128 | } |
| 2085 | 2129 | ||
| 2086 | bool hci_inquiry_cache_update(struct hci_dev *hdev, struct inquiry_data *data, | 2130 | u32 hci_inquiry_cache_update(struct hci_dev *hdev, struct inquiry_data *data, |
| 2087 | bool name_known, bool *ssp) | 2131 | bool name_known) |
| 2088 | { | 2132 | { |
| 2089 | struct discovery_state *cache = &hdev->discovery; | 2133 | struct discovery_state *cache = &hdev->discovery; |
| 2090 | struct inquiry_entry *ie; | 2134 | struct inquiry_entry *ie; |
| 2135 | u32 flags = 0; | ||
| 2091 | 2136 | ||
| 2092 | BT_DBG("cache %p, %pMR", cache, &data->bdaddr); | 2137 | BT_DBG("cache %p, %pMR", cache, &data->bdaddr); |
| 2093 | 2138 | ||
| 2094 | hci_remove_remote_oob_data(hdev, &data->bdaddr); | 2139 | hci_remove_remote_oob_data(hdev, &data->bdaddr); |
| 2095 | 2140 | ||
| 2096 | *ssp = data->ssp_mode; | 2141 | if (!data->ssp_mode) |
| 2142 | flags |= MGMT_DEV_FOUND_LEGACY_PAIRING; | ||
| 2097 | 2143 | ||
| 2098 | ie = hci_inquiry_cache_lookup(hdev, &data->bdaddr); | 2144 | ie = hci_inquiry_cache_lookup(hdev, &data->bdaddr); |
| 2099 | if (ie) { | 2145 | if (ie) { |
| 2100 | if (ie->data.ssp_mode) | 2146 | if (!ie->data.ssp_mode) |
| 2101 | *ssp = true; | 2147 | flags |= MGMT_DEV_FOUND_LEGACY_PAIRING; |
| 2102 | 2148 | ||
| 2103 | if (ie->name_state == NAME_NEEDED && | 2149 | if (ie->name_state == NAME_NEEDED && |
| 2104 | data->rssi != ie->data.rssi) { | 2150 | data->rssi != ie->data.rssi) { |
| @@ -2110,9 +2156,11 @@ bool hci_inquiry_cache_update(struct hci_dev *hdev, struct inquiry_data *data, | |||
| 2110 | } | 2156 | } |
| 2111 | 2157 | ||
| 2112 | /* Entry not in the cache. Add new one. */ | 2158 | /* Entry not in the cache. Add new one. */ |
| 2113 | ie = kzalloc(sizeof(struct inquiry_entry), GFP_ATOMIC); | 2159 | ie = kzalloc(sizeof(*ie), GFP_KERNEL); |
| 2114 | if (!ie) | 2160 | if (!ie) { |
| 2115 | return false; | 2161 | flags |= MGMT_DEV_FOUND_CONFIRM_NAME; |
| 2162 | goto done; | ||
| 2163 | } | ||
| 2116 | 2164 | ||
| 2117 | list_add(&ie->all, &cache->all); | 2165 | list_add(&ie->all, &cache->all); |
| 2118 | 2166 | ||
| @@ -2135,9 +2183,10 @@ update: | |||
| 2135 | cache->timestamp = jiffies; | 2183 | cache->timestamp = jiffies; |
| 2136 | 2184 | ||
| 2137 | if (ie->name_state == NAME_NOT_KNOWN) | 2185 | if (ie->name_state == NAME_NOT_KNOWN) |
| 2138 | return false; | 2186 | flags |= MGMT_DEV_FOUND_CONFIRM_NAME; |
| 2139 | 2187 | ||
| 2140 | return true; | 2188 | done: |
| 2189 | return flags; | ||
| 2141 | } | 2190 | } |
| 2142 | 2191 | ||
| 2143 | static int inquiry_cache_dump(struct hci_dev *hdev, int num, __u8 *buf) | 2192 | static int inquiry_cache_dump(struct hci_dev *hdev, int num, __u8 *buf) |
| @@ -2186,12 +2235,6 @@ static void hci_inq_req(struct hci_request *req, unsigned long opt) | |||
| 2186 | hci_req_add(req, HCI_OP_INQUIRY, sizeof(cp), &cp); | 2235 | hci_req_add(req, HCI_OP_INQUIRY, sizeof(cp), &cp); |
| 2187 | } | 2236 | } |
| 2188 | 2237 | ||
| 2189 | static int wait_inquiry(void *word) | ||
| 2190 | { | ||
| 2191 | schedule(); | ||
| 2192 | return signal_pending(current); | ||
| 2193 | } | ||
| 2194 | |||
| 2195 | int hci_inquiry(void __user *arg) | 2238 | int hci_inquiry(void __user *arg) |
| 2196 | { | 2239 | { |
| 2197 | __u8 __user *ptr = arg; | 2240 | __u8 __user *ptr = arg; |
| @@ -2213,6 +2256,11 @@ int hci_inquiry(void __user *arg) | |||
| 2213 | goto done; | 2256 | goto done; |
| 2214 | } | 2257 | } |
| 2215 | 2258 | ||
| 2259 | if (test_bit(HCI_UNCONFIGURED, &hdev->dev_flags)) { | ||
| 2260 | err = -EOPNOTSUPP; | ||
| 2261 | goto done; | ||
| 2262 | } | ||
| 2263 | |||
| 2216 | if (hdev->dev_type != HCI_BREDR) { | 2264 | if (hdev->dev_type != HCI_BREDR) { |
| 2217 | err = -EOPNOTSUPP; | 2265 | err = -EOPNOTSUPP; |
| 2218 | goto done; | 2266 | goto done; |
| @@ -2242,7 +2290,7 @@ int hci_inquiry(void __user *arg) | |||
| 2242 | /* Wait until Inquiry procedure finishes (HCI_INQUIRY flag is | 2290 | /* Wait until Inquiry procedure finishes (HCI_INQUIRY flag is |
| 2243 | * cleared). If it is interrupted by a signal, return -EINTR. | 2291 | * cleared). If it is interrupted by a signal, return -EINTR. |
| 2244 | */ | 2292 | */ |
| 2245 | if (wait_on_bit(&hdev->flags, HCI_INQUIRY, wait_inquiry, | 2293 | if (wait_on_bit(&hdev->flags, HCI_INQUIRY, |
| 2246 | TASK_INTERRUPTIBLE)) | 2294 | TASK_INTERRUPTIBLE)) |
| 2247 | return -EINTR; | 2295 | return -EINTR; |
| 2248 | } | 2296 | } |
| @@ -2295,7 +2343,8 @@ static int hci_dev_do_open(struct hci_dev *hdev) | |||
| 2295 | goto done; | 2343 | goto done; |
| 2296 | } | 2344 | } |
| 2297 | 2345 | ||
| 2298 | if (!test_bit(HCI_SETUP, &hdev->dev_flags)) { | 2346 | if (!test_bit(HCI_SETUP, &hdev->dev_flags) && |
| 2347 | !test_bit(HCI_CONFIG, &hdev->dev_flags)) { | ||
| 2299 | /* Check for rfkill but allow the HCI setup stage to | 2348 | /* Check for rfkill but allow the HCI setup stage to |
| 2300 | * proceed (which in itself doesn't cause any RF activity). | 2349 | * proceed (which in itself doesn't cause any RF activity). |
| 2301 | */ | 2350 | */ |
| @@ -2338,14 +2387,47 @@ static int hci_dev_do_open(struct hci_dev *hdev) | |||
| 2338 | atomic_set(&hdev->cmd_cnt, 1); | 2387 | atomic_set(&hdev->cmd_cnt, 1); |
| 2339 | set_bit(HCI_INIT, &hdev->flags); | 2388 | set_bit(HCI_INIT, &hdev->flags); |
| 2340 | 2389 | ||
| 2341 | if (hdev->setup && test_bit(HCI_SETUP, &hdev->dev_flags)) | 2390 | if (test_bit(HCI_SETUP, &hdev->dev_flags)) { |
| 2342 | ret = hdev->setup(hdev); | 2391 | if (hdev->setup) |
| 2392 | ret = hdev->setup(hdev); | ||
| 2343 | 2393 | ||
| 2344 | if (!ret) { | 2394 | /* The transport driver can set these quirks before |
| 2345 | if (test_bit(HCI_QUIRK_RAW_DEVICE, &hdev->quirks)) | 2395 | * creating the HCI device or in its setup callback. |
| 2346 | set_bit(HCI_RAW, &hdev->flags); | 2396 | * |
| 2397 | * In case any of them is set, the controller has to | ||
| 2398 | * start up as unconfigured. | ||
| 2399 | */ | ||
| 2400 | if (test_bit(HCI_QUIRK_EXTERNAL_CONFIG, &hdev->quirks) || | ||
| 2401 | test_bit(HCI_QUIRK_INVALID_BDADDR, &hdev->quirks)) | ||
| 2402 | set_bit(HCI_UNCONFIGURED, &hdev->dev_flags); | ||
| 2347 | 2403 | ||
| 2348 | if (!test_bit(HCI_RAW, &hdev->flags) && | 2404 | /* For an unconfigured controller it is required to |
| 2405 | * read at least the version information provided by | ||
| 2406 | * the Read Local Version Information command. | ||
| 2407 | * | ||
| 2408 | * If the set_bdaddr driver callback is provided, then | ||
| 2409 | * also the original Bluetooth public device address | ||
| 2410 | * will be read using the Read BD Address command. | ||
| 2411 | */ | ||
| 2412 | if (test_bit(HCI_UNCONFIGURED, &hdev->dev_flags)) | ||
| 2413 | ret = __hci_unconf_init(hdev); | ||
| 2414 | } | ||
| 2415 | |||
| 2416 | if (test_bit(HCI_CONFIG, &hdev->dev_flags)) { | ||
| 2417 | /* If public address change is configured, ensure that | ||
| 2418 | * the address gets programmed. If the driver does not | ||
| 2419 | * support changing the public address, fail the power | ||
| 2420 | * on procedure. | ||
| 2421 | */ | ||
| 2422 | if (bacmp(&hdev->public_addr, BDADDR_ANY) && | ||
| 2423 | hdev->set_bdaddr) | ||
| 2424 | ret = hdev->set_bdaddr(hdev, &hdev->public_addr); | ||
| 2425 | else | ||
| 2426 | ret = -EADDRNOTAVAIL; | ||
| 2427 | } | ||
| 2428 | |||
| 2429 | if (!ret) { | ||
| 2430 | if (!test_bit(HCI_UNCONFIGURED, &hdev->dev_flags) && | ||
| 2349 | !test_bit(HCI_USER_CHANNEL, &hdev->dev_flags)) | 2431 | !test_bit(HCI_USER_CHANNEL, &hdev->dev_flags)) |
| 2350 | ret = __hci_init(hdev); | 2432 | ret = __hci_init(hdev); |
| 2351 | } | 2433 | } |
| @@ -2358,6 +2440,8 @@ static int hci_dev_do_open(struct hci_dev *hdev) | |||
| 2358 | set_bit(HCI_UP, &hdev->flags); | 2440 | set_bit(HCI_UP, &hdev->flags); |
| 2359 | hci_notify(hdev, HCI_DEV_UP); | 2441 | hci_notify(hdev, HCI_DEV_UP); |
| 2360 | if (!test_bit(HCI_SETUP, &hdev->dev_flags) && | 2442 | if (!test_bit(HCI_SETUP, &hdev->dev_flags) && |
| 2443 | !test_bit(HCI_CONFIG, &hdev->dev_flags) && | ||
| 2444 | !test_bit(HCI_UNCONFIGURED, &hdev->dev_flags) && | ||
| 2361 | !test_bit(HCI_USER_CHANNEL, &hdev->dev_flags) && | 2445 | !test_bit(HCI_USER_CHANNEL, &hdev->dev_flags) && |
| 2362 | hdev->dev_type == HCI_BREDR) { | 2446 | hdev->dev_type == HCI_BREDR) { |
| 2363 | hci_dev_lock(hdev); | 2447 | hci_dev_lock(hdev); |
| @@ -2382,7 +2466,7 @@ static int hci_dev_do_open(struct hci_dev *hdev) | |||
| 2382 | } | 2466 | } |
| 2383 | 2467 | ||
| 2384 | hdev->close(hdev); | 2468 | hdev->close(hdev); |
| 2385 | hdev->flags = 0; | 2469 | hdev->flags &= BIT(HCI_RAW); |
| 2386 | } | 2470 | } |
| 2387 | 2471 | ||
| 2388 | done: | 2472 | done: |
| @@ -2401,6 +2485,21 @@ int hci_dev_open(__u16 dev) | |||
| 2401 | if (!hdev) | 2485 | if (!hdev) |
| 2402 | return -ENODEV; | 2486 | return -ENODEV; |
| 2403 | 2487 | ||
| 2488 | /* Devices that are marked as unconfigured can only be powered | ||
| 2489 | * up as user channel. Trying to bring them up as normal devices | ||
| 2490 | * will result into a failure. Only user channel operation is | ||
| 2491 | * possible. | ||
| 2492 | * | ||
| 2493 | * When this function is called for a user channel, the flag | ||
| 2494 | * HCI_USER_CHANNEL will be set first before attempting to | ||
| 2495 | * open the device. | ||
| 2496 | */ | ||
| 2497 | if (test_bit(HCI_UNCONFIGURED, &hdev->dev_flags) && | ||
| 2498 | !test_bit(HCI_USER_CHANNEL, &hdev->dev_flags)) { | ||
| 2499 | err = -EOPNOTSUPP; | ||
| 2500 | goto done; | ||
| 2501 | } | ||
| 2502 | |||
| 2404 | /* We need to ensure that no other power on/off work is pending | 2503 | /* We need to ensure that no other power on/off work is pending |
| 2405 | * before proceeding to call hci_dev_do_open. This is | 2504 | * before proceeding to call hci_dev_do_open. This is |
| 2406 | * particularly important if the setup procedure has not yet | 2505 | * particularly important if the setup procedure has not yet |
| @@ -2415,13 +2514,34 @@ int hci_dev_open(__u16 dev) | |||
| 2415 | */ | 2514 | */ |
| 2416 | flush_workqueue(hdev->req_workqueue); | 2515 | flush_workqueue(hdev->req_workqueue); |
| 2417 | 2516 | ||
| 2517 | /* For controllers not using the management interface and that | ||
| 2518 | * are brought up using legacy ioctl, set the HCI_BONDABLE bit | ||
| 2519 | * so that pairing works for them. Once the management interface | ||
| 2520 | * is in use this bit will be cleared again and userspace has | ||
| 2521 | * to explicitly enable it. | ||
| 2522 | */ | ||
| 2523 | if (!test_bit(HCI_USER_CHANNEL, &hdev->dev_flags) && | ||
| 2524 | !test_bit(HCI_MGMT, &hdev->dev_flags)) | ||
| 2525 | set_bit(HCI_BONDABLE, &hdev->dev_flags); | ||
| 2526 | |||
| 2418 | err = hci_dev_do_open(hdev); | 2527 | err = hci_dev_do_open(hdev); |
| 2419 | 2528 | ||
| 2529 | done: | ||
| 2420 | hci_dev_put(hdev); | 2530 | hci_dev_put(hdev); |
| 2421 | |||
| 2422 | return err; | 2531 | return err; |
| 2423 | } | 2532 | } |
| 2424 | 2533 | ||
| 2534 | /* This function requires the caller holds hdev->lock */ | ||
| 2535 | static void hci_pend_le_actions_clear(struct hci_dev *hdev) | ||
| 2536 | { | ||
| 2537 | struct hci_conn_params *p; | ||
| 2538 | |||
| 2539 | list_for_each_entry(p, &hdev->le_conn_params, list) | ||
| 2540 | list_del_init(&p->action); | ||
| 2541 | |||
| 2542 | BT_DBG("All LE pending actions cleared"); | ||
| 2543 | } | ||
| 2544 | |||
| 2425 | static int hci_dev_do_close(struct hci_dev *hdev) | 2545 | static int hci_dev_do_close(struct hci_dev *hdev) |
| 2426 | { | 2546 | { |
| 2427 | BT_DBG("%s %p", hdev->name, hdev); | 2547 | BT_DBG("%s %p", hdev->name, hdev); |
| @@ -2432,7 +2552,7 @@ static int hci_dev_do_close(struct hci_dev *hdev) | |||
| 2432 | hci_req_lock(hdev); | 2552 | hci_req_lock(hdev); |
| 2433 | 2553 | ||
| 2434 | if (!test_and_clear_bit(HCI_UP, &hdev->flags)) { | 2554 | if (!test_and_clear_bit(HCI_UP, &hdev->flags)) { |
| 2435 | del_timer_sync(&hdev->cmd_timer); | 2555 | cancel_delayed_work_sync(&hdev->cmd_timer); |
| 2436 | hci_req_unlock(hdev); | 2556 | hci_req_unlock(hdev); |
| 2437 | return 0; | 2557 | return 0; |
| 2438 | } | 2558 | } |
| @@ -2459,7 +2579,7 @@ static int hci_dev_do_close(struct hci_dev *hdev) | |||
| 2459 | hci_dev_lock(hdev); | 2579 | hci_dev_lock(hdev); |
| 2460 | hci_inquiry_cache_flush(hdev); | 2580 | hci_inquiry_cache_flush(hdev); |
| 2461 | hci_conn_hash_flush(hdev); | 2581 | hci_conn_hash_flush(hdev); |
| 2462 | hci_pend_le_conns_clear(hdev); | 2582 | hci_pend_le_actions_clear(hdev); |
| 2463 | hci_dev_unlock(hdev); | 2583 | hci_dev_unlock(hdev); |
| 2464 | 2584 | ||
| 2465 | hci_notify(hdev, HCI_DEV_DOWN); | 2585 | hci_notify(hdev, HCI_DEV_DOWN); |
| @@ -2470,8 +2590,8 @@ static int hci_dev_do_close(struct hci_dev *hdev) | |||
| 2470 | /* Reset device */ | 2590 | /* Reset device */ |
| 2471 | skb_queue_purge(&hdev->cmd_q); | 2591 | skb_queue_purge(&hdev->cmd_q); |
| 2472 | atomic_set(&hdev->cmd_cnt, 1); | 2592 | atomic_set(&hdev->cmd_cnt, 1); |
| 2473 | if (!test_bit(HCI_RAW, &hdev->flags) && | 2593 | if (!test_bit(HCI_AUTO_OFF, &hdev->dev_flags) && |
| 2474 | !test_bit(HCI_AUTO_OFF, &hdev->dev_flags) && | 2594 | !test_bit(HCI_UNCONFIGURED, &hdev->dev_flags) && |
| 2475 | test_bit(HCI_QUIRK_RESET_ON_CLOSE, &hdev->quirks)) { | 2595 | test_bit(HCI_QUIRK_RESET_ON_CLOSE, &hdev->quirks)) { |
| 2476 | set_bit(HCI_INIT, &hdev->flags); | 2596 | set_bit(HCI_INIT, &hdev->flags); |
| 2477 | __hci_req_sync(hdev, hci_reset_req, 0, HCI_CMD_TIMEOUT); | 2597 | __hci_req_sync(hdev, hci_reset_req, 0, HCI_CMD_TIMEOUT); |
| @@ -2488,7 +2608,7 @@ static int hci_dev_do_close(struct hci_dev *hdev) | |||
| 2488 | 2608 | ||
| 2489 | /* Drop last sent command */ | 2609 | /* Drop last sent command */ |
| 2490 | if (hdev->sent_cmd) { | 2610 | if (hdev->sent_cmd) { |
| 2491 | del_timer_sync(&hdev->cmd_timer); | 2611 | cancel_delayed_work_sync(&hdev->cmd_timer); |
| 2492 | kfree_skb(hdev->sent_cmd); | 2612 | kfree_skb(hdev->sent_cmd); |
| 2493 | hdev->sent_cmd = NULL; | 2613 | hdev->sent_cmd = NULL; |
| 2494 | } | 2614 | } |
| @@ -2501,7 +2621,7 @@ static int hci_dev_do_close(struct hci_dev *hdev) | |||
| 2501 | hdev->close(hdev); | 2621 | hdev->close(hdev); |
| 2502 | 2622 | ||
| 2503 | /* Clear flags */ | 2623 | /* Clear flags */ |
| 2504 | hdev->flags = 0; | 2624 | hdev->flags &= BIT(HCI_RAW); |
| 2505 | hdev->dev_flags &= ~HCI_PERSISTENT_MASK; | 2625 | hdev->dev_flags &= ~HCI_PERSISTENT_MASK; |
| 2506 | 2626 | ||
| 2507 | if (!test_and_clear_bit(HCI_AUTO_OFF, &hdev->dev_flags)) { | 2627 | if (!test_and_clear_bit(HCI_AUTO_OFF, &hdev->dev_flags)) { |
| @@ -2570,6 +2690,11 @@ int hci_dev_reset(__u16 dev) | |||
| 2570 | goto done; | 2690 | goto done; |
| 2571 | } | 2691 | } |
| 2572 | 2692 | ||
| 2693 | if (test_bit(HCI_UNCONFIGURED, &hdev->dev_flags)) { | ||
| 2694 | ret = -EOPNOTSUPP; | ||
| 2695 | goto done; | ||
| 2696 | } | ||
| 2697 | |||
| 2573 | /* Drop queues */ | 2698 | /* Drop queues */ |
| 2574 | skb_queue_purge(&hdev->rx_q); | 2699 | skb_queue_purge(&hdev->rx_q); |
| 2575 | skb_queue_purge(&hdev->cmd_q); | 2700 | skb_queue_purge(&hdev->cmd_q); |
| @@ -2585,8 +2710,7 @@ int hci_dev_reset(__u16 dev) | |||
| 2585 | atomic_set(&hdev->cmd_cnt, 1); | 2710 | atomic_set(&hdev->cmd_cnt, 1); |
| 2586 | hdev->acl_cnt = 0; hdev->sco_cnt = 0; hdev->le_cnt = 0; | 2711 | hdev->acl_cnt = 0; hdev->sco_cnt = 0; hdev->le_cnt = 0; |
| 2587 | 2712 | ||
| 2588 | if (!test_bit(HCI_RAW, &hdev->flags)) | 2713 | ret = __hci_req_sync(hdev, hci_reset_req, 0, HCI_INIT_TIMEOUT); |
| 2589 | ret = __hci_req_sync(hdev, hci_reset_req, 0, HCI_INIT_TIMEOUT); | ||
| 2590 | 2714 | ||
| 2591 | done: | 2715 | done: |
| 2592 | hci_req_unlock(hdev); | 2716 | hci_req_unlock(hdev); |
| @@ -2608,6 +2732,11 @@ int hci_dev_reset_stat(__u16 dev) | |||
| 2608 | goto done; | 2732 | goto done; |
| 2609 | } | 2733 | } |
| 2610 | 2734 | ||
| 2735 | if (test_bit(HCI_UNCONFIGURED, &hdev->dev_flags)) { | ||
| 2736 | ret = -EOPNOTSUPP; | ||
| 2737 | goto done; | ||
| 2738 | } | ||
| 2739 | |||
| 2611 | memset(&hdev->stat, 0, sizeof(struct hci_dev_stats)); | 2740 | memset(&hdev->stat, 0, sizeof(struct hci_dev_stats)); |
| 2612 | 2741 | ||
| 2613 | done: | 2742 | done: |
| @@ -2615,6 +2744,42 @@ done: | |||
| 2615 | return ret; | 2744 | return ret; |
| 2616 | } | 2745 | } |
| 2617 | 2746 | ||
| 2747 | static void hci_update_scan_state(struct hci_dev *hdev, u8 scan) | ||
| 2748 | { | ||
| 2749 | bool conn_changed, discov_changed; | ||
| 2750 | |||
| 2751 | BT_DBG("%s scan 0x%02x", hdev->name, scan); | ||
| 2752 | |||
| 2753 | if ((scan & SCAN_PAGE)) | ||
| 2754 | conn_changed = !test_and_set_bit(HCI_CONNECTABLE, | ||
| 2755 | &hdev->dev_flags); | ||
| 2756 | else | ||
| 2757 | conn_changed = test_and_clear_bit(HCI_CONNECTABLE, | ||
| 2758 | &hdev->dev_flags); | ||
| 2759 | |||
| 2760 | if ((scan & SCAN_INQUIRY)) { | ||
| 2761 | discov_changed = !test_and_set_bit(HCI_DISCOVERABLE, | ||
| 2762 | &hdev->dev_flags); | ||
| 2763 | } else { | ||
| 2764 | clear_bit(HCI_LIMITED_DISCOVERABLE, &hdev->dev_flags); | ||
| 2765 | discov_changed = test_and_clear_bit(HCI_DISCOVERABLE, | ||
| 2766 | &hdev->dev_flags); | ||
| 2767 | } | ||
| 2768 | |||
| 2769 | if (!test_bit(HCI_MGMT, &hdev->dev_flags)) | ||
| 2770 | return; | ||
| 2771 | |||
| 2772 | if (conn_changed || discov_changed) { | ||
| 2773 | /* In case this was disabled through mgmt */ | ||
| 2774 | set_bit(HCI_BREDR_ENABLED, &hdev->dev_flags); | ||
| 2775 | |||
| 2776 | if (test_bit(HCI_LE_ENABLED, &hdev->dev_flags)) | ||
| 2777 | mgmt_update_adv_data(hdev); | ||
| 2778 | |||
| 2779 | mgmt_new_settings(hdev); | ||
| 2780 | } | ||
| 2781 | } | ||
| 2782 | |||
| 2618 | int hci_dev_cmd(unsigned int cmd, void __user *arg) | 2783 | int hci_dev_cmd(unsigned int cmd, void __user *arg) |
| 2619 | { | 2784 | { |
| 2620 | struct hci_dev *hdev; | 2785 | struct hci_dev *hdev; |
| @@ -2633,6 +2798,11 @@ int hci_dev_cmd(unsigned int cmd, void __user *arg) | |||
| 2633 | goto done; | 2798 | goto done; |
| 2634 | } | 2799 | } |
| 2635 | 2800 | ||
| 2801 | if (test_bit(HCI_UNCONFIGURED, &hdev->dev_flags)) { | ||
| 2802 | err = -EOPNOTSUPP; | ||
| 2803 | goto done; | ||
| 2804 | } | ||
| 2805 | |||
| 2636 | if (hdev->dev_type != HCI_BREDR) { | 2806 | if (hdev->dev_type != HCI_BREDR) { |
| 2637 | err = -EOPNOTSUPP; | 2807 | err = -EOPNOTSUPP; |
| 2638 | goto done; | 2808 | goto done; |
| @@ -2670,6 +2840,12 @@ int hci_dev_cmd(unsigned int cmd, void __user *arg) | |||
| 2670 | case HCISETSCAN: | 2840 | case HCISETSCAN: |
| 2671 | err = hci_req_sync(hdev, hci_scan_req, dr.dev_opt, | 2841 | err = hci_req_sync(hdev, hci_scan_req, dr.dev_opt, |
| 2672 | HCI_INIT_TIMEOUT); | 2842 | HCI_INIT_TIMEOUT); |
| 2843 | |||
| 2844 | /* Ensure that the connectable and discoverable states | ||
| 2845 | * get correctly modified as this was a non-mgmt change. | ||
| 2846 | */ | ||
| 2847 | if (!err) | ||
| 2848 | hci_update_scan_state(hdev, dr.dev_opt); | ||
| 2673 | break; | 2849 | break; |
| 2674 | 2850 | ||
| 2675 | case HCISETLINKPOL: | 2851 | case HCISETLINKPOL: |
| @@ -2730,14 +2906,17 @@ int hci_get_dev_list(void __user *arg) | |||
| 2730 | 2906 | ||
| 2731 | read_lock(&hci_dev_list_lock); | 2907 | read_lock(&hci_dev_list_lock); |
| 2732 | list_for_each_entry(hdev, &hci_dev_list, list) { | 2908 | list_for_each_entry(hdev, &hci_dev_list, list) { |
| 2733 | if (test_and_clear_bit(HCI_AUTO_OFF, &hdev->dev_flags)) | 2909 | unsigned long flags = hdev->flags; |
| 2734 | cancel_delayed_work(&hdev->power_off); | ||
| 2735 | 2910 | ||
| 2736 | if (!test_bit(HCI_MGMT, &hdev->dev_flags)) | 2911 | /* When the auto-off is configured it means the transport |
| 2737 | set_bit(HCI_PAIRABLE, &hdev->dev_flags); | 2912 | * is running, but in that case still indicate that the |
| 2913 | * device is actually down. | ||
| 2914 | */ | ||
| 2915 | if (test_bit(HCI_AUTO_OFF, &hdev->dev_flags)) | ||
| 2916 | flags &= ~BIT(HCI_UP); | ||
| 2738 | 2917 | ||
| 2739 | (dr + n)->dev_id = hdev->id; | 2918 | (dr + n)->dev_id = hdev->id; |
| 2740 | (dr + n)->dev_opt = hdev->flags; | 2919 | (dr + n)->dev_opt = flags; |
| 2741 | 2920 | ||
| 2742 | if (++n >= dev_num) | 2921 | if (++n >= dev_num) |
| 2743 | break; | 2922 | break; |
| @@ -2757,6 +2936,7 @@ int hci_get_dev_info(void __user *arg) | |||
| 2757 | { | 2936 | { |
| 2758 | struct hci_dev *hdev; | 2937 | struct hci_dev *hdev; |
| 2759 | struct hci_dev_info di; | 2938 | struct hci_dev_info di; |
| 2939 | unsigned long flags; | ||
| 2760 | int err = 0; | 2940 | int err = 0; |
| 2761 | 2941 | ||
| 2762 | if (copy_from_user(&di, arg, sizeof(di))) | 2942 | if (copy_from_user(&di, arg, sizeof(di))) |
| @@ -2766,16 +2946,19 @@ int hci_get_dev_info(void __user *arg) | |||
| 2766 | if (!hdev) | 2946 | if (!hdev) |
| 2767 | return -ENODEV; | 2947 | return -ENODEV; |
| 2768 | 2948 | ||
| 2769 | if (test_and_clear_bit(HCI_AUTO_OFF, &hdev->dev_flags)) | 2949 | /* When the auto-off is configured it means the transport |
| 2770 | cancel_delayed_work_sync(&hdev->power_off); | 2950 | * is running, but in that case still indicate that the |
| 2771 | 2951 | * device is actually down. | |
| 2772 | if (!test_bit(HCI_MGMT, &hdev->dev_flags)) | 2952 | */ |
| 2773 | set_bit(HCI_PAIRABLE, &hdev->dev_flags); | 2953 | if (test_bit(HCI_AUTO_OFF, &hdev->dev_flags)) |
| 2954 | flags = hdev->flags & ~BIT(HCI_UP); | ||
| 2955 | else | ||
| 2956 | flags = hdev->flags; | ||
| 2774 | 2957 | ||
| 2775 | strcpy(di.name, hdev->name); | 2958 | strcpy(di.name, hdev->name); |
| 2776 | di.bdaddr = hdev->bdaddr; | 2959 | di.bdaddr = hdev->bdaddr; |
| 2777 | di.type = (hdev->bus & 0x0f) | ((hdev->dev_type & 0x03) << 4); | 2960 | di.type = (hdev->bus & 0x0f) | ((hdev->dev_type & 0x03) << 4); |
| 2778 | di.flags = hdev->flags; | 2961 | di.flags = flags; |
| 2779 | di.pkt_type = hdev->pkt_type; | 2962 | di.pkt_type = hdev->pkt_type; |
| 2780 | if (lmp_bredr_capable(hdev)) { | 2963 | if (lmp_bredr_capable(hdev)) { |
| 2781 | di.acl_mtu = hdev->acl_mtu; | 2964 | di.acl_mtu = hdev->acl_mtu; |
| @@ -2815,7 +2998,8 @@ static int hci_rfkill_set_block(void *data, bool blocked) | |||
| 2815 | 2998 | ||
| 2816 | if (blocked) { | 2999 | if (blocked) { |
| 2817 | set_bit(HCI_RFKILLED, &hdev->dev_flags); | 3000 | set_bit(HCI_RFKILLED, &hdev->dev_flags); |
| 2818 | if (!test_bit(HCI_SETUP, &hdev->dev_flags)) | 3001 | if (!test_bit(HCI_SETUP, &hdev->dev_flags) && |
| 3002 | !test_bit(HCI_CONFIG, &hdev->dev_flags)) | ||
| 2819 | hci_dev_do_close(hdev); | 3003 | hci_dev_do_close(hdev); |
| 2820 | } else { | 3004 | } else { |
| 2821 | clear_bit(HCI_RFKILLED, &hdev->dev_flags); | 3005 | clear_bit(HCI_RFKILLED, &hdev->dev_flags); |
| @@ -2846,6 +3030,7 @@ static void hci_power_on(struct work_struct *work) | |||
| 2846 | * valid, it is important to turn the device back off. | 3030 | * valid, it is important to turn the device back off. |
| 2847 | */ | 3031 | */ |
| 2848 | if (test_bit(HCI_RFKILLED, &hdev->dev_flags) || | 3032 | if (test_bit(HCI_RFKILLED, &hdev->dev_flags) || |
| 3033 | test_bit(HCI_UNCONFIGURED, &hdev->dev_flags) || | ||
| 2849 | (hdev->dev_type == HCI_BREDR && | 3034 | (hdev->dev_type == HCI_BREDR && |
| 2850 | !bacmp(&hdev->bdaddr, BDADDR_ANY) && | 3035 | !bacmp(&hdev->bdaddr, BDADDR_ANY) && |
| 2851 | !bacmp(&hdev->static_addr, BDADDR_ANY))) { | 3036 | !bacmp(&hdev->static_addr, BDADDR_ANY))) { |
| @@ -2856,8 +3041,34 @@ static void hci_power_on(struct work_struct *work) | |||
| 2856 | HCI_AUTO_OFF_TIMEOUT); | 3041 | HCI_AUTO_OFF_TIMEOUT); |
| 2857 | } | 3042 | } |
| 2858 | 3043 | ||
| 2859 | if (test_and_clear_bit(HCI_SETUP, &hdev->dev_flags)) | 3044 | if (test_and_clear_bit(HCI_SETUP, &hdev->dev_flags)) { |
| 3045 | /* For unconfigured devices, set the HCI_RAW flag | ||
| 3046 | * so that userspace can easily identify them. | ||
| 3047 | */ | ||
| 3048 | if (test_bit(HCI_UNCONFIGURED, &hdev->dev_flags)) | ||
| 3049 | set_bit(HCI_RAW, &hdev->flags); | ||
| 3050 | |||
| 3051 | /* For fully configured devices, this will send | ||
| 3052 | * the Index Added event. For unconfigured devices, | ||
| 3053 | * it will send Unconfigued Index Added event. | ||
| 3054 | * | ||
| 3055 | * Devices with HCI_QUIRK_RAW_DEVICE are ignored | ||
| 3056 | * and no event will be send. | ||
| 3057 | */ | ||
| 3058 | mgmt_index_added(hdev); | ||
| 3059 | } else if (test_and_clear_bit(HCI_CONFIG, &hdev->dev_flags)) { | ||
| 3060 | /* When the controller is now configured, then it | ||
| 3061 | * is important to clear the HCI_RAW flag. | ||
| 3062 | */ | ||
| 3063 | if (!test_bit(HCI_UNCONFIGURED, &hdev->dev_flags)) | ||
| 3064 | clear_bit(HCI_RAW, &hdev->flags); | ||
| 3065 | |||
| 3066 | /* Powering on the controller with HCI_CONFIG set only | ||
| 3067 | * happens with the transition from unconfigured to | ||
| 3068 | * configured. This will send the Index Added event. | ||
| 3069 | */ | ||
| 2860 | mgmt_index_added(hdev); | 3070 | mgmt_index_added(hdev); |
| 3071 | } | ||
| 2861 | } | 3072 | } |
| 2862 | 3073 | ||
| 2863 | static void hci_power_off(struct work_struct *work) | 3074 | static void hci_power_off(struct work_struct *work) |
| @@ -2972,16 +3183,16 @@ static bool hci_persistent_key(struct hci_dev *hdev, struct hci_conn *conn, | |||
| 2972 | return false; | 3183 | return false; |
| 2973 | } | 3184 | } |
| 2974 | 3185 | ||
| 2975 | static bool ltk_type_master(u8 type) | 3186 | static u8 ltk_role(u8 type) |
| 2976 | { | 3187 | { |
| 2977 | if (type == HCI_SMP_STK || type == HCI_SMP_LTK) | 3188 | if (type == SMP_LTK) |
| 2978 | return true; | 3189 | return HCI_ROLE_MASTER; |
| 2979 | 3190 | ||
| 2980 | return false; | 3191 | return HCI_ROLE_SLAVE; |
| 2981 | } | 3192 | } |
| 2982 | 3193 | ||
| 2983 | struct smp_ltk *hci_find_ltk(struct hci_dev *hdev, __le16 ediv, __le64 rand, | 3194 | struct smp_ltk *hci_find_ltk(struct hci_dev *hdev, __le16 ediv, __le64 rand, |
| 2984 | bool master) | 3195 | u8 role) |
| 2985 | { | 3196 | { |
| 2986 | struct smp_ltk *k; | 3197 | struct smp_ltk *k; |
| 2987 | 3198 | ||
| @@ -2989,7 +3200,7 @@ struct smp_ltk *hci_find_ltk(struct hci_dev *hdev, __le16 ediv, __le64 rand, | |||
| 2989 | if (k->ediv != ediv || k->rand != rand) | 3200 | if (k->ediv != ediv || k->rand != rand) |
| 2990 | continue; | 3201 | continue; |
| 2991 | 3202 | ||
| 2992 | if (ltk_type_master(k->type) != master) | 3203 | if (ltk_role(k->type) != role) |
| 2993 | continue; | 3204 | continue; |
| 2994 | 3205 | ||
| 2995 | return k; | 3206 | return k; |
| @@ -2999,14 +3210,14 @@ struct smp_ltk *hci_find_ltk(struct hci_dev *hdev, __le16 ediv, __le64 rand, | |||
| 2999 | } | 3210 | } |
| 3000 | 3211 | ||
| 3001 | struct smp_ltk *hci_find_ltk_by_addr(struct hci_dev *hdev, bdaddr_t *bdaddr, | 3212 | struct smp_ltk *hci_find_ltk_by_addr(struct hci_dev *hdev, bdaddr_t *bdaddr, |
| 3002 | u8 addr_type, bool master) | 3213 | u8 addr_type, u8 role) |
| 3003 | { | 3214 | { |
| 3004 | struct smp_ltk *k; | 3215 | struct smp_ltk *k; |
| 3005 | 3216 | ||
| 3006 | list_for_each_entry(k, &hdev->long_term_keys, list) | 3217 | list_for_each_entry(k, &hdev->long_term_keys, list) |
| 3007 | if (addr_type == k->bdaddr_type && | 3218 | if (addr_type == k->bdaddr_type && |
| 3008 | bacmp(bdaddr, &k->bdaddr) == 0 && | 3219 | bacmp(bdaddr, &k->bdaddr) == 0 && |
| 3009 | ltk_type_master(k->type) == master) | 3220 | ltk_role(k->type) == role) |
| 3010 | return k; | 3221 | return k; |
| 3011 | 3222 | ||
| 3012 | return NULL; | 3223 | return NULL; |
| @@ -3049,12 +3260,12 @@ struct smp_irk *hci_find_irk_by_addr(struct hci_dev *hdev, bdaddr_t *bdaddr, | |||
| 3049 | return NULL; | 3260 | return NULL; |
| 3050 | } | 3261 | } |
| 3051 | 3262 | ||
| 3052 | int hci_add_link_key(struct hci_dev *hdev, struct hci_conn *conn, int new_key, | 3263 | struct link_key *hci_add_link_key(struct hci_dev *hdev, struct hci_conn *conn, |
| 3053 | bdaddr_t *bdaddr, u8 *val, u8 type, u8 pin_len) | 3264 | bdaddr_t *bdaddr, u8 *val, u8 type, |
| 3265 | u8 pin_len, bool *persistent) | ||
| 3054 | { | 3266 | { |
| 3055 | struct link_key *key, *old_key; | 3267 | struct link_key *key, *old_key; |
| 3056 | u8 old_key_type; | 3268 | u8 old_key_type; |
| 3057 | bool persistent; | ||
| 3058 | 3269 | ||
| 3059 | old_key = hci_find_link_key(hdev, bdaddr); | 3270 | old_key = hci_find_link_key(hdev, bdaddr); |
| 3060 | if (old_key) { | 3271 | if (old_key) { |
| @@ -3064,7 +3275,7 @@ int hci_add_link_key(struct hci_dev *hdev, struct hci_conn *conn, int new_key, | |||
| 3064 | old_key_type = conn ? conn->key_type : 0xff; | 3275 | old_key_type = conn ? conn->key_type : 0xff; |
| 3065 | key = kzalloc(sizeof(*key), GFP_KERNEL); | 3276 | key = kzalloc(sizeof(*key), GFP_KERNEL); |
| 3066 | if (!key) | 3277 | if (!key) |
| 3067 | return -ENOMEM; | 3278 | return NULL; |
| 3068 | list_add(&key->list, &hdev->link_keys); | 3279 | list_add(&key->list, &hdev->link_keys); |
| 3069 | } | 3280 | } |
| 3070 | 3281 | ||
| @@ -3089,17 +3300,11 @@ int hci_add_link_key(struct hci_dev *hdev, struct hci_conn *conn, int new_key, | |||
| 3089 | else | 3300 | else |
| 3090 | key->type = type; | 3301 | key->type = type; |
| 3091 | 3302 | ||
| 3092 | if (!new_key) | 3303 | if (persistent) |
| 3093 | return 0; | 3304 | *persistent = hci_persistent_key(hdev, conn, type, |
| 3094 | 3305 | old_key_type); | |
| 3095 | persistent = hci_persistent_key(hdev, conn, type, old_key_type); | ||
| 3096 | |||
| 3097 | mgmt_new_link_key(hdev, key, persistent); | ||
| 3098 | |||
| 3099 | if (conn) | ||
| 3100 | conn->flush_key = !persistent; | ||
| 3101 | 3306 | ||
| 3102 | return 0; | 3307 | return key; |
| 3103 | } | 3308 | } |
| 3104 | 3309 | ||
| 3105 | struct smp_ltk *hci_add_ltk(struct hci_dev *hdev, bdaddr_t *bdaddr, | 3310 | struct smp_ltk *hci_add_ltk(struct hci_dev *hdev, bdaddr_t *bdaddr, |
| @@ -3107,9 +3312,9 @@ struct smp_ltk *hci_add_ltk(struct hci_dev *hdev, bdaddr_t *bdaddr, | |||
| 3107 | u8 tk[16], u8 enc_size, __le16 ediv, __le64 rand) | 3312 | u8 tk[16], u8 enc_size, __le16 ediv, __le64 rand) |
| 3108 | { | 3313 | { |
| 3109 | struct smp_ltk *key, *old_key; | 3314 | struct smp_ltk *key, *old_key; |
| 3110 | bool master = ltk_type_master(type); | 3315 | u8 role = ltk_role(type); |
| 3111 | 3316 | ||
| 3112 | old_key = hci_find_ltk_by_addr(hdev, bdaddr, addr_type, master); | 3317 | old_key = hci_find_ltk_by_addr(hdev, bdaddr, addr_type, role); |
| 3113 | if (old_key) | 3318 | if (old_key) |
| 3114 | key = old_key; | 3319 | key = old_key; |
| 3115 | else { | 3320 | else { |
| @@ -3205,9 +3410,10 @@ void hci_remove_irk(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 addr_type) | |||
| 3205 | } | 3410 | } |
| 3206 | 3411 | ||
| 3207 | /* HCI command timer function */ | 3412 | /* HCI command timer function */ |
| 3208 | static void hci_cmd_timeout(unsigned long arg) | 3413 | static void hci_cmd_timeout(struct work_struct *work) |
| 3209 | { | 3414 | { |
| 3210 | struct hci_dev *hdev = (void *) arg; | 3415 | struct hci_dev *hdev = container_of(work, struct hci_dev, |
| 3416 | cmd_timer.work); | ||
| 3211 | 3417 | ||
| 3212 | if (hdev->sent_cmd) { | 3418 | if (hdev->sent_cmd) { |
| 3213 | struct hci_command_hdr *sent = (void *) hdev->sent_cmd->data; | 3419 | struct hci_command_hdr *sent = (void *) hdev->sent_cmd->data; |
| @@ -3313,12 +3519,12 @@ int hci_add_remote_oob_ext_data(struct hci_dev *hdev, bdaddr_t *bdaddr, | |||
| 3313 | return 0; | 3519 | return 0; |
| 3314 | } | 3520 | } |
| 3315 | 3521 | ||
| 3316 | struct bdaddr_list *hci_blacklist_lookup(struct hci_dev *hdev, | 3522 | struct bdaddr_list *hci_bdaddr_list_lookup(struct list_head *bdaddr_list, |
| 3317 | bdaddr_t *bdaddr, u8 type) | 3523 | bdaddr_t *bdaddr, u8 type) |
| 3318 | { | 3524 | { |
| 3319 | struct bdaddr_list *b; | 3525 | struct bdaddr_list *b; |
| 3320 | 3526 | ||
| 3321 | list_for_each_entry(b, &hdev->blacklist, list) { | 3527 | list_for_each_entry(b, bdaddr_list, list) { |
| 3322 | if (!bacmp(&b->bdaddr, bdaddr) && b->bdaddr_type == type) | 3528 | if (!bacmp(&b->bdaddr, bdaddr) && b->bdaddr_type == type) |
| 3323 | return b; | 3529 | return b; |
| 3324 | } | 3530 | } |
| @@ -3326,11 +3532,11 @@ struct bdaddr_list *hci_blacklist_lookup(struct hci_dev *hdev, | |||
| 3326 | return NULL; | 3532 | return NULL; |
| 3327 | } | 3533 | } |
| 3328 | 3534 | ||
| 3329 | static void hci_blacklist_clear(struct hci_dev *hdev) | 3535 | void hci_bdaddr_list_clear(struct list_head *bdaddr_list) |
| 3330 | { | 3536 | { |
| 3331 | struct list_head *p, *n; | 3537 | struct list_head *p, *n; |
| 3332 | 3538 | ||
| 3333 | list_for_each_safe(p, n, &hdev->blacklist) { | 3539 | list_for_each_safe(p, n, bdaddr_list) { |
| 3334 | struct bdaddr_list *b = list_entry(p, struct bdaddr_list, list); | 3540 | struct bdaddr_list *b = list_entry(p, struct bdaddr_list, list); |
| 3335 | 3541 | ||
| 3336 | list_del(p); | 3542 | list_del(p); |
| @@ -3338,99 +3544,38 @@ static void hci_blacklist_clear(struct hci_dev *hdev) | |||
| 3338 | } | 3544 | } |
| 3339 | } | 3545 | } |
| 3340 | 3546 | ||
| 3341 | int hci_blacklist_add(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 type) | 3547 | int hci_bdaddr_list_add(struct list_head *list, bdaddr_t *bdaddr, u8 type) |
| 3342 | { | 3548 | { |
| 3343 | struct bdaddr_list *entry; | 3549 | struct bdaddr_list *entry; |
| 3344 | 3550 | ||
| 3345 | if (!bacmp(bdaddr, BDADDR_ANY)) | 3551 | if (!bacmp(bdaddr, BDADDR_ANY)) |
| 3346 | return -EBADF; | 3552 | return -EBADF; |
| 3347 | 3553 | ||
| 3348 | if (hci_blacklist_lookup(hdev, bdaddr, type)) | 3554 | if (hci_bdaddr_list_lookup(list, bdaddr, type)) |
| 3349 | return -EEXIST; | 3555 | return -EEXIST; |
| 3350 | 3556 | ||
| 3351 | entry = kzalloc(sizeof(struct bdaddr_list), GFP_KERNEL); | 3557 | entry = kzalloc(sizeof(*entry), GFP_KERNEL); |
| 3352 | if (!entry) | 3558 | if (!entry) |
| 3353 | return -ENOMEM; | 3559 | return -ENOMEM; |
| 3354 | 3560 | ||
| 3355 | bacpy(&entry->bdaddr, bdaddr); | 3561 | bacpy(&entry->bdaddr, bdaddr); |
| 3356 | entry->bdaddr_type = type; | 3562 | entry->bdaddr_type = type; |
| 3357 | 3563 | ||
| 3358 | list_add(&entry->list, &hdev->blacklist); | 3564 | list_add(&entry->list, list); |
| 3359 | 3565 | ||
| 3360 | return mgmt_device_blocked(hdev, bdaddr, type); | 3566 | return 0; |
| 3361 | } | 3567 | } |
| 3362 | 3568 | ||
| 3363 | int hci_blacklist_del(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 type) | 3569 | int hci_bdaddr_list_del(struct list_head *list, bdaddr_t *bdaddr, u8 type) |
| 3364 | { | 3570 | { |
| 3365 | struct bdaddr_list *entry; | 3571 | struct bdaddr_list *entry; |
| 3366 | 3572 | ||
| 3367 | if (!bacmp(bdaddr, BDADDR_ANY)) { | 3573 | if (!bacmp(bdaddr, BDADDR_ANY)) { |
| 3368 | hci_blacklist_clear(hdev); | 3574 | hci_bdaddr_list_clear(list); |
| 3369 | return 0; | 3575 | return 0; |
| 3370 | } | 3576 | } |
| 3371 | 3577 | ||
| 3372 | entry = hci_blacklist_lookup(hdev, bdaddr, type); | 3578 | entry = hci_bdaddr_list_lookup(list, bdaddr, type); |
| 3373 | if (!entry) | ||
| 3374 | return -ENOENT; | ||
| 3375 | |||
| 3376 | list_del(&entry->list); | ||
| 3377 | kfree(entry); | ||
| 3378 | |||
| 3379 | return mgmt_device_unblocked(hdev, bdaddr, type); | ||
| 3380 | } | ||
| 3381 | |||
| 3382 | struct bdaddr_list *hci_white_list_lookup(struct hci_dev *hdev, | ||
| 3383 | bdaddr_t *bdaddr, u8 type) | ||
| 3384 | { | ||
| 3385 | struct bdaddr_list *b; | ||
| 3386 | |||
| 3387 | list_for_each_entry(b, &hdev->le_white_list, list) { | ||
| 3388 | if (!bacmp(&b->bdaddr, bdaddr) && b->bdaddr_type == type) | ||
| 3389 | return b; | ||
| 3390 | } | ||
| 3391 | |||
| 3392 | return NULL; | ||
| 3393 | } | ||
| 3394 | |||
| 3395 | void hci_white_list_clear(struct hci_dev *hdev) | ||
| 3396 | { | ||
| 3397 | struct list_head *p, *n; | ||
| 3398 | |||
| 3399 | list_for_each_safe(p, n, &hdev->le_white_list) { | ||
| 3400 | struct bdaddr_list *b = list_entry(p, struct bdaddr_list, list); | ||
| 3401 | |||
| 3402 | list_del(p); | ||
| 3403 | kfree(b); | ||
| 3404 | } | ||
| 3405 | } | ||
| 3406 | |||
| 3407 | int hci_white_list_add(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 type) | ||
| 3408 | { | ||
| 3409 | struct bdaddr_list *entry; | ||
| 3410 | |||
| 3411 | if (!bacmp(bdaddr, BDADDR_ANY)) | ||
| 3412 | return -EBADF; | ||
| 3413 | |||
| 3414 | entry = kzalloc(sizeof(struct bdaddr_list), GFP_KERNEL); | ||
| 3415 | if (!entry) | ||
| 3416 | return -ENOMEM; | ||
| 3417 | |||
| 3418 | bacpy(&entry->bdaddr, bdaddr); | ||
| 3419 | entry->bdaddr_type = type; | ||
| 3420 | |||
| 3421 | list_add(&entry->list, &hdev->le_white_list); | ||
| 3422 | |||
| 3423 | return 0; | ||
| 3424 | } | ||
| 3425 | |||
| 3426 | int hci_white_list_del(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 type) | ||
| 3427 | { | ||
| 3428 | struct bdaddr_list *entry; | ||
| 3429 | |||
| 3430 | if (!bacmp(bdaddr, BDADDR_ANY)) | ||
| 3431 | return -EBADF; | ||
| 3432 | |||
| 3433 | entry = hci_white_list_lookup(hdev, bdaddr, type); | ||
| 3434 | if (!entry) | 3579 | if (!entry) |
| 3435 | return -ENOENT; | 3580 | return -ENOENT; |
| 3436 | 3581 | ||
| @@ -3446,6 +3591,10 @@ struct hci_conn_params *hci_conn_params_lookup(struct hci_dev *hdev, | |||
| 3446 | { | 3591 | { |
| 3447 | struct hci_conn_params *params; | 3592 | struct hci_conn_params *params; |
| 3448 | 3593 | ||
| 3594 | /* The conn params list only contains identity addresses */ | ||
| 3595 | if (!hci_is_identity_address(addr, addr_type)) | ||
| 3596 | return NULL; | ||
| 3597 | |||
| 3449 | list_for_each_entry(params, &hdev->le_conn_params, list) { | 3598 | list_for_each_entry(params, &hdev->le_conn_params, list) { |
| 3450 | if (bacmp(¶ms->addr, addr) == 0 && | 3599 | if (bacmp(¶ms->addr, addr) == 0 && |
| 3451 | params->addr_type == addr_type) { | 3600 | params->addr_type == addr_type) { |
| @@ -3473,62 +3622,98 @@ static bool is_connected(struct hci_dev *hdev, bdaddr_t *addr, u8 type) | |||
| 3473 | return true; | 3622 | return true; |
| 3474 | } | 3623 | } |
| 3475 | 3624 | ||
| 3476 | static bool is_identity_address(bdaddr_t *addr, u8 addr_type) | 3625 | /* This function requires the caller holds hdev->lock */ |
| 3626 | struct hci_conn_params *hci_pend_le_action_lookup(struct list_head *list, | ||
| 3627 | bdaddr_t *addr, u8 addr_type) | ||
| 3477 | { | 3628 | { |
| 3478 | if (addr_type == ADDR_LE_DEV_PUBLIC) | 3629 | struct hci_conn_params *param; |
| 3479 | return true; | ||
| 3480 | 3630 | ||
| 3481 | /* Check for Random Static address type */ | 3631 | /* The list only contains identity addresses */ |
| 3482 | if ((addr->b[5] & 0xc0) == 0xc0) | 3632 | if (!hci_is_identity_address(addr, addr_type)) |
| 3483 | return true; | 3633 | return NULL; |
| 3484 | 3634 | ||
| 3485 | return false; | 3635 | list_for_each_entry(param, list, action) { |
| 3636 | if (bacmp(¶m->addr, addr) == 0 && | ||
| 3637 | param->addr_type == addr_type) | ||
| 3638 | return param; | ||
| 3639 | } | ||
| 3640 | |||
| 3641 | return NULL; | ||
| 3486 | } | 3642 | } |
| 3487 | 3643 | ||
| 3488 | /* This function requires the caller holds hdev->lock */ | 3644 | /* This function requires the caller holds hdev->lock */ |
| 3489 | int hci_conn_params_add(struct hci_dev *hdev, bdaddr_t *addr, u8 addr_type, | 3645 | struct hci_conn_params *hci_conn_params_add(struct hci_dev *hdev, |
| 3490 | u8 auto_connect, u16 conn_min_interval, | 3646 | bdaddr_t *addr, u8 addr_type) |
| 3491 | u16 conn_max_interval) | ||
| 3492 | { | 3647 | { |
| 3493 | struct hci_conn_params *params; | 3648 | struct hci_conn_params *params; |
| 3494 | 3649 | ||
| 3495 | if (!is_identity_address(addr, addr_type)) | 3650 | if (!hci_is_identity_address(addr, addr_type)) |
| 3496 | return -EINVAL; | 3651 | return NULL; |
| 3497 | 3652 | ||
| 3498 | params = hci_conn_params_lookup(hdev, addr, addr_type); | 3653 | params = hci_conn_params_lookup(hdev, addr, addr_type); |
| 3499 | if (params) | 3654 | if (params) |
| 3500 | goto update; | 3655 | return params; |
| 3501 | 3656 | ||
| 3502 | params = kzalloc(sizeof(*params), GFP_KERNEL); | 3657 | params = kzalloc(sizeof(*params), GFP_KERNEL); |
| 3503 | if (!params) { | 3658 | if (!params) { |
| 3504 | BT_ERR("Out of memory"); | 3659 | BT_ERR("Out of memory"); |
| 3505 | return -ENOMEM; | 3660 | return NULL; |
| 3506 | } | 3661 | } |
| 3507 | 3662 | ||
| 3508 | bacpy(¶ms->addr, addr); | 3663 | bacpy(¶ms->addr, addr); |
| 3509 | params->addr_type = addr_type; | 3664 | params->addr_type = addr_type; |
| 3510 | 3665 | ||
| 3511 | list_add(¶ms->list, &hdev->le_conn_params); | 3666 | list_add(¶ms->list, &hdev->le_conn_params); |
| 3667 | INIT_LIST_HEAD(¶ms->action); | ||
| 3512 | 3668 | ||
| 3513 | update: | 3669 | params->conn_min_interval = hdev->le_conn_min_interval; |
| 3514 | params->conn_min_interval = conn_min_interval; | 3670 | params->conn_max_interval = hdev->le_conn_max_interval; |
| 3515 | params->conn_max_interval = conn_max_interval; | 3671 | params->conn_latency = hdev->le_conn_latency; |
| 3516 | params->auto_connect = auto_connect; | 3672 | params->supervision_timeout = hdev->le_supv_timeout; |
| 3673 | params->auto_connect = HCI_AUTO_CONN_DISABLED; | ||
| 3674 | |||
| 3675 | BT_DBG("addr %pMR (type %u)", addr, addr_type); | ||
| 3676 | |||
| 3677 | return params; | ||
| 3678 | } | ||
| 3679 | |||
| 3680 | /* This function requires the caller holds hdev->lock */ | ||
| 3681 | int hci_conn_params_set(struct hci_dev *hdev, bdaddr_t *addr, u8 addr_type, | ||
| 3682 | u8 auto_connect) | ||
| 3683 | { | ||
| 3684 | struct hci_conn_params *params; | ||
| 3685 | |||
| 3686 | params = hci_conn_params_add(hdev, addr, addr_type); | ||
| 3687 | if (!params) | ||
| 3688 | return -EIO; | ||
| 3689 | |||
| 3690 | if (params->auto_connect == auto_connect) | ||
| 3691 | return 0; | ||
| 3692 | |||
| 3693 | list_del_init(¶ms->action); | ||
| 3517 | 3694 | ||
| 3518 | switch (auto_connect) { | 3695 | switch (auto_connect) { |
| 3519 | case HCI_AUTO_CONN_DISABLED: | 3696 | case HCI_AUTO_CONN_DISABLED: |
| 3520 | case HCI_AUTO_CONN_LINK_LOSS: | 3697 | case HCI_AUTO_CONN_LINK_LOSS: |
| 3521 | hci_pend_le_conn_del(hdev, addr, addr_type); | 3698 | hci_update_background_scan(hdev); |
| 3522 | break; | 3699 | break; |
| 3700 | case HCI_AUTO_CONN_REPORT: | ||
| 3701 | list_add(¶ms->action, &hdev->pend_le_reports); | ||
| 3702 | hci_update_background_scan(hdev); | ||
| 3703 | break; | ||
| 3704 | case HCI_AUTO_CONN_DIRECT: | ||
| 3523 | case HCI_AUTO_CONN_ALWAYS: | 3705 | case HCI_AUTO_CONN_ALWAYS: |
| 3524 | if (!is_connected(hdev, addr, addr_type)) | 3706 | if (!is_connected(hdev, addr, addr_type)) { |
| 3525 | hci_pend_le_conn_add(hdev, addr, addr_type); | 3707 | list_add(¶ms->action, &hdev->pend_le_conns); |
| 3708 | hci_update_background_scan(hdev); | ||
| 3709 | } | ||
| 3526 | break; | 3710 | break; |
| 3527 | } | 3711 | } |
| 3528 | 3712 | ||
| 3529 | BT_DBG("addr %pMR (type %u) auto_connect %u conn_min_interval 0x%.4x " | 3713 | params->auto_connect = auto_connect; |
| 3530 | "conn_max_interval 0x%.4x", addr, addr_type, auto_connect, | 3714 | |
| 3531 | conn_min_interval, conn_max_interval); | 3715 | BT_DBG("addr %pMR (type %u) auto_connect %u", addr, addr_type, |
| 3716 | auto_connect); | ||
| 3532 | 3717 | ||
| 3533 | return 0; | 3718 | return 0; |
| 3534 | } | 3719 | } |
| @@ -3542,97 +3727,44 @@ void hci_conn_params_del(struct hci_dev *hdev, bdaddr_t *addr, u8 addr_type) | |||
| 3542 | if (!params) | 3727 | if (!params) |
| 3543 | return; | 3728 | return; |
| 3544 | 3729 | ||
| 3545 | hci_pend_le_conn_del(hdev, addr, addr_type); | 3730 | list_del(¶ms->action); |
| 3546 | |||
| 3547 | list_del(¶ms->list); | 3731 | list_del(¶ms->list); |
| 3548 | kfree(params); | 3732 | kfree(params); |
| 3549 | 3733 | ||
| 3734 | hci_update_background_scan(hdev); | ||
| 3735 | |||
| 3550 | BT_DBG("addr %pMR (type %u)", addr, addr_type); | 3736 | BT_DBG("addr %pMR (type %u)", addr, addr_type); |
| 3551 | } | 3737 | } |
| 3552 | 3738 | ||
| 3553 | /* This function requires the caller holds hdev->lock */ | 3739 | /* This function requires the caller holds hdev->lock */ |
| 3554 | void hci_conn_params_clear(struct hci_dev *hdev) | 3740 | void hci_conn_params_clear_disabled(struct hci_dev *hdev) |
| 3555 | { | 3741 | { |
| 3556 | struct hci_conn_params *params, *tmp; | 3742 | struct hci_conn_params *params, *tmp; |
| 3557 | 3743 | ||
| 3558 | list_for_each_entry_safe(params, tmp, &hdev->le_conn_params, list) { | 3744 | list_for_each_entry_safe(params, tmp, &hdev->le_conn_params, list) { |
| 3745 | if (params->auto_connect != HCI_AUTO_CONN_DISABLED) | ||
| 3746 | continue; | ||
| 3559 | list_del(¶ms->list); | 3747 | list_del(¶ms->list); |
| 3560 | kfree(params); | 3748 | kfree(params); |
| 3561 | } | 3749 | } |
| 3562 | 3750 | ||
| 3563 | BT_DBG("All LE connection parameters were removed"); | 3751 | BT_DBG("All LE disabled connection parameters were removed"); |
| 3564 | } | 3752 | } |
| 3565 | 3753 | ||
| 3566 | /* This function requires the caller holds hdev->lock */ | 3754 | /* This function requires the caller holds hdev->lock */ |
| 3567 | struct bdaddr_list *hci_pend_le_conn_lookup(struct hci_dev *hdev, | 3755 | void hci_conn_params_clear_all(struct hci_dev *hdev) |
| 3568 | bdaddr_t *addr, u8 addr_type) | ||
| 3569 | { | 3756 | { |
| 3570 | struct bdaddr_list *entry; | 3757 | struct hci_conn_params *params, *tmp; |
| 3571 | |||
| 3572 | list_for_each_entry(entry, &hdev->pend_le_conns, list) { | ||
| 3573 | if (bacmp(&entry->bdaddr, addr) == 0 && | ||
| 3574 | entry->bdaddr_type == addr_type) | ||
| 3575 | return entry; | ||
| 3576 | } | ||
| 3577 | |||
| 3578 | return NULL; | ||
| 3579 | } | ||
| 3580 | |||
| 3581 | /* This function requires the caller holds hdev->lock */ | ||
| 3582 | void hci_pend_le_conn_add(struct hci_dev *hdev, bdaddr_t *addr, u8 addr_type) | ||
| 3583 | { | ||
| 3584 | struct bdaddr_list *entry; | ||
| 3585 | |||
| 3586 | entry = hci_pend_le_conn_lookup(hdev, addr, addr_type); | ||
| 3587 | if (entry) | ||
| 3588 | goto done; | ||
| 3589 | 3758 | ||
| 3590 | entry = kzalloc(sizeof(*entry), GFP_KERNEL); | 3759 | list_for_each_entry_safe(params, tmp, &hdev->le_conn_params, list) { |
| 3591 | if (!entry) { | 3760 | list_del(¶ms->action); |
| 3592 | BT_ERR("Out of memory"); | 3761 | list_del(¶ms->list); |
| 3593 | return; | 3762 | kfree(params); |
| 3594 | } | 3763 | } |
| 3595 | 3764 | ||
| 3596 | bacpy(&entry->bdaddr, addr); | ||
| 3597 | entry->bdaddr_type = addr_type; | ||
| 3598 | |||
| 3599 | list_add(&entry->list, &hdev->pend_le_conns); | ||
| 3600 | |||
| 3601 | BT_DBG("addr %pMR (type %u)", addr, addr_type); | ||
| 3602 | |||
| 3603 | done: | ||
| 3604 | hci_update_background_scan(hdev); | ||
| 3605 | } | ||
| 3606 | |||
| 3607 | /* This function requires the caller holds hdev->lock */ | ||
| 3608 | void hci_pend_le_conn_del(struct hci_dev *hdev, bdaddr_t *addr, u8 addr_type) | ||
| 3609 | { | ||
| 3610 | struct bdaddr_list *entry; | ||
| 3611 | |||
| 3612 | entry = hci_pend_le_conn_lookup(hdev, addr, addr_type); | ||
| 3613 | if (!entry) | ||
| 3614 | goto done; | ||
| 3615 | |||
| 3616 | list_del(&entry->list); | ||
| 3617 | kfree(entry); | ||
| 3618 | |||
| 3619 | BT_DBG("addr %pMR (type %u)", addr, addr_type); | ||
| 3620 | |||
| 3621 | done: | ||
| 3622 | hci_update_background_scan(hdev); | 3765 | hci_update_background_scan(hdev); |
| 3623 | } | ||
| 3624 | |||
| 3625 | /* This function requires the caller holds hdev->lock */ | ||
| 3626 | void hci_pend_le_conns_clear(struct hci_dev *hdev) | ||
| 3627 | { | ||
| 3628 | struct bdaddr_list *entry, *tmp; | ||
| 3629 | 3766 | ||
| 3630 | list_for_each_entry_safe(entry, tmp, &hdev->pend_le_conns, list) { | 3767 | BT_DBG("All LE connection parameters were removed"); |
| 3631 | list_del(&entry->list); | ||
| 3632 | kfree(entry); | ||
| 3633 | } | ||
| 3634 | |||
| 3635 | BT_DBG("All LE pending connections cleared"); | ||
| 3636 | } | 3768 | } |
| 3637 | 3769 | ||
| 3638 | static void inquiry_complete(struct hci_dev *hdev, u8 status) | 3770 | static void inquiry_complete(struct hci_dev *hdev, u8 status) |
| @@ -3722,7 +3854,7 @@ static void set_random_addr(struct hci_request *req, bdaddr_t *rpa) | |||
| 3722 | * In this kind of scenario skip the update and let the random | 3854 | * In this kind of scenario skip the update and let the random |
| 3723 | * address be updated at the next cycle. | 3855 | * address be updated at the next cycle. |
| 3724 | */ | 3856 | */ |
| 3725 | if (test_bit(HCI_ADVERTISING, &hdev->dev_flags) || | 3857 | if (test_bit(HCI_LE_ADV, &hdev->dev_flags) || |
| 3726 | hci_conn_hash_lookup_state(hdev, LE_LINK, BT_CONNECT)) { | 3858 | hci_conn_hash_lookup_state(hdev, LE_LINK, BT_CONNECT)) { |
| 3727 | BT_DBG("Deferring random address update"); | 3859 | BT_DBG("Deferring random address update"); |
| 3728 | return; | 3860 | return; |
| @@ -3784,7 +3916,7 @@ int hci_update_random_address(struct hci_request *req, bool require_privacy, | |||
| 3784 | * the HCI command if the current random address is already the | 3916 | * the HCI command if the current random address is already the |
| 3785 | * static one. | 3917 | * static one. |
| 3786 | */ | 3918 | */ |
| 3787 | if (test_bit(HCI_FORCE_STATIC_ADDR, &hdev->dev_flags) || | 3919 | if (test_bit(HCI_FORCE_STATIC_ADDR, &hdev->dbg_flags) || |
| 3788 | !bacmp(&hdev->bdaddr, BDADDR_ANY)) { | 3920 | !bacmp(&hdev->bdaddr, BDADDR_ANY)) { |
| 3789 | *own_addr_type = ADDR_LE_DEV_RANDOM; | 3921 | *own_addr_type = ADDR_LE_DEV_RANDOM; |
| 3790 | if (bacmp(&hdev->static_addr, &hdev->random_addr)) | 3922 | if (bacmp(&hdev->static_addr, &hdev->random_addr)) |
| @@ -3813,7 +3945,7 @@ int hci_update_random_address(struct hci_request *req, bool require_privacy, | |||
| 3813 | void hci_copy_identity_address(struct hci_dev *hdev, bdaddr_t *bdaddr, | 3945 | void hci_copy_identity_address(struct hci_dev *hdev, bdaddr_t *bdaddr, |
| 3814 | u8 *bdaddr_type) | 3946 | u8 *bdaddr_type) |
| 3815 | { | 3947 | { |
| 3816 | if (test_bit(HCI_FORCE_STATIC_ADDR, &hdev->dev_flags) || | 3948 | if (test_bit(HCI_FORCE_STATIC_ADDR, &hdev->dbg_flags) || |
| 3817 | !bacmp(&hdev->bdaddr, BDADDR_ANY)) { | 3949 | !bacmp(&hdev->bdaddr, BDADDR_ANY)) { |
| 3818 | bacpy(bdaddr, &hdev->static_addr); | 3950 | bacpy(bdaddr, &hdev->static_addr); |
| 3819 | *bdaddr_type = ADDR_LE_DEV_RANDOM; | 3951 | *bdaddr_type = ADDR_LE_DEV_RANDOM; |
| @@ -3828,7 +3960,7 @@ struct hci_dev *hci_alloc_dev(void) | |||
| 3828 | { | 3960 | { |
| 3829 | struct hci_dev *hdev; | 3961 | struct hci_dev *hdev; |
| 3830 | 3962 | ||
| 3831 | hdev = kzalloc(sizeof(struct hci_dev), GFP_KERNEL); | 3963 | hdev = kzalloc(sizeof(*hdev), GFP_KERNEL); |
| 3832 | if (!hdev) | 3964 | if (!hdev) |
| 3833 | return NULL; | 3965 | return NULL; |
| 3834 | 3966 | ||
| @@ -3837,6 +3969,7 @@ struct hci_dev *hci_alloc_dev(void) | |||
| 3837 | hdev->link_mode = (HCI_LM_ACCEPT); | 3969 | hdev->link_mode = (HCI_LM_ACCEPT); |
| 3838 | hdev->num_iac = 0x01; /* One IAC support is mandatory */ | 3970 | hdev->num_iac = 0x01; /* One IAC support is mandatory */ |
| 3839 | hdev->io_capability = 0x03; /* No Input No Output */ | 3971 | hdev->io_capability = 0x03; /* No Input No Output */ |
| 3972 | hdev->manufacturer = 0xffff; /* Default to internal use */ | ||
| 3840 | hdev->inq_tx_power = HCI_TX_POWER_INVALID; | 3973 | hdev->inq_tx_power = HCI_TX_POWER_INVALID; |
| 3841 | hdev->adv_tx_power = HCI_TX_POWER_INVALID; | 3974 | hdev->adv_tx_power = HCI_TX_POWER_INVALID; |
| 3842 | 3975 | ||
| @@ -3844,10 +3977,14 @@ struct hci_dev *hci_alloc_dev(void) | |||
| 3844 | hdev->sniff_min_interval = 80; | 3977 | hdev->sniff_min_interval = 80; |
| 3845 | 3978 | ||
| 3846 | hdev->le_adv_channel_map = 0x07; | 3979 | hdev->le_adv_channel_map = 0x07; |
| 3980 | hdev->le_adv_min_interval = 0x0800; | ||
| 3981 | hdev->le_adv_max_interval = 0x0800; | ||
| 3847 | hdev->le_scan_interval = 0x0060; | 3982 | hdev->le_scan_interval = 0x0060; |
| 3848 | hdev->le_scan_window = 0x0030; | 3983 | hdev->le_scan_window = 0x0030; |
| 3849 | hdev->le_conn_min_interval = 0x0028; | 3984 | hdev->le_conn_min_interval = 0x0028; |
| 3850 | hdev->le_conn_max_interval = 0x0038; | 3985 | hdev->le_conn_max_interval = 0x0038; |
| 3986 | hdev->le_conn_latency = 0x0000; | ||
| 3987 | hdev->le_supv_timeout = 0x002a; | ||
| 3851 | 3988 | ||
| 3852 | hdev->rpa_timeout = HCI_DEFAULT_RPA_TIMEOUT; | 3989 | hdev->rpa_timeout = HCI_DEFAULT_RPA_TIMEOUT; |
| 3853 | hdev->discov_interleaved_timeout = DISCOV_INTERLEAVED_TIMEOUT; | 3990 | hdev->discov_interleaved_timeout = DISCOV_INTERLEAVED_TIMEOUT; |
| @@ -3859,6 +3996,7 @@ struct hci_dev *hci_alloc_dev(void) | |||
| 3859 | 3996 | ||
| 3860 | INIT_LIST_HEAD(&hdev->mgmt_pending); | 3997 | INIT_LIST_HEAD(&hdev->mgmt_pending); |
| 3861 | INIT_LIST_HEAD(&hdev->blacklist); | 3998 | INIT_LIST_HEAD(&hdev->blacklist); |
| 3999 | INIT_LIST_HEAD(&hdev->whitelist); | ||
| 3862 | INIT_LIST_HEAD(&hdev->uuids); | 4000 | INIT_LIST_HEAD(&hdev->uuids); |
| 3863 | INIT_LIST_HEAD(&hdev->link_keys); | 4001 | INIT_LIST_HEAD(&hdev->link_keys); |
| 3864 | INIT_LIST_HEAD(&hdev->long_term_keys); | 4002 | INIT_LIST_HEAD(&hdev->long_term_keys); |
| @@ -3867,6 +4005,7 @@ struct hci_dev *hci_alloc_dev(void) | |||
| 3867 | INIT_LIST_HEAD(&hdev->le_white_list); | 4005 | INIT_LIST_HEAD(&hdev->le_white_list); |
| 3868 | INIT_LIST_HEAD(&hdev->le_conn_params); | 4006 | INIT_LIST_HEAD(&hdev->le_conn_params); |
| 3869 | INIT_LIST_HEAD(&hdev->pend_le_conns); | 4007 | INIT_LIST_HEAD(&hdev->pend_le_conns); |
| 4008 | INIT_LIST_HEAD(&hdev->pend_le_reports); | ||
| 3870 | INIT_LIST_HEAD(&hdev->conn_hash.list); | 4009 | INIT_LIST_HEAD(&hdev->conn_hash.list); |
| 3871 | 4010 | ||
| 3872 | INIT_WORK(&hdev->rx_work, hci_rx_work); | 4011 | INIT_WORK(&hdev->rx_work, hci_rx_work); |
| @@ -3884,7 +4023,7 @@ struct hci_dev *hci_alloc_dev(void) | |||
| 3884 | 4023 | ||
| 3885 | init_waitqueue_head(&hdev->req_wait_q); | 4024 | init_waitqueue_head(&hdev->req_wait_q); |
| 3886 | 4025 | ||
| 3887 | setup_timer(&hdev->cmd_timer, hci_cmd_timeout, (unsigned long) hdev); | 4026 | INIT_DELAYED_WORK(&hdev->cmd_timer, hci_cmd_timeout); |
| 3888 | 4027 | ||
| 3889 | hci_init_sysfs(hdev); | 4028 | hci_init_sysfs(hdev); |
| 3890 | discovery_init(hdev); | 4029 | discovery_init(hdev); |
| @@ -3906,7 +4045,7 @@ int hci_register_dev(struct hci_dev *hdev) | |||
| 3906 | { | 4045 | { |
| 3907 | int id, error; | 4046 | int id, error; |
| 3908 | 4047 | ||
| 3909 | if (!hdev->open || !hdev->close) | 4048 | if (!hdev->open || !hdev->close || !hdev->send) |
| 3910 | return -EINVAL; | 4049 | return -EINVAL; |
| 3911 | 4050 | ||
| 3912 | /* Do not allow HCI_AMP devices to register at index 0, | 4051 | /* Do not allow HCI_AMP devices to register at index 0, |
| @@ -3991,6 +4130,12 @@ int hci_register_dev(struct hci_dev *hdev) | |||
| 3991 | list_add(&hdev->list, &hci_dev_list); | 4130 | list_add(&hdev->list, &hci_dev_list); |
| 3992 | write_unlock(&hci_dev_list_lock); | 4131 | write_unlock(&hci_dev_list_lock); |
| 3993 | 4132 | ||
| 4133 | /* Devices that are marked for raw-only usage are unconfigured | ||
| 4134 | * and should not be included in normal operation. | ||
| 4135 | */ | ||
| 4136 | if (test_bit(HCI_QUIRK_RAW_DEVICE, &hdev->quirks)) | ||
| 4137 | set_bit(HCI_UNCONFIGURED, &hdev->dev_flags); | ||
| 4138 | |||
| 3994 | hci_notify(hdev, HCI_DEV_REG); | 4139 | hci_notify(hdev, HCI_DEV_REG); |
| 3995 | hci_dev_hold(hdev); | 4140 | hci_dev_hold(hdev); |
| 3996 | 4141 | ||
| @@ -4033,7 +4178,8 @@ void hci_unregister_dev(struct hci_dev *hdev) | |||
| 4033 | cancel_work_sync(&hdev->power_on); | 4178 | cancel_work_sync(&hdev->power_on); |
| 4034 | 4179 | ||
| 4035 | if (!test_bit(HCI_INIT, &hdev->flags) && | 4180 | if (!test_bit(HCI_INIT, &hdev->flags) && |
| 4036 | !test_bit(HCI_SETUP, &hdev->dev_flags)) { | 4181 | !test_bit(HCI_SETUP, &hdev->dev_flags) && |
| 4182 | !test_bit(HCI_CONFIG, &hdev->dev_flags)) { | ||
| 4037 | hci_dev_lock(hdev); | 4183 | hci_dev_lock(hdev); |
| 4038 | mgmt_index_removed(hdev); | 4184 | mgmt_index_removed(hdev); |
| 4039 | hci_dev_unlock(hdev); | 4185 | hci_dev_unlock(hdev); |
| @@ -4061,15 +4207,15 @@ void hci_unregister_dev(struct hci_dev *hdev) | |||
| 4061 | destroy_workqueue(hdev->req_workqueue); | 4207 | destroy_workqueue(hdev->req_workqueue); |
| 4062 | 4208 | ||
| 4063 | hci_dev_lock(hdev); | 4209 | hci_dev_lock(hdev); |
| 4064 | hci_blacklist_clear(hdev); | 4210 | hci_bdaddr_list_clear(&hdev->blacklist); |
| 4211 | hci_bdaddr_list_clear(&hdev->whitelist); | ||
| 4065 | hci_uuids_clear(hdev); | 4212 | hci_uuids_clear(hdev); |
| 4066 | hci_link_keys_clear(hdev); | 4213 | hci_link_keys_clear(hdev); |
| 4067 | hci_smp_ltks_clear(hdev); | 4214 | hci_smp_ltks_clear(hdev); |
| 4068 | hci_smp_irks_clear(hdev); | 4215 | hci_smp_irks_clear(hdev); |
| 4069 | hci_remote_oob_data_clear(hdev); | 4216 | hci_remote_oob_data_clear(hdev); |
| 4070 | hci_white_list_clear(hdev); | 4217 | hci_bdaddr_list_clear(&hdev->le_white_list); |
| 4071 | hci_conn_params_clear(hdev); | 4218 | hci_conn_params_clear_all(hdev); |
| 4072 | hci_pend_le_conns_clear(hdev); | ||
| 4073 | hci_dev_unlock(hdev); | 4219 | hci_dev_unlock(hdev); |
| 4074 | 4220 | ||
| 4075 | hci_dev_put(hdev); | 4221 | hci_dev_put(hdev); |
| @@ -4307,6 +4453,8 @@ EXPORT_SYMBOL(hci_unregister_cb); | |||
| 4307 | 4453 | ||
| 4308 | static void hci_send_frame(struct hci_dev *hdev, struct sk_buff *skb) | 4454 | static void hci_send_frame(struct hci_dev *hdev, struct sk_buff *skb) |
| 4309 | { | 4455 | { |
| 4456 | int err; | ||
| 4457 | |||
| 4310 | BT_DBG("%s type %d len %d", hdev->name, bt_cb(skb)->pkt_type, skb->len); | 4458 | BT_DBG("%s type %d len %d", hdev->name, bt_cb(skb)->pkt_type, skb->len); |
| 4311 | 4459 | ||
| 4312 | /* Time stamp */ | 4460 | /* Time stamp */ |
| @@ -4323,8 +4471,11 @@ static void hci_send_frame(struct hci_dev *hdev, struct sk_buff *skb) | |||
| 4323 | /* Get rid of skb owner, prior to sending to the driver. */ | 4471 | /* Get rid of skb owner, prior to sending to the driver. */ |
| 4324 | skb_orphan(skb); | 4472 | skb_orphan(skb); |
| 4325 | 4473 | ||
| 4326 | if (hdev->send(hdev, skb) < 0) | 4474 | err = hdev->send(hdev, skb); |
| 4327 | BT_ERR("%s sending frame failed", hdev->name); | 4475 | if (err < 0) { |
| 4476 | BT_ERR("%s sending frame failed (%d)", hdev->name, err); | ||
| 4477 | kfree_skb(skb); | ||
| 4478 | } | ||
| 4328 | } | 4479 | } |
| 4329 | 4480 | ||
| 4330 | void hci_req_init(struct hci_request *req, struct hci_dev *hdev) | 4481 | void hci_req_init(struct hci_request *req, struct hci_dev *hdev) |
| @@ -4366,6 +4517,11 @@ int hci_req_run(struct hci_request *req, hci_req_complete_t complete) | |||
| 4366 | return 0; | 4517 | return 0; |
| 4367 | } | 4518 | } |
| 4368 | 4519 | ||
| 4520 | bool hci_req_pending(struct hci_dev *hdev) | ||
| 4521 | { | ||
| 4522 | return (hdev->req_status == HCI_REQ_PEND); | ||
| 4523 | } | ||
| 4524 | |||
| 4369 | static struct sk_buff *hci_prepare_cmd(struct hci_dev *hdev, u16 opcode, | 4525 | static struct sk_buff *hci_prepare_cmd(struct hci_dev *hdev, u16 opcode, |
| 4370 | u32 plen, const void *param) | 4526 | u32 plen, const void *param) |
| 4371 | { | 4527 | { |
| @@ -4798,7 +4954,7 @@ static inline int __get_blocks(struct hci_dev *hdev, struct sk_buff *skb) | |||
| 4798 | 4954 | ||
| 4799 | static void __check_timeout(struct hci_dev *hdev, unsigned int cnt) | 4955 | static void __check_timeout(struct hci_dev *hdev, unsigned int cnt) |
| 4800 | { | 4956 | { |
| 4801 | if (!test_bit(HCI_RAW, &hdev->flags)) { | 4957 | if (!test_bit(HCI_UNCONFIGURED, &hdev->dev_flags)) { |
| 4802 | /* ACL tx timeout must be longer than maximum | 4958 | /* ACL tx timeout must be longer than maximum |
| 4803 | * link supervision timeout (40.9 seconds) */ | 4959 | * link supervision timeout (40.9 seconds) */ |
| 4804 | if (!cnt && time_after(jiffies, hdev->acl_last_tx + | 4960 | if (!cnt && time_after(jiffies, hdev->acl_last_tx + |
| @@ -4981,7 +5137,7 @@ static void hci_sched_le(struct hci_dev *hdev) | |||
| 4981 | if (!hci_conn_num(hdev, LE_LINK)) | 5137 | if (!hci_conn_num(hdev, LE_LINK)) |
| 4982 | return; | 5138 | return; |
| 4983 | 5139 | ||
| 4984 | if (!test_bit(HCI_RAW, &hdev->flags)) { | 5140 | if (!test_bit(HCI_UNCONFIGURED, &hdev->dev_flags)) { |
| 4985 | /* LE tx timeout must be longer than maximum | 5141 | /* LE tx timeout must be longer than maximum |
| 4986 | * link supervision timeout (40.9 seconds) */ | 5142 | * link supervision timeout (40.9 seconds) */ |
| 4987 | if (!hdev->le_cnt && hdev->le_pkts && | 5143 | if (!hdev->le_cnt && hdev->le_pkts && |
| @@ -5226,8 +5382,7 @@ static void hci_rx_work(struct work_struct *work) | |||
| 5226 | hci_send_to_sock(hdev, skb); | 5382 | hci_send_to_sock(hdev, skb); |
| 5227 | } | 5383 | } |
| 5228 | 5384 | ||
| 5229 | if (test_bit(HCI_RAW, &hdev->flags) || | 5385 | if (test_bit(HCI_USER_CHANNEL, &hdev->dev_flags)) { |
| 5230 | test_bit(HCI_USER_CHANNEL, &hdev->dev_flags)) { | ||
| 5231 | kfree_skb(skb); | 5386 | kfree_skb(skb); |
| 5232 | continue; | 5387 | continue; |
| 5233 | } | 5388 | } |
| @@ -5287,10 +5442,10 @@ static void hci_cmd_work(struct work_struct *work) | |||
| 5287 | atomic_dec(&hdev->cmd_cnt); | 5442 | atomic_dec(&hdev->cmd_cnt); |
| 5288 | hci_send_frame(hdev, skb); | 5443 | hci_send_frame(hdev, skb); |
| 5289 | if (test_bit(HCI_RESET, &hdev->flags)) | 5444 | if (test_bit(HCI_RESET, &hdev->flags)) |
| 5290 | del_timer(&hdev->cmd_timer); | 5445 | cancel_delayed_work(&hdev->cmd_timer); |
| 5291 | else | 5446 | else |
| 5292 | mod_timer(&hdev->cmd_timer, | 5447 | schedule_delayed_work(&hdev->cmd_timer, |
| 5293 | jiffies + HCI_CMD_TIMEOUT); | 5448 | HCI_CMD_TIMEOUT); |
| 5294 | } else { | 5449 | } else { |
| 5295 | skb_queue_head(&hdev->cmd_q, skb); | 5450 | skb_queue_head(&hdev->cmd_q, skb); |
| 5296 | queue_work(hdev->workqueue, &hdev->cmd_work); | 5451 | queue_work(hdev->workqueue, &hdev->cmd_work); |
| @@ -5307,26 +5462,135 @@ void hci_req_add_le_scan_disable(struct hci_request *req) | |||
| 5307 | hci_req_add(req, HCI_OP_LE_SET_SCAN_ENABLE, sizeof(cp), &cp); | 5462 | hci_req_add(req, HCI_OP_LE_SET_SCAN_ENABLE, sizeof(cp), &cp); |
| 5308 | } | 5463 | } |
| 5309 | 5464 | ||
| 5465 | static void add_to_white_list(struct hci_request *req, | ||
| 5466 | struct hci_conn_params *params) | ||
| 5467 | { | ||
| 5468 | struct hci_cp_le_add_to_white_list cp; | ||
| 5469 | |||
| 5470 | cp.bdaddr_type = params->addr_type; | ||
| 5471 | bacpy(&cp.bdaddr, ¶ms->addr); | ||
| 5472 | |||
| 5473 | hci_req_add(req, HCI_OP_LE_ADD_TO_WHITE_LIST, sizeof(cp), &cp); | ||
| 5474 | } | ||
| 5475 | |||
| 5476 | static u8 update_white_list(struct hci_request *req) | ||
| 5477 | { | ||
| 5478 | struct hci_dev *hdev = req->hdev; | ||
| 5479 | struct hci_conn_params *params; | ||
| 5480 | struct bdaddr_list *b; | ||
| 5481 | uint8_t white_list_entries = 0; | ||
| 5482 | |||
| 5483 | /* Go through the current white list programmed into the | ||
| 5484 | * controller one by one and check if that address is still | ||
| 5485 | * in the list of pending connections or list of devices to | ||
| 5486 | * report. If not present in either list, then queue the | ||
| 5487 | * command to remove it from the controller. | ||
| 5488 | */ | ||
| 5489 | list_for_each_entry(b, &hdev->le_white_list, list) { | ||
| 5490 | struct hci_cp_le_del_from_white_list cp; | ||
| 5491 | |||
| 5492 | if (hci_pend_le_action_lookup(&hdev->pend_le_conns, | ||
| 5493 | &b->bdaddr, b->bdaddr_type) || | ||
| 5494 | hci_pend_le_action_lookup(&hdev->pend_le_reports, | ||
| 5495 | &b->bdaddr, b->bdaddr_type)) { | ||
| 5496 | white_list_entries++; | ||
| 5497 | continue; | ||
| 5498 | } | ||
| 5499 | |||
| 5500 | cp.bdaddr_type = b->bdaddr_type; | ||
| 5501 | bacpy(&cp.bdaddr, &b->bdaddr); | ||
| 5502 | |||
| 5503 | hci_req_add(req, HCI_OP_LE_DEL_FROM_WHITE_LIST, | ||
| 5504 | sizeof(cp), &cp); | ||
| 5505 | } | ||
| 5506 | |||
| 5507 | /* Since all no longer valid white list entries have been | ||
| 5508 | * removed, walk through the list of pending connections | ||
| 5509 | * and ensure that any new device gets programmed into | ||
| 5510 | * the controller. | ||
| 5511 | * | ||
| 5512 | * If the list of the devices is larger than the list of | ||
| 5513 | * available white list entries in the controller, then | ||
| 5514 | * just abort and return filer policy value to not use the | ||
| 5515 | * white list. | ||
| 5516 | */ | ||
| 5517 | list_for_each_entry(params, &hdev->pend_le_conns, action) { | ||
| 5518 | if (hci_bdaddr_list_lookup(&hdev->le_white_list, | ||
| 5519 | ¶ms->addr, params->addr_type)) | ||
| 5520 | continue; | ||
| 5521 | |||
| 5522 | if (white_list_entries >= hdev->le_white_list_size) { | ||
| 5523 | /* Select filter policy to accept all advertising */ | ||
| 5524 | return 0x00; | ||
| 5525 | } | ||
| 5526 | |||
| 5527 | if (hci_find_irk_by_addr(hdev, ¶ms->addr, | ||
| 5528 | params->addr_type)) { | ||
| 5529 | /* White list can not be used with RPAs */ | ||
| 5530 | return 0x00; | ||
| 5531 | } | ||
| 5532 | |||
| 5533 | white_list_entries++; | ||
| 5534 | add_to_white_list(req, params); | ||
| 5535 | } | ||
| 5536 | |||
| 5537 | /* After adding all new pending connections, walk through | ||
| 5538 | * the list of pending reports and also add these to the | ||
| 5539 | * white list if there is still space. | ||
| 5540 | */ | ||
| 5541 | list_for_each_entry(params, &hdev->pend_le_reports, action) { | ||
| 5542 | if (hci_bdaddr_list_lookup(&hdev->le_white_list, | ||
| 5543 | ¶ms->addr, params->addr_type)) | ||
| 5544 | continue; | ||
| 5545 | |||
| 5546 | if (white_list_entries >= hdev->le_white_list_size) { | ||
| 5547 | /* Select filter policy to accept all advertising */ | ||
| 5548 | return 0x00; | ||
| 5549 | } | ||
| 5550 | |||
| 5551 | if (hci_find_irk_by_addr(hdev, ¶ms->addr, | ||
| 5552 | params->addr_type)) { | ||
| 5553 | /* White list can not be used with RPAs */ | ||
| 5554 | return 0x00; | ||
| 5555 | } | ||
| 5556 | |||
| 5557 | white_list_entries++; | ||
| 5558 | add_to_white_list(req, params); | ||
| 5559 | } | ||
| 5560 | |||
| 5561 | /* Select filter policy to use white list */ | ||
| 5562 | return 0x01; | ||
| 5563 | } | ||
| 5564 | |||
| 5310 | void hci_req_add_le_passive_scan(struct hci_request *req) | 5565 | void hci_req_add_le_passive_scan(struct hci_request *req) |
| 5311 | { | 5566 | { |
| 5312 | struct hci_cp_le_set_scan_param param_cp; | 5567 | struct hci_cp_le_set_scan_param param_cp; |
| 5313 | struct hci_cp_le_set_scan_enable enable_cp; | 5568 | struct hci_cp_le_set_scan_enable enable_cp; |
| 5314 | struct hci_dev *hdev = req->hdev; | 5569 | struct hci_dev *hdev = req->hdev; |
| 5315 | u8 own_addr_type; | 5570 | u8 own_addr_type; |
| 5571 | u8 filter_policy; | ||
| 5316 | 5572 | ||
| 5317 | /* Set require_privacy to true to avoid identification from | 5573 | /* Set require_privacy to false since no SCAN_REQ are send |
| 5318 | * unknown peer devices. Since this is passive scanning, no | 5574 | * during passive scanning. Not using an unresolvable address |
| 5319 | * SCAN_REQ using the local identity should be sent. Mandating | 5575 | * here is important so that peer devices using direct |
| 5320 | * privacy is just an extra precaution. | 5576 | * advertising with our address will be correctly reported |
| 5577 | * by the controller. | ||
| 5321 | */ | 5578 | */ |
| 5322 | if (hci_update_random_address(req, true, &own_addr_type)) | 5579 | if (hci_update_random_address(req, false, &own_addr_type)) |
| 5323 | return; | 5580 | return; |
| 5324 | 5581 | ||
| 5582 | /* Adding or removing entries from the white list must | ||
| 5583 | * happen before enabling scanning. The controller does | ||
| 5584 | * not allow white list modification while scanning. | ||
| 5585 | */ | ||
| 5586 | filter_policy = update_white_list(req); | ||
| 5587 | |||
| 5325 | memset(¶m_cp, 0, sizeof(param_cp)); | 5588 | memset(¶m_cp, 0, sizeof(param_cp)); |
| 5326 | param_cp.type = LE_SCAN_PASSIVE; | 5589 | param_cp.type = LE_SCAN_PASSIVE; |
| 5327 | param_cp.interval = cpu_to_le16(hdev->le_scan_interval); | 5590 | param_cp.interval = cpu_to_le16(hdev->le_scan_interval); |
| 5328 | param_cp.window = cpu_to_le16(hdev->le_scan_window); | 5591 | param_cp.window = cpu_to_le16(hdev->le_scan_window); |
| 5329 | param_cp.own_address_type = own_addr_type; | 5592 | param_cp.own_address_type = own_addr_type; |
| 5593 | param_cp.filter_policy = filter_policy; | ||
| 5330 | hci_req_add(req, HCI_OP_LE_SET_SCAN_PARAM, sizeof(param_cp), | 5594 | hci_req_add(req, HCI_OP_LE_SET_SCAN_PARAM, sizeof(param_cp), |
| 5331 | ¶m_cp); | 5595 | ¶m_cp); |
| 5332 | 5596 | ||
| @@ -5356,11 +5620,29 @@ void hci_update_background_scan(struct hci_dev *hdev) | |||
| 5356 | struct hci_conn *conn; | 5620 | struct hci_conn *conn; |
| 5357 | int err; | 5621 | int err; |
| 5358 | 5622 | ||
| 5623 | if (!test_bit(HCI_UP, &hdev->flags) || | ||
| 5624 | test_bit(HCI_INIT, &hdev->flags) || | ||
| 5625 | test_bit(HCI_SETUP, &hdev->dev_flags) || | ||
| 5626 | test_bit(HCI_CONFIG, &hdev->dev_flags) || | ||
| 5627 | test_bit(HCI_AUTO_OFF, &hdev->dev_flags) || | ||
| 5628 | test_bit(HCI_UNREGISTER, &hdev->dev_flags)) | ||
| 5629 | return; | ||
| 5630 | |||
| 5631 | /* No point in doing scanning if LE support hasn't been enabled */ | ||
| 5632 | if (!test_bit(HCI_LE_ENABLED, &hdev->dev_flags)) | ||
| 5633 | return; | ||
| 5634 | |||
| 5635 | /* If discovery is active don't interfere with it */ | ||
| 5636 | if (hdev->discovery.state != DISCOVERY_STOPPED) | ||
| 5637 | return; | ||
| 5638 | |||
| 5359 | hci_req_init(&req, hdev); | 5639 | hci_req_init(&req, hdev); |
| 5360 | 5640 | ||
| 5361 | if (list_empty(&hdev->pend_le_conns)) { | 5641 | if (list_empty(&hdev->pend_le_conns) && |
| 5362 | /* If there is no pending LE connections, we should stop | 5642 | list_empty(&hdev->pend_le_reports)) { |
| 5363 | * the background scanning. | 5643 | /* If there is no pending LE connections or devices |
| 5644 | * to be scanned for, we should stop the background | ||
| 5645 | * scanning. | ||
| 5364 | */ | 5646 | */ |
| 5365 | 5647 | ||
| 5366 | /* If controller is not scanning we are done. */ | 5648 | /* If controller is not scanning we are done. */ |
diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c index 640c54ec1bd2..be35598984d9 100644 --- a/net/bluetooth/hci_event.c +++ b/net/bluetooth/hci_event.c | |||
| @@ -32,6 +32,7 @@ | |||
| 32 | 32 | ||
| 33 | #include "a2mp.h" | 33 | #include "a2mp.h" |
| 34 | #include "amp.h" | 34 | #include "amp.h" |
| 35 | #include "smp.h" | ||
| 35 | 36 | ||
| 36 | /* Handle HCI Event packets */ | 37 | /* Handle HCI Event packets */ |
| 37 | 38 | ||
| @@ -100,12 +101,8 @@ static void hci_cc_role_discovery(struct hci_dev *hdev, struct sk_buff *skb) | |||
| 100 | hci_dev_lock(hdev); | 101 | hci_dev_lock(hdev); |
| 101 | 102 | ||
| 102 | conn = hci_conn_hash_lookup_handle(hdev, __le16_to_cpu(rp->handle)); | 103 | conn = hci_conn_hash_lookup_handle(hdev, __le16_to_cpu(rp->handle)); |
| 103 | if (conn) { | 104 | if (conn) |
| 104 | if (rp->role) | 105 | conn->role = rp->role; |
| 105 | conn->link_mode &= ~HCI_LM_MASTER; | ||
| 106 | else | ||
| 107 | conn->link_mode |= HCI_LM_MASTER; | ||
| 108 | } | ||
| 109 | 106 | ||
| 110 | hci_dev_unlock(hdev); | 107 | hci_dev_unlock(hdev); |
| 111 | } | 108 | } |
| @@ -174,12 +171,14 @@ static void hci_cc_write_def_link_policy(struct hci_dev *hdev, | |||
| 174 | 171 | ||
| 175 | BT_DBG("%s status 0x%2.2x", hdev->name, status); | 172 | BT_DBG("%s status 0x%2.2x", hdev->name, status); |
| 176 | 173 | ||
| 174 | if (status) | ||
| 175 | return; | ||
| 176 | |||
| 177 | sent = hci_sent_cmd_data(hdev, HCI_OP_WRITE_DEF_LINK_POLICY); | 177 | sent = hci_sent_cmd_data(hdev, HCI_OP_WRITE_DEF_LINK_POLICY); |
| 178 | if (!sent) | 178 | if (!sent) |
| 179 | return; | 179 | return; |
| 180 | 180 | ||
| 181 | if (!status) | 181 | hdev->link_policy = get_unaligned_le16(sent); |
| 182 | hdev->link_policy = get_unaligned_le16(sent); | ||
| 183 | } | 182 | } |
| 184 | 183 | ||
| 185 | static void hci_cc_reset(struct hci_dev *hdev, struct sk_buff *skb) | 184 | static void hci_cc_reset(struct hci_dev *hdev, struct sk_buff *skb) |
| @@ -269,28 +268,30 @@ static void hci_cc_write_auth_enable(struct hci_dev *hdev, struct sk_buff *skb) | |||
| 269 | static void hci_cc_write_encrypt_mode(struct hci_dev *hdev, struct sk_buff *skb) | 268 | static void hci_cc_write_encrypt_mode(struct hci_dev *hdev, struct sk_buff *skb) |
| 270 | { | 269 | { |
| 271 | __u8 status = *((__u8 *) skb->data); | 270 | __u8 status = *((__u8 *) skb->data); |
| 271 | __u8 param; | ||
| 272 | void *sent; | 272 | void *sent; |
| 273 | 273 | ||
| 274 | BT_DBG("%s status 0x%2.2x", hdev->name, status); | 274 | BT_DBG("%s status 0x%2.2x", hdev->name, status); |
| 275 | 275 | ||
| 276 | if (status) | ||
| 277 | return; | ||
| 278 | |||
| 276 | sent = hci_sent_cmd_data(hdev, HCI_OP_WRITE_ENCRYPT_MODE); | 279 | sent = hci_sent_cmd_data(hdev, HCI_OP_WRITE_ENCRYPT_MODE); |
| 277 | if (!sent) | 280 | if (!sent) |
| 278 | return; | 281 | return; |
| 279 | 282 | ||
| 280 | if (!status) { | 283 | param = *((__u8 *) sent); |
| 281 | __u8 param = *((__u8 *) sent); | ||
| 282 | 284 | ||
| 283 | if (param) | 285 | if (param) |
| 284 | set_bit(HCI_ENCRYPT, &hdev->flags); | 286 | set_bit(HCI_ENCRYPT, &hdev->flags); |
| 285 | else | 287 | else |
| 286 | clear_bit(HCI_ENCRYPT, &hdev->flags); | 288 | clear_bit(HCI_ENCRYPT, &hdev->flags); |
| 287 | } | ||
| 288 | } | 289 | } |
| 289 | 290 | ||
| 290 | static void hci_cc_write_scan_enable(struct hci_dev *hdev, struct sk_buff *skb) | 291 | static void hci_cc_write_scan_enable(struct hci_dev *hdev, struct sk_buff *skb) |
| 291 | { | 292 | { |
| 292 | __u8 param, status = *((__u8 *) skb->data); | 293 | __u8 status = *((__u8 *) skb->data); |
| 293 | int old_pscan, old_iscan; | 294 | __u8 param; |
| 294 | void *sent; | 295 | void *sent; |
| 295 | 296 | ||
| 296 | BT_DBG("%s status 0x%2.2x", hdev->name, status); | 297 | BT_DBG("%s status 0x%2.2x", hdev->name, status); |
| @@ -304,32 +305,19 @@ static void hci_cc_write_scan_enable(struct hci_dev *hdev, struct sk_buff *skb) | |||
| 304 | hci_dev_lock(hdev); | 305 | hci_dev_lock(hdev); |
| 305 | 306 | ||
| 306 | if (status) { | 307 | if (status) { |
| 307 | mgmt_write_scan_failed(hdev, param, status); | ||
| 308 | hdev->discov_timeout = 0; | 308 | hdev->discov_timeout = 0; |
| 309 | goto done; | 309 | goto done; |
| 310 | } | 310 | } |
| 311 | 311 | ||
| 312 | /* We need to ensure that we set this back on if someone changed | 312 | if (param & SCAN_INQUIRY) |
| 313 | * the scan mode through a raw HCI socket. | ||
| 314 | */ | ||
| 315 | set_bit(HCI_BREDR_ENABLED, &hdev->dev_flags); | ||
| 316 | |||
| 317 | old_pscan = test_and_clear_bit(HCI_PSCAN, &hdev->flags); | ||
| 318 | old_iscan = test_and_clear_bit(HCI_ISCAN, &hdev->flags); | ||
| 319 | |||
| 320 | if (param & SCAN_INQUIRY) { | ||
| 321 | set_bit(HCI_ISCAN, &hdev->flags); | 313 | set_bit(HCI_ISCAN, &hdev->flags); |
| 322 | if (!old_iscan) | 314 | else |
| 323 | mgmt_discoverable(hdev, 1); | 315 | clear_bit(HCI_ISCAN, &hdev->flags); |
| 324 | } else if (old_iscan) | ||
| 325 | mgmt_discoverable(hdev, 0); | ||
| 326 | 316 | ||
| 327 | if (param & SCAN_PAGE) { | 317 | if (param & SCAN_PAGE) |
| 328 | set_bit(HCI_PSCAN, &hdev->flags); | 318 | set_bit(HCI_PSCAN, &hdev->flags); |
| 329 | if (!old_pscan) | 319 | else |
| 330 | mgmt_connectable(hdev, 1); | 320 | clear_bit(HCI_PSCAN, &hdev->flags); |
| 331 | } else if (old_pscan) | ||
| 332 | mgmt_connectable(hdev, 0); | ||
| 333 | 321 | ||
| 334 | done: | 322 | done: |
| 335 | hci_dev_unlock(hdev); | 323 | hci_dev_unlock(hdev); |
| @@ -601,8 +589,10 @@ static void hci_cc_read_flow_control_mode(struct hci_dev *hdev, | |||
| 601 | 589 | ||
| 602 | BT_DBG("%s status 0x%2.2x", hdev->name, rp->status); | 590 | BT_DBG("%s status 0x%2.2x", hdev->name, rp->status); |
| 603 | 591 | ||
| 604 | if (!rp->status) | 592 | if (rp->status) |
| 605 | hdev->flow_ctl_mode = rp->mode; | 593 | return; |
| 594 | |||
| 595 | hdev->flow_ctl_mode = rp->mode; | ||
| 606 | } | 596 | } |
| 607 | 597 | ||
| 608 | static void hci_cc_read_buffer_size(struct hci_dev *hdev, struct sk_buff *skb) | 598 | static void hci_cc_read_buffer_size(struct hci_dev *hdev, struct sk_buff *skb) |
| @@ -637,8 +627,14 @@ static void hci_cc_read_bd_addr(struct hci_dev *hdev, struct sk_buff *skb) | |||
| 637 | 627 | ||
| 638 | BT_DBG("%s status 0x%2.2x", hdev->name, rp->status); | 628 | BT_DBG("%s status 0x%2.2x", hdev->name, rp->status); |
| 639 | 629 | ||
| 640 | if (!rp->status) | 630 | if (rp->status) |
| 631 | return; | ||
| 632 | |||
| 633 | if (test_bit(HCI_INIT, &hdev->flags)) | ||
| 641 | bacpy(&hdev->bdaddr, &rp->bdaddr); | 634 | bacpy(&hdev->bdaddr, &rp->bdaddr); |
| 635 | |||
| 636 | if (test_bit(HCI_SETUP, &hdev->dev_flags)) | ||
| 637 | bacpy(&hdev->setup_addr, &rp->bdaddr); | ||
| 642 | } | 638 | } |
| 643 | 639 | ||
| 644 | static void hci_cc_read_page_scan_activity(struct hci_dev *hdev, | 640 | static void hci_cc_read_page_scan_activity(struct hci_dev *hdev, |
| @@ -648,7 +644,10 @@ static void hci_cc_read_page_scan_activity(struct hci_dev *hdev, | |||
| 648 | 644 | ||
| 649 | BT_DBG("%s status 0x%2.2x", hdev->name, rp->status); | 645 | BT_DBG("%s status 0x%2.2x", hdev->name, rp->status); |
| 650 | 646 | ||
| 651 | if (test_bit(HCI_INIT, &hdev->flags) && !rp->status) { | 647 | if (rp->status) |
| 648 | return; | ||
| 649 | |||
| 650 | if (test_bit(HCI_INIT, &hdev->flags)) { | ||
| 652 | hdev->page_scan_interval = __le16_to_cpu(rp->interval); | 651 | hdev->page_scan_interval = __le16_to_cpu(rp->interval); |
| 653 | hdev->page_scan_window = __le16_to_cpu(rp->window); | 652 | hdev->page_scan_window = __le16_to_cpu(rp->window); |
| 654 | } | 653 | } |
| @@ -680,7 +679,10 @@ static void hci_cc_read_page_scan_type(struct hci_dev *hdev, | |||
| 680 | 679 | ||
| 681 | BT_DBG("%s status 0x%2.2x", hdev->name, rp->status); | 680 | BT_DBG("%s status 0x%2.2x", hdev->name, rp->status); |
| 682 | 681 | ||
| 683 | if (test_bit(HCI_INIT, &hdev->flags) && !rp->status) | 682 | if (rp->status) |
| 683 | return; | ||
| 684 | |||
| 685 | if (test_bit(HCI_INIT, &hdev->flags)) | ||
| 684 | hdev->page_scan_type = rp->type; | 686 | hdev->page_scan_type = rp->type; |
| 685 | } | 687 | } |
| 686 | 688 | ||
| @@ -720,6 +722,41 @@ static void hci_cc_read_data_block_size(struct hci_dev *hdev, | |||
| 720 | hdev->block_cnt, hdev->block_len); | 722 | hdev->block_cnt, hdev->block_len); |
| 721 | } | 723 | } |
| 722 | 724 | ||
| 725 | static void hci_cc_read_clock(struct hci_dev *hdev, struct sk_buff *skb) | ||
| 726 | { | ||
| 727 | struct hci_rp_read_clock *rp = (void *) skb->data; | ||
| 728 | struct hci_cp_read_clock *cp; | ||
| 729 | struct hci_conn *conn; | ||
| 730 | |||
| 731 | BT_DBG("%s", hdev->name); | ||
| 732 | |||
| 733 | if (skb->len < sizeof(*rp)) | ||
| 734 | return; | ||
| 735 | |||
| 736 | if (rp->status) | ||
| 737 | return; | ||
| 738 | |||
| 739 | hci_dev_lock(hdev); | ||
| 740 | |||
| 741 | cp = hci_sent_cmd_data(hdev, HCI_OP_READ_CLOCK); | ||
| 742 | if (!cp) | ||
| 743 | goto unlock; | ||
| 744 | |||
| 745 | if (cp->which == 0x00) { | ||
| 746 | hdev->clock = le32_to_cpu(rp->clock); | ||
| 747 | goto unlock; | ||
| 748 | } | ||
| 749 | |||
| 750 | conn = hci_conn_hash_lookup_handle(hdev, __le16_to_cpu(rp->handle)); | ||
| 751 | if (conn) { | ||
| 752 | conn->clock = le32_to_cpu(rp->clock); | ||
| 753 | conn->clock_accuracy = le16_to_cpu(rp->accuracy); | ||
| 754 | } | ||
| 755 | |||
| 756 | unlock: | ||
| 757 | hci_dev_unlock(hdev); | ||
| 758 | } | ||
| 759 | |||
| 723 | static void hci_cc_read_local_amp_info(struct hci_dev *hdev, | 760 | static void hci_cc_read_local_amp_info(struct hci_dev *hdev, |
| 724 | struct sk_buff *skb) | 761 | struct sk_buff *skb) |
| 725 | { | 762 | { |
| @@ -789,8 +826,10 @@ static void hci_cc_read_inq_rsp_tx_power(struct hci_dev *hdev, | |||
| 789 | 826 | ||
| 790 | BT_DBG("%s status 0x%2.2x", hdev->name, rp->status); | 827 | BT_DBG("%s status 0x%2.2x", hdev->name, rp->status); |
| 791 | 828 | ||
| 792 | if (!rp->status) | 829 | if (rp->status) |
| 793 | hdev->inq_tx_power = rp->tx_power; | 830 | return; |
| 831 | |||
| 832 | hdev->inq_tx_power = rp->tx_power; | ||
| 794 | } | 833 | } |
| 795 | 834 | ||
| 796 | static void hci_cc_pin_code_reply(struct hci_dev *hdev, struct sk_buff *skb) | 835 | static void hci_cc_pin_code_reply(struct hci_dev *hdev, struct sk_buff *skb) |
| @@ -861,8 +900,10 @@ static void hci_cc_le_read_local_features(struct hci_dev *hdev, | |||
| 861 | 900 | ||
| 862 | BT_DBG("%s status 0x%2.2x", hdev->name, rp->status); | 901 | BT_DBG("%s status 0x%2.2x", hdev->name, rp->status); |
| 863 | 902 | ||
| 864 | if (!rp->status) | 903 | if (rp->status) |
| 865 | memcpy(hdev->le_features, rp->features, 8); | 904 | return; |
| 905 | |||
| 906 | memcpy(hdev->le_features, rp->features, 8); | ||
| 866 | } | 907 | } |
| 867 | 908 | ||
| 868 | static void hci_cc_le_read_adv_tx_power(struct hci_dev *hdev, | 909 | static void hci_cc_le_read_adv_tx_power(struct hci_dev *hdev, |
| @@ -872,8 +913,10 @@ static void hci_cc_le_read_adv_tx_power(struct hci_dev *hdev, | |||
| 872 | 913 | ||
| 873 | BT_DBG("%s status 0x%2.2x", hdev->name, rp->status); | 914 | BT_DBG("%s status 0x%2.2x", hdev->name, rp->status); |
| 874 | 915 | ||
| 875 | if (!rp->status) | 916 | if (rp->status) |
| 876 | hdev->adv_tx_power = rp->tx_power; | 917 | return; |
| 918 | |||
| 919 | hdev->adv_tx_power = rp->tx_power; | ||
| 877 | } | 920 | } |
| 878 | 921 | ||
| 879 | static void hci_cc_user_confirm_reply(struct hci_dev *hdev, struct sk_buff *skb) | 922 | static void hci_cc_user_confirm_reply(struct hci_dev *hdev, struct sk_buff *skb) |
| @@ -973,14 +1016,16 @@ static void hci_cc_le_set_random_addr(struct hci_dev *hdev, struct sk_buff *skb) | |||
| 973 | 1016 | ||
| 974 | BT_DBG("%s status 0x%2.2x", hdev->name, status); | 1017 | BT_DBG("%s status 0x%2.2x", hdev->name, status); |
| 975 | 1018 | ||
| 1019 | if (status) | ||
| 1020 | return; | ||
| 1021 | |||
| 976 | sent = hci_sent_cmd_data(hdev, HCI_OP_LE_SET_RANDOM_ADDR); | 1022 | sent = hci_sent_cmd_data(hdev, HCI_OP_LE_SET_RANDOM_ADDR); |
| 977 | if (!sent) | 1023 | if (!sent) |
| 978 | return; | 1024 | return; |
| 979 | 1025 | ||
| 980 | hci_dev_lock(hdev); | 1026 | hci_dev_lock(hdev); |
| 981 | 1027 | ||
| 982 | if (!status) | 1028 | bacpy(&hdev->random_addr, sent); |
| 983 | bacpy(&hdev->random_addr, sent); | ||
| 984 | 1029 | ||
| 985 | hci_dev_unlock(hdev); | 1030 | hci_dev_unlock(hdev); |
| 986 | } | 1031 | } |
| @@ -991,11 +1036,11 @@ static void hci_cc_le_set_adv_enable(struct hci_dev *hdev, struct sk_buff *skb) | |||
| 991 | 1036 | ||
| 992 | BT_DBG("%s status 0x%2.2x", hdev->name, status); | 1037 | BT_DBG("%s status 0x%2.2x", hdev->name, status); |
| 993 | 1038 | ||
| 994 | sent = hci_sent_cmd_data(hdev, HCI_OP_LE_SET_ADV_ENABLE); | 1039 | if (status) |
| 995 | if (!sent) | ||
| 996 | return; | 1040 | return; |
| 997 | 1041 | ||
| 998 | if (status) | 1042 | sent = hci_sent_cmd_data(hdev, HCI_OP_LE_SET_ADV_ENABLE); |
| 1043 | if (!sent) | ||
| 999 | return; | 1044 | return; |
| 1000 | 1045 | ||
| 1001 | hci_dev_lock(hdev); | 1046 | hci_dev_lock(hdev); |
| @@ -1006,15 +1051,17 @@ static void hci_cc_le_set_adv_enable(struct hci_dev *hdev, struct sk_buff *skb) | |||
| 1006 | if (*sent) { | 1051 | if (*sent) { |
| 1007 | struct hci_conn *conn; | 1052 | struct hci_conn *conn; |
| 1008 | 1053 | ||
| 1054 | set_bit(HCI_LE_ADV, &hdev->dev_flags); | ||
| 1055 | |||
| 1009 | conn = hci_conn_hash_lookup_state(hdev, LE_LINK, BT_CONNECT); | 1056 | conn = hci_conn_hash_lookup_state(hdev, LE_LINK, BT_CONNECT); |
| 1010 | if (conn) | 1057 | if (conn) |
| 1011 | queue_delayed_work(hdev->workqueue, | 1058 | queue_delayed_work(hdev->workqueue, |
| 1012 | &conn->le_conn_timeout, | 1059 | &conn->le_conn_timeout, |
| 1013 | HCI_LE_CONN_TIMEOUT); | 1060 | conn->conn_timeout); |
| 1061 | } else { | ||
| 1062 | clear_bit(HCI_LE_ADV, &hdev->dev_flags); | ||
| 1014 | } | 1063 | } |
| 1015 | 1064 | ||
| 1016 | mgmt_advertising(hdev, *sent); | ||
| 1017 | |||
| 1018 | hci_dev_unlock(hdev); | 1065 | hci_dev_unlock(hdev); |
| 1019 | } | 1066 | } |
| 1020 | 1067 | ||
| @@ -1025,14 +1072,16 @@ static void hci_cc_le_set_scan_param(struct hci_dev *hdev, struct sk_buff *skb) | |||
| 1025 | 1072 | ||
| 1026 | BT_DBG("%s status 0x%2.2x", hdev->name, status); | 1073 | BT_DBG("%s status 0x%2.2x", hdev->name, status); |
| 1027 | 1074 | ||
| 1075 | if (status) | ||
| 1076 | return; | ||
| 1077 | |||
| 1028 | cp = hci_sent_cmd_data(hdev, HCI_OP_LE_SET_SCAN_PARAM); | 1078 | cp = hci_sent_cmd_data(hdev, HCI_OP_LE_SET_SCAN_PARAM); |
| 1029 | if (!cp) | 1079 | if (!cp) |
| 1030 | return; | 1080 | return; |
| 1031 | 1081 | ||
| 1032 | hci_dev_lock(hdev); | 1082 | hci_dev_lock(hdev); |
| 1033 | 1083 | ||
| 1034 | if (!status) | 1084 | hdev->le_scan_type = cp->type; |
| 1035 | hdev->le_scan_type = cp->type; | ||
| 1036 | 1085 | ||
| 1037 | hci_dev_unlock(hdev); | 1086 | hci_dev_unlock(hdev); |
| 1038 | } | 1087 | } |
| @@ -1053,13 +1102,15 @@ static void clear_pending_adv_report(struct hci_dev *hdev) | |||
| 1053 | } | 1102 | } |
| 1054 | 1103 | ||
| 1055 | static void store_pending_adv_report(struct hci_dev *hdev, bdaddr_t *bdaddr, | 1104 | static void store_pending_adv_report(struct hci_dev *hdev, bdaddr_t *bdaddr, |
| 1056 | u8 bdaddr_type, s8 rssi, u8 *data, u8 len) | 1105 | u8 bdaddr_type, s8 rssi, u32 flags, |
| 1106 | u8 *data, u8 len) | ||
| 1057 | { | 1107 | { |
| 1058 | struct discovery_state *d = &hdev->discovery; | 1108 | struct discovery_state *d = &hdev->discovery; |
| 1059 | 1109 | ||
| 1060 | bacpy(&d->last_adv_addr, bdaddr); | 1110 | bacpy(&d->last_adv_addr, bdaddr); |
| 1061 | d->last_adv_addr_type = bdaddr_type; | 1111 | d->last_adv_addr_type = bdaddr_type; |
| 1062 | d->last_adv_rssi = rssi; | 1112 | d->last_adv_rssi = rssi; |
| 1113 | d->last_adv_flags = flags; | ||
| 1063 | memcpy(d->last_adv_data, data, len); | 1114 | memcpy(d->last_adv_data, data, len); |
| 1064 | d->last_adv_data_len = len; | 1115 | d->last_adv_data_len = len; |
| 1065 | } | 1116 | } |
| @@ -1072,11 +1123,11 @@ static void hci_cc_le_set_scan_enable(struct hci_dev *hdev, | |||
| 1072 | 1123 | ||
| 1073 | BT_DBG("%s status 0x%2.2x", hdev->name, status); | 1124 | BT_DBG("%s status 0x%2.2x", hdev->name, status); |
| 1074 | 1125 | ||
| 1075 | cp = hci_sent_cmd_data(hdev, HCI_OP_LE_SET_SCAN_ENABLE); | 1126 | if (status) |
| 1076 | if (!cp) | ||
| 1077 | return; | 1127 | return; |
| 1078 | 1128 | ||
| 1079 | if (status) | 1129 | cp = hci_sent_cmd_data(hdev, HCI_OP_LE_SET_SCAN_ENABLE); |
| 1130 | if (!cp) | ||
| 1080 | return; | 1131 | return; |
| 1081 | 1132 | ||
| 1082 | switch (cp->enable) { | 1133 | switch (cp->enable) { |
| @@ -1096,7 +1147,7 @@ static void hci_cc_le_set_scan_enable(struct hci_dev *hdev, | |||
| 1096 | 1147 | ||
| 1097 | mgmt_device_found(hdev, &d->last_adv_addr, LE_LINK, | 1148 | mgmt_device_found(hdev, &d->last_adv_addr, LE_LINK, |
| 1098 | d->last_adv_addr_type, NULL, | 1149 | d->last_adv_addr_type, NULL, |
| 1099 | d->last_adv_rssi, 0, 1, | 1150 | d->last_adv_rssi, d->last_adv_flags, |
| 1100 | d->last_adv_data, | 1151 | d->last_adv_data, |
| 1101 | d->last_adv_data_len, NULL, 0); | 1152 | d->last_adv_data_len, NULL, 0); |
| 1102 | } | 1153 | } |
| @@ -1107,13 +1158,21 @@ static void hci_cc_le_set_scan_enable(struct hci_dev *hdev, | |||
| 1107 | cancel_delayed_work(&hdev->le_scan_disable); | 1158 | cancel_delayed_work(&hdev->le_scan_disable); |
| 1108 | 1159 | ||
| 1109 | clear_bit(HCI_LE_SCAN, &hdev->dev_flags); | 1160 | clear_bit(HCI_LE_SCAN, &hdev->dev_flags); |
| 1161 | |||
| 1110 | /* The HCI_LE_SCAN_INTERRUPTED flag indicates that we | 1162 | /* The HCI_LE_SCAN_INTERRUPTED flag indicates that we |
| 1111 | * interrupted scanning due to a connect request. Mark | 1163 | * interrupted scanning due to a connect request. Mark |
| 1112 | * therefore discovery as stopped. | 1164 | * therefore discovery as stopped. If this was not |
| 1165 | * because of a connect request advertising might have | ||
| 1166 | * been disabled because of active scanning, so | ||
| 1167 | * re-enable it again if necessary. | ||
| 1113 | */ | 1168 | */ |
| 1114 | if (test_and_clear_bit(HCI_LE_SCAN_INTERRUPTED, | 1169 | if (test_and_clear_bit(HCI_LE_SCAN_INTERRUPTED, |
| 1115 | &hdev->dev_flags)) | 1170 | &hdev->dev_flags)) |
| 1116 | hci_discovery_set_state(hdev, DISCOVERY_STOPPED); | 1171 | hci_discovery_set_state(hdev, DISCOVERY_STOPPED); |
| 1172 | else if (!test_bit(HCI_LE_ADV, &hdev->dev_flags) && | ||
| 1173 | hdev->discovery.state == DISCOVERY_FINDING) | ||
| 1174 | mgmt_reenable_advertising(hdev); | ||
| 1175 | |||
| 1117 | break; | 1176 | break; |
| 1118 | 1177 | ||
| 1119 | default: | 1178 | default: |
| @@ -1129,8 +1188,10 @@ static void hci_cc_le_read_white_list_size(struct hci_dev *hdev, | |||
| 1129 | 1188 | ||
| 1130 | BT_DBG("%s status 0x%2.2x size %u", hdev->name, rp->status, rp->size); | 1189 | BT_DBG("%s status 0x%2.2x size %u", hdev->name, rp->status, rp->size); |
| 1131 | 1190 | ||
| 1132 | if (!rp->status) | 1191 | if (rp->status) |
| 1133 | hdev->le_white_list_size = rp->size; | 1192 | return; |
| 1193 | |||
| 1194 | hdev->le_white_list_size = rp->size; | ||
| 1134 | } | 1195 | } |
| 1135 | 1196 | ||
| 1136 | static void hci_cc_le_clear_white_list(struct hci_dev *hdev, | 1197 | static void hci_cc_le_clear_white_list(struct hci_dev *hdev, |
| @@ -1140,8 +1201,10 @@ static void hci_cc_le_clear_white_list(struct hci_dev *hdev, | |||
| 1140 | 1201 | ||
| 1141 | BT_DBG("%s status 0x%2.2x", hdev->name, status); | 1202 | BT_DBG("%s status 0x%2.2x", hdev->name, status); |
| 1142 | 1203 | ||
| 1143 | if (!status) | 1204 | if (status) |
| 1144 | hci_white_list_clear(hdev); | 1205 | return; |
| 1206 | |||
| 1207 | hci_bdaddr_list_clear(&hdev->le_white_list); | ||
| 1145 | } | 1208 | } |
| 1146 | 1209 | ||
| 1147 | static void hci_cc_le_add_to_white_list(struct hci_dev *hdev, | 1210 | static void hci_cc_le_add_to_white_list(struct hci_dev *hdev, |
| @@ -1152,12 +1215,15 @@ static void hci_cc_le_add_to_white_list(struct hci_dev *hdev, | |||
| 1152 | 1215 | ||
| 1153 | BT_DBG("%s status 0x%2.2x", hdev->name, status); | 1216 | BT_DBG("%s status 0x%2.2x", hdev->name, status); |
| 1154 | 1217 | ||
| 1218 | if (status) | ||
| 1219 | return; | ||
| 1220 | |||
| 1155 | sent = hci_sent_cmd_data(hdev, HCI_OP_LE_ADD_TO_WHITE_LIST); | 1221 | sent = hci_sent_cmd_data(hdev, HCI_OP_LE_ADD_TO_WHITE_LIST); |
| 1156 | if (!sent) | 1222 | if (!sent) |
| 1157 | return; | 1223 | return; |
| 1158 | 1224 | ||
| 1159 | if (!status) | 1225 | hci_bdaddr_list_add(&hdev->le_white_list, &sent->bdaddr, |
| 1160 | hci_white_list_add(hdev, &sent->bdaddr, sent->bdaddr_type); | 1226 | sent->bdaddr_type); |
| 1161 | } | 1227 | } |
| 1162 | 1228 | ||
| 1163 | static void hci_cc_le_del_from_white_list(struct hci_dev *hdev, | 1229 | static void hci_cc_le_del_from_white_list(struct hci_dev *hdev, |
| @@ -1168,12 +1234,15 @@ static void hci_cc_le_del_from_white_list(struct hci_dev *hdev, | |||
| 1168 | 1234 | ||
| 1169 | BT_DBG("%s status 0x%2.2x", hdev->name, status); | 1235 | BT_DBG("%s status 0x%2.2x", hdev->name, status); |
| 1170 | 1236 | ||
| 1237 | if (status) | ||
| 1238 | return; | ||
| 1239 | |||
| 1171 | sent = hci_sent_cmd_data(hdev, HCI_OP_LE_DEL_FROM_WHITE_LIST); | 1240 | sent = hci_sent_cmd_data(hdev, HCI_OP_LE_DEL_FROM_WHITE_LIST); |
| 1172 | if (!sent) | 1241 | if (!sent) |
| 1173 | return; | 1242 | return; |
| 1174 | 1243 | ||
| 1175 | if (!status) | 1244 | hci_bdaddr_list_del(&hdev->le_white_list, &sent->bdaddr, |
| 1176 | hci_white_list_del(hdev, &sent->bdaddr, sent->bdaddr_type); | 1245 | sent->bdaddr_type); |
| 1177 | } | 1246 | } |
| 1178 | 1247 | ||
| 1179 | static void hci_cc_le_read_supported_states(struct hci_dev *hdev, | 1248 | static void hci_cc_le_read_supported_states(struct hci_dev *hdev, |
| @@ -1183,8 +1252,10 @@ static void hci_cc_le_read_supported_states(struct hci_dev *hdev, | |||
| 1183 | 1252 | ||
| 1184 | BT_DBG("%s status 0x%2.2x", hdev->name, rp->status); | 1253 | BT_DBG("%s status 0x%2.2x", hdev->name, rp->status); |
| 1185 | 1254 | ||
| 1186 | if (!rp->status) | 1255 | if (rp->status) |
| 1187 | memcpy(hdev->le_states, rp->le_states, 8); | 1256 | return; |
| 1257 | |||
| 1258 | memcpy(hdev->le_states, rp->le_states, 8); | ||
| 1188 | } | 1259 | } |
| 1189 | 1260 | ||
| 1190 | static void hci_cc_write_le_host_supported(struct hci_dev *hdev, | 1261 | static void hci_cc_write_le_host_supported(struct hci_dev *hdev, |
| @@ -1195,25 +1266,26 @@ static void hci_cc_write_le_host_supported(struct hci_dev *hdev, | |||
| 1195 | 1266 | ||
| 1196 | BT_DBG("%s status 0x%2.2x", hdev->name, status); | 1267 | BT_DBG("%s status 0x%2.2x", hdev->name, status); |
| 1197 | 1268 | ||
| 1269 | if (status) | ||
| 1270 | return; | ||
| 1271 | |||
| 1198 | sent = hci_sent_cmd_data(hdev, HCI_OP_WRITE_LE_HOST_SUPPORTED); | 1272 | sent = hci_sent_cmd_data(hdev, HCI_OP_WRITE_LE_HOST_SUPPORTED); |
| 1199 | if (!sent) | 1273 | if (!sent) |
| 1200 | return; | 1274 | return; |
| 1201 | 1275 | ||
| 1202 | if (!status) { | 1276 | if (sent->le) { |
| 1203 | if (sent->le) { | 1277 | hdev->features[1][0] |= LMP_HOST_LE; |
| 1204 | hdev->features[1][0] |= LMP_HOST_LE; | 1278 | set_bit(HCI_LE_ENABLED, &hdev->dev_flags); |
| 1205 | set_bit(HCI_LE_ENABLED, &hdev->dev_flags); | 1279 | } else { |
| 1206 | } else { | 1280 | hdev->features[1][0] &= ~LMP_HOST_LE; |
| 1207 | hdev->features[1][0] &= ~LMP_HOST_LE; | 1281 | clear_bit(HCI_LE_ENABLED, &hdev->dev_flags); |
| 1208 | clear_bit(HCI_LE_ENABLED, &hdev->dev_flags); | 1282 | clear_bit(HCI_ADVERTISING, &hdev->dev_flags); |
| 1209 | clear_bit(HCI_ADVERTISING, &hdev->dev_flags); | ||
| 1210 | } | ||
| 1211 | |||
| 1212 | if (sent->simul) | ||
| 1213 | hdev->features[1][0] |= LMP_HOST_LE_BREDR; | ||
| 1214 | else | ||
| 1215 | hdev->features[1][0] &= ~LMP_HOST_LE_BREDR; | ||
| 1216 | } | 1283 | } |
| 1284 | |||
| 1285 | if (sent->simul) | ||
| 1286 | hdev->features[1][0] |= LMP_HOST_LE_BREDR; | ||
| 1287 | else | ||
| 1288 | hdev->features[1][0] &= ~LMP_HOST_LE_BREDR; | ||
| 1217 | } | 1289 | } |
| 1218 | 1290 | ||
| 1219 | static void hci_cc_set_adv_param(struct hci_dev *hdev, struct sk_buff *skb) | 1291 | static void hci_cc_set_adv_param(struct hci_dev *hdev, struct sk_buff *skb) |
| @@ -1342,11 +1414,9 @@ static void hci_cs_create_conn(struct hci_dev *hdev, __u8 status) | |||
| 1342 | } | 1414 | } |
| 1343 | } else { | 1415 | } else { |
| 1344 | if (!conn) { | 1416 | if (!conn) { |
| 1345 | conn = hci_conn_add(hdev, ACL_LINK, &cp->bdaddr); | 1417 | conn = hci_conn_add(hdev, ACL_LINK, &cp->bdaddr, |
| 1346 | if (conn) { | 1418 | HCI_ROLE_MASTER); |
| 1347 | conn->out = true; | 1419 | if (!conn) |
| 1348 | conn->link_mode |= HCI_LM_MASTER; | ||
| 1349 | } else | ||
| 1350 | BT_ERR("No memory for new connection"); | 1420 | BT_ERR("No memory for new connection"); |
| 1351 | } | 1421 | } |
| 1352 | } | 1422 | } |
| @@ -1575,6 +1645,8 @@ static void hci_cs_remote_name_req(struct hci_dev *hdev, __u8 status) | |||
| 1575 | if (!test_and_set_bit(HCI_CONN_AUTH_PEND, &conn->flags)) { | 1645 | if (!test_and_set_bit(HCI_CONN_AUTH_PEND, &conn->flags)) { |
| 1576 | struct hci_cp_auth_requested auth_cp; | 1646 | struct hci_cp_auth_requested auth_cp; |
| 1577 | 1647 | ||
| 1648 | set_bit(HCI_CONN_AUTH_INITIATOR, &conn->flags); | ||
| 1649 | |||
| 1578 | auth_cp.handle = __cpu_to_le16(conn->handle); | 1650 | auth_cp.handle = __cpu_to_le16(conn->handle); |
| 1579 | hci_send_cmd(hdev, HCI_OP_AUTH_REQUESTED, | 1651 | hci_send_cmd(hdev, HCI_OP_AUTH_REQUESTED, |
| 1580 | sizeof(auth_cp), &auth_cp); | 1652 | sizeof(auth_cp), &auth_cp); |
| @@ -1835,7 +1907,7 @@ static void hci_cs_le_create_conn(struct hci_dev *hdev, u8 status) | |||
| 1835 | if (cp->filter_policy == HCI_LE_USE_PEER_ADDR) | 1907 | if (cp->filter_policy == HCI_LE_USE_PEER_ADDR) |
| 1836 | queue_delayed_work(conn->hdev->workqueue, | 1908 | queue_delayed_work(conn->hdev->workqueue, |
| 1837 | &conn->le_conn_timeout, | 1909 | &conn->le_conn_timeout, |
| 1838 | HCI_LE_CONN_TIMEOUT); | 1910 | conn->conn_timeout); |
| 1839 | 1911 | ||
| 1840 | unlock: | 1912 | unlock: |
| 1841 | hci_dev_unlock(hdev); | 1913 | hci_dev_unlock(hdev); |
| @@ -1929,7 +2001,7 @@ static void hci_inquiry_result_evt(struct hci_dev *hdev, struct sk_buff *skb) | |||
| 1929 | hci_dev_lock(hdev); | 2001 | hci_dev_lock(hdev); |
| 1930 | 2002 | ||
| 1931 | for (; num_rsp; num_rsp--, info++) { | 2003 | for (; num_rsp; num_rsp--, info++) { |
| 1932 | bool name_known, ssp; | 2004 | u32 flags; |
| 1933 | 2005 | ||
| 1934 | bacpy(&data.bdaddr, &info->bdaddr); | 2006 | bacpy(&data.bdaddr, &info->bdaddr); |
| 1935 | data.pscan_rep_mode = info->pscan_rep_mode; | 2007 | data.pscan_rep_mode = info->pscan_rep_mode; |
| @@ -1940,10 +2012,10 @@ static void hci_inquiry_result_evt(struct hci_dev *hdev, struct sk_buff *skb) | |||
| 1940 | data.rssi = 0x00; | 2012 | data.rssi = 0x00; |
| 1941 | data.ssp_mode = 0x00; | 2013 | data.ssp_mode = 0x00; |
| 1942 | 2014 | ||
| 1943 | name_known = hci_inquiry_cache_update(hdev, &data, false, &ssp); | 2015 | flags = hci_inquiry_cache_update(hdev, &data, false); |
| 2016 | |||
| 1944 | mgmt_device_found(hdev, &info->bdaddr, ACL_LINK, 0x00, | 2017 | mgmt_device_found(hdev, &info->bdaddr, ACL_LINK, 0x00, |
| 1945 | info->dev_class, 0, !name_known, ssp, NULL, | 2018 | info->dev_class, 0, flags, NULL, 0, NULL, 0); |
| 1946 | 0, NULL, 0); | ||
| 1947 | } | 2019 | } |
| 1948 | 2020 | ||
| 1949 | hci_dev_unlock(hdev); | 2021 | hci_dev_unlock(hdev); |
| @@ -1988,10 +2060,10 @@ static void hci_conn_complete_evt(struct hci_dev *hdev, struct sk_buff *skb) | |||
| 1988 | hci_conn_add_sysfs(conn); | 2060 | hci_conn_add_sysfs(conn); |
| 1989 | 2061 | ||
| 1990 | if (test_bit(HCI_AUTH, &hdev->flags)) | 2062 | if (test_bit(HCI_AUTH, &hdev->flags)) |
| 1991 | conn->link_mode |= HCI_LM_AUTH; | 2063 | set_bit(HCI_CONN_AUTH, &conn->flags); |
| 1992 | 2064 | ||
| 1993 | if (test_bit(HCI_ENCRYPT, &hdev->flags)) | 2065 | if (test_bit(HCI_ENCRYPT, &hdev->flags)) |
| 1994 | conn->link_mode |= HCI_LM_ENCRYPT; | 2066 | set_bit(HCI_CONN_ENCRYPT, &conn->flags); |
| 1995 | 2067 | ||
| 1996 | /* Get remote features */ | 2068 | /* Get remote features */ |
| 1997 | if (conn->type == ACL_LINK) { | 2069 | if (conn->type == ACL_LINK) { |
| @@ -2031,10 +2103,21 @@ unlock: | |||
| 2031 | hci_conn_check_pending(hdev); | 2103 | hci_conn_check_pending(hdev); |
| 2032 | } | 2104 | } |
| 2033 | 2105 | ||
| 2106 | static void hci_reject_conn(struct hci_dev *hdev, bdaddr_t *bdaddr) | ||
| 2107 | { | ||
| 2108 | struct hci_cp_reject_conn_req cp; | ||
| 2109 | |||
| 2110 | bacpy(&cp.bdaddr, bdaddr); | ||
| 2111 | cp.reason = HCI_ERROR_REJ_BAD_ADDR; | ||
| 2112 | hci_send_cmd(hdev, HCI_OP_REJECT_CONN_REQ, sizeof(cp), &cp); | ||
| 2113 | } | ||
| 2114 | |||
| 2034 | static void hci_conn_request_evt(struct hci_dev *hdev, struct sk_buff *skb) | 2115 | static void hci_conn_request_evt(struct hci_dev *hdev, struct sk_buff *skb) |
| 2035 | { | 2116 | { |
| 2036 | struct hci_ev_conn_request *ev = (void *) skb->data; | 2117 | struct hci_ev_conn_request *ev = (void *) skb->data; |
| 2037 | int mask = hdev->link_mode; | 2118 | int mask = hdev->link_mode; |
| 2119 | struct inquiry_entry *ie; | ||
| 2120 | struct hci_conn *conn; | ||
| 2038 | __u8 flags = 0; | 2121 | __u8 flags = 0; |
| 2039 | 2122 | ||
| 2040 | BT_DBG("%s bdaddr %pMR type 0x%x", hdev->name, &ev->bdaddr, | 2123 | BT_DBG("%s bdaddr %pMR type 0x%x", hdev->name, &ev->bdaddr, |
| @@ -2043,73 +2126,79 @@ static void hci_conn_request_evt(struct hci_dev *hdev, struct sk_buff *skb) | |||
| 2043 | mask |= hci_proto_connect_ind(hdev, &ev->bdaddr, ev->link_type, | 2126 | mask |= hci_proto_connect_ind(hdev, &ev->bdaddr, ev->link_type, |
| 2044 | &flags); | 2127 | &flags); |
| 2045 | 2128 | ||
| 2046 | if ((mask & HCI_LM_ACCEPT) && | 2129 | if (!(mask & HCI_LM_ACCEPT)) { |
| 2047 | !hci_blacklist_lookup(hdev, &ev->bdaddr, BDADDR_BREDR)) { | 2130 | hci_reject_conn(hdev, &ev->bdaddr); |
| 2048 | /* Connection accepted */ | 2131 | return; |
| 2049 | struct inquiry_entry *ie; | 2132 | } |
| 2050 | struct hci_conn *conn; | ||
| 2051 | 2133 | ||
| 2052 | hci_dev_lock(hdev); | 2134 | if (hci_bdaddr_list_lookup(&hdev->blacklist, &ev->bdaddr, |
| 2135 | BDADDR_BREDR)) { | ||
| 2136 | hci_reject_conn(hdev, &ev->bdaddr); | ||
| 2137 | return; | ||
| 2138 | } | ||
| 2053 | 2139 | ||
| 2054 | ie = hci_inquiry_cache_lookup(hdev, &ev->bdaddr); | 2140 | if (!test_bit(HCI_CONNECTABLE, &hdev->dev_flags) && |
| 2055 | if (ie) | 2141 | !hci_bdaddr_list_lookup(&hdev->whitelist, &ev->bdaddr, |
| 2056 | memcpy(ie->data.dev_class, ev->dev_class, 3); | 2142 | BDADDR_BREDR)) { |
| 2143 | hci_reject_conn(hdev, &ev->bdaddr); | ||
| 2144 | return; | ||
| 2145 | } | ||
| 2146 | |||
| 2147 | /* Connection accepted */ | ||
| 2057 | 2148 | ||
| 2058 | conn = hci_conn_hash_lookup_ba(hdev, ev->link_type, | 2149 | hci_dev_lock(hdev); |
| 2059 | &ev->bdaddr); | 2150 | |
| 2151 | ie = hci_inquiry_cache_lookup(hdev, &ev->bdaddr); | ||
| 2152 | if (ie) | ||
| 2153 | memcpy(ie->data.dev_class, ev->dev_class, 3); | ||
| 2154 | |||
| 2155 | conn = hci_conn_hash_lookup_ba(hdev, ev->link_type, | ||
| 2156 | &ev->bdaddr); | ||
| 2157 | if (!conn) { | ||
| 2158 | conn = hci_conn_add(hdev, ev->link_type, &ev->bdaddr, | ||
| 2159 | HCI_ROLE_SLAVE); | ||
| 2060 | if (!conn) { | 2160 | if (!conn) { |
| 2061 | conn = hci_conn_add(hdev, ev->link_type, &ev->bdaddr); | 2161 | BT_ERR("No memory for new connection"); |
| 2062 | if (!conn) { | 2162 | hci_dev_unlock(hdev); |
| 2063 | BT_ERR("No memory for new connection"); | 2163 | return; |
| 2064 | hci_dev_unlock(hdev); | ||
| 2065 | return; | ||
| 2066 | } | ||
| 2067 | } | 2164 | } |
| 2165 | } | ||
| 2068 | 2166 | ||
| 2069 | memcpy(conn->dev_class, ev->dev_class, 3); | 2167 | memcpy(conn->dev_class, ev->dev_class, 3); |
| 2070 | 2168 | ||
| 2071 | hci_dev_unlock(hdev); | 2169 | hci_dev_unlock(hdev); |
| 2072 | 2170 | ||
| 2073 | if (ev->link_type == ACL_LINK || | 2171 | if (ev->link_type == ACL_LINK || |
| 2074 | (!(flags & HCI_PROTO_DEFER) && !lmp_esco_capable(hdev))) { | 2172 | (!(flags & HCI_PROTO_DEFER) && !lmp_esco_capable(hdev))) { |
| 2075 | struct hci_cp_accept_conn_req cp; | 2173 | struct hci_cp_accept_conn_req cp; |
| 2076 | conn->state = BT_CONNECT; | 2174 | conn->state = BT_CONNECT; |
| 2077 | 2175 | ||
| 2078 | bacpy(&cp.bdaddr, &ev->bdaddr); | 2176 | bacpy(&cp.bdaddr, &ev->bdaddr); |
| 2079 | 2177 | ||
| 2080 | if (lmp_rswitch_capable(hdev) && (mask & HCI_LM_MASTER)) | 2178 | if (lmp_rswitch_capable(hdev) && (mask & HCI_LM_MASTER)) |
| 2081 | cp.role = 0x00; /* Become master */ | 2179 | cp.role = 0x00; /* Become master */ |
| 2082 | else | 2180 | else |
| 2083 | cp.role = 0x01; /* Remain slave */ | 2181 | cp.role = 0x01; /* Remain slave */ |
| 2084 | 2182 | ||
| 2085 | hci_send_cmd(hdev, HCI_OP_ACCEPT_CONN_REQ, sizeof(cp), | 2183 | hci_send_cmd(hdev, HCI_OP_ACCEPT_CONN_REQ, sizeof(cp), &cp); |
| 2086 | &cp); | 2184 | } else if (!(flags & HCI_PROTO_DEFER)) { |
| 2087 | } else if (!(flags & HCI_PROTO_DEFER)) { | 2185 | struct hci_cp_accept_sync_conn_req cp; |
| 2088 | struct hci_cp_accept_sync_conn_req cp; | 2186 | conn->state = BT_CONNECT; |
| 2089 | conn->state = BT_CONNECT; | ||
| 2090 | 2187 | ||
| 2091 | bacpy(&cp.bdaddr, &ev->bdaddr); | 2188 | bacpy(&cp.bdaddr, &ev->bdaddr); |
| 2092 | cp.pkt_type = cpu_to_le16(conn->pkt_type); | 2189 | cp.pkt_type = cpu_to_le16(conn->pkt_type); |
| 2093 | 2190 | ||
| 2094 | cp.tx_bandwidth = cpu_to_le32(0x00001f40); | 2191 | cp.tx_bandwidth = cpu_to_le32(0x00001f40); |
| 2095 | cp.rx_bandwidth = cpu_to_le32(0x00001f40); | 2192 | cp.rx_bandwidth = cpu_to_le32(0x00001f40); |
| 2096 | cp.max_latency = cpu_to_le16(0xffff); | 2193 | cp.max_latency = cpu_to_le16(0xffff); |
| 2097 | cp.content_format = cpu_to_le16(hdev->voice_setting); | 2194 | cp.content_format = cpu_to_le16(hdev->voice_setting); |
| 2098 | cp.retrans_effort = 0xff; | 2195 | cp.retrans_effort = 0xff; |
| 2099 | 2196 | ||
| 2100 | hci_send_cmd(hdev, HCI_OP_ACCEPT_SYNC_CONN_REQ, | 2197 | hci_send_cmd(hdev, HCI_OP_ACCEPT_SYNC_CONN_REQ, sizeof(cp), |
| 2101 | sizeof(cp), &cp); | 2198 | &cp); |
| 2102 | } else { | ||
| 2103 | conn->state = BT_CONNECT2; | ||
| 2104 | hci_proto_connect_cfm(conn, 0); | ||
| 2105 | } | ||
| 2106 | } else { | 2199 | } else { |
| 2107 | /* Connection rejected */ | 2200 | conn->state = BT_CONNECT2; |
| 2108 | struct hci_cp_reject_conn_req cp; | 2201 | hci_proto_connect_cfm(conn, 0); |
| 2109 | |||
| 2110 | bacpy(&cp.bdaddr, &ev->bdaddr); | ||
| 2111 | cp.reason = HCI_ERROR_REJ_BAD_ADDR; | ||
| 2112 | hci_send_cmd(hdev, HCI_OP_REJECT_CONN_REQ, sizeof(cp), &cp); | ||
| 2113 | } | 2202 | } |
| 2114 | } | 2203 | } |
| 2115 | 2204 | ||
| @@ -2158,7 +2247,8 @@ static void hci_disconn_complete_evt(struct hci_dev *hdev, struct sk_buff *skb) | |||
| 2158 | mgmt_device_disconnected(hdev, &conn->dst, conn->type, conn->dst_type, | 2247 | mgmt_device_disconnected(hdev, &conn->dst, conn->type, conn->dst_type, |
| 2159 | reason, mgmt_connected); | 2248 | reason, mgmt_connected); |
| 2160 | 2249 | ||
| 2161 | if (conn->type == ACL_LINK && conn->flush_key) | 2250 | if (conn->type == ACL_LINK && |
| 2251 | test_bit(HCI_CONN_FLUSH_KEY, &conn->flags)) | ||
| 2162 | hci_remove_link_key(hdev, &conn->dst); | 2252 | hci_remove_link_key(hdev, &conn->dst); |
| 2163 | 2253 | ||
| 2164 | params = hci_conn_params_lookup(hdev, &conn->dst, conn->dst_type); | 2254 | params = hci_conn_params_lookup(hdev, &conn->dst, conn->dst_type); |
| @@ -2169,8 +2259,11 @@ static void hci_disconn_complete_evt(struct hci_dev *hdev, struct sk_buff *skb) | |||
| 2169 | break; | 2259 | break; |
| 2170 | /* Fall through */ | 2260 | /* Fall through */ |
| 2171 | 2261 | ||
| 2262 | case HCI_AUTO_CONN_DIRECT: | ||
| 2172 | case HCI_AUTO_CONN_ALWAYS: | 2263 | case HCI_AUTO_CONN_ALWAYS: |
| 2173 | hci_pend_le_conn_add(hdev, &conn->dst, conn->dst_type); | 2264 | list_del_init(¶ms->action); |
| 2265 | list_add(¶ms->action, &hdev->pend_le_conns); | ||
| 2266 | hci_update_background_scan(hdev); | ||
| 2174 | break; | 2267 | break; |
| 2175 | 2268 | ||
| 2176 | default: | 2269 | default: |
| @@ -2218,7 +2311,7 @@ static void hci_auth_complete_evt(struct hci_dev *hdev, struct sk_buff *skb) | |||
| 2218 | test_bit(HCI_CONN_REAUTH_PEND, &conn->flags)) { | 2311 | test_bit(HCI_CONN_REAUTH_PEND, &conn->flags)) { |
| 2219 | BT_INFO("re-auth of legacy device is not possible."); | 2312 | BT_INFO("re-auth of legacy device is not possible."); |
| 2220 | } else { | 2313 | } else { |
| 2221 | conn->link_mode |= HCI_LM_AUTH; | 2314 | set_bit(HCI_CONN_AUTH, &conn->flags); |
| 2222 | conn->sec_level = conn->pending_sec_level; | 2315 | conn->sec_level = conn->pending_sec_level; |
| 2223 | } | 2316 | } |
| 2224 | } else { | 2317 | } else { |
| @@ -2297,6 +2390,9 @@ check_auth: | |||
| 2297 | 2390 | ||
| 2298 | if (!test_and_set_bit(HCI_CONN_AUTH_PEND, &conn->flags)) { | 2391 | if (!test_and_set_bit(HCI_CONN_AUTH_PEND, &conn->flags)) { |
| 2299 | struct hci_cp_auth_requested cp; | 2392 | struct hci_cp_auth_requested cp; |
| 2393 | |||
| 2394 | set_bit(HCI_CONN_AUTH_INITIATOR, &conn->flags); | ||
| 2395 | |||
| 2300 | cp.handle = __cpu_to_le16(conn->handle); | 2396 | cp.handle = __cpu_to_le16(conn->handle); |
| 2301 | hci_send_cmd(hdev, HCI_OP_AUTH_REQUESTED, sizeof(cp), &cp); | 2397 | hci_send_cmd(hdev, HCI_OP_AUTH_REQUESTED, sizeof(cp), &cp); |
| 2302 | } | 2398 | } |
| @@ -2321,19 +2417,19 @@ static void hci_encrypt_change_evt(struct hci_dev *hdev, struct sk_buff *skb) | |||
| 2321 | if (!ev->status) { | 2417 | if (!ev->status) { |
| 2322 | if (ev->encrypt) { | 2418 | if (ev->encrypt) { |
| 2323 | /* Encryption implies authentication */ | 2419 | /* Encryption implies authentication */ |
| 2324 | conn->link_mode |= HCI_LM_AUTH; | 2420 | set_bit(HCI_CONN_AUTH, &conn->flags); |
| 2325 | conn->link_mode |= HCI_LM_ENCRYPT; | 2421 | set_bit(HCI_CONN_ENCRYPT, &conn->flags); |
| 2326 | conn->sec_level = conn->pending_sec_level; | 2422 | conn->sec_level = conn->pending_sec_level; |
| 2327 | 2423 | ||
| 2328 | /* P-256 authentication key implies FIPS */ | 2424 | /* P-256 authentication key implies FIPS */ |
| 2329 | if (conn->key_type == HCI_LK_AUTH_COMBINATION_P256) | 2425 | if (conn->key_type == HCI_LK_AUTH_COMBINATION_P256) |
| 2330 | conn->link_mode |= HCI_LM_FIPS; | 2426 | set_bit(HCI_CONN_FIPS, &conn->flags); |
| 2331 | 2427 | ||
| 2332 | if ((conn->type == ACL_LINK && ev->encrypt == 0x02) || | 2428 | if ((conn->type == ACL_LINK && ev->encrypt == 0x02) || |
| 2333 | conn->type == LE_LINK) | 2429 | conn->type == LE_LINK) |
| 2334 | set_bit(HCI_CONN_AES_CCM, &conn->flags); | 2430 | set_bit(HCI_CONN_AES_CCM, &conn->flags); |
| 2335 | } else { | 2431 | } else { |
| 2336 | conn->link_mode &= ~HCI_LM_ENCRYPT; | 2432 | clear_bit(HCI_CONN_ENCRYPT, &conn->flags); |
| 2337 | clear_bit(HCI_CONN_AES_CCM, &conn->flags); | 2433 | clear_bit(HCI_CONN_AES_CCM, &conn->flags); |
| 2338 | } | 2434 | } |
| 2339 | } | 2435 | } |
| @@ -2384,7 +2480,7 @@ static void hci_change_link_key_complete_evt(struct hci_dev *hdev, | |||
| 2384 | conn = hci_conn_hash_lookup_handle(hdev, __le16_to_cpu(ev->handle)); | 2480 | conn = hci_conn_hash_lookup_handle(hdev, __le16_to_cpu(ev->handle)); |
| 2385 | if (conn) { | 2481 | if (conn) { |
| 2386 | if (!ev->status) | 2482 | if (!ev->status) |
| 2387 | conn->link_mode |= HCI_LM_SECURE; | 2483 | set_bit(HCI_CONN_SECURE, &conn->flags); |
| 2388 | 2484 | ||
| 2389 | clear_bit(HCI_CONN_AUTH_PEND, &conn->flags); | 2485 | clear_bit(HCI_CONN_AUTH_PEND, &conn->flags); |
| 2390 | 2486 | ||
| @@ -2595,6 +2691,10 @@ static void hci_cmd_complete_evt(struct hci_dev *hdev, struct sk_buff *skb) | |||
| 2595 | hci_cc_read_local_amp_info(hdev, skb); | 2691 | hci_cc_read_local_amp_info(hdev, skb); |
| 2596 | break; | 2692 | break; |
| 2597 | 2693 | ||
| 2694 | case HCI_OP_READ_CLOCK: | ||
| 2695 | hci_cc_read_clock(hdev, skb); | ||
| 2696 | break; | ||
| 2697 | |||
| 2598 | case HCI_OP_READ_LOCAL_AMP_ASSOC: | 2698 | case HCI_OP_READ_LOCAL_AMP_ASSOC: |
| 2599 | hci_cc_read_local_amp_assoc(hdev, skb); | 2699 | hci_cc_read_local_amp_assoc(hdev, skb); |
| 2600 | break; | 2700 | break; |
| @@ -2709,7 +2809,7 @@ static void hci_cmd_complete_evt(struct hci_dev *hdev, struct sk_buff *skb) | |||
| 2709 | } | 2809 | } |
| 2710 | 2810 | ||
| 2711 | if (opcode != HCI_OP_NOP) | 2811 | if (opcode != HCI_OP_NOP) |
| 2712 | del_timer(&hdev->cmd_timer); | 2812 | cancel_delayed_work(&hdev->cmd_timer); |
| 2713 | 2813 | ||
| 2714 | hci_req_cmd_complete(hdev, opcode, status); | 2814 | hci_req_cmd_complete(hdev, opcode, status); |
| 2715 | 2815 | ||
| @@ -2800,7 +2900,7 @@ static void hci_cmd_status_evt(struct hci_dev *hdev, struct sk_buff *skb) | |||
| 2800 | } | 2900 | } |
| 2801 | 2901 | ||
| 2802 | if (opcode != HCI_OP_NOP) | 2902 | if (opcode != HCI_OP_NOP) |
| 2803 | del_timer(&hdev->cmd_timer); | 2903 | cancel_delayed_work(&hdev->cmd_timer); |
| 2804 | 2904 | ||
| 2805 | if (ev->status || | 2905 | if (ev->status || |
| 2806 | (hdev->sent_cmd && !bt_cb(hdev->sent_cmd)->req.event)) | 2906 | (hdev->sent_cmd && !bt_cb(hdev->sent_cmd)->req.event)) |
| @@ -2824,12 +2924,8 @@ static void hci_role_change_evt(struct hci_dev *hdev, struct sk_buff *skb) | |||
| 2824 | 2924 | ||
| 2825 | conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &ev->bdaddr); | 2925 | conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &ev->bdaddr); |
| 2826 | if (conn) { | 2926 | if (conn) { |
| 2827 | if (!ev->status) { | 2927 | if (!ev->status) |
| 2828 | if (ev->role) | 2928 | conn->role = ev->role; |
| 2829 | conn->link_mode &= ~HCI_LM_MASTER; | ||
| 2830 | else | ||
| 2831 | conn->link_mode |= HCI_LM_MASTER; | ||
| 2832 | } | ||
| 2833 | 2929 | ||
| 2834 | clear_bit(HCI_CONN_RSWITCH_PEND, &conn->flags); | 2930 | clear_bit(HCI_CONN_RSWITCH_PEND, &conn->flags); |
| 2835 | 2931 | ||
| @@ -3023,10 +3119,11 @@ static void hci_pin_code_request_evt(struct hci_dev *hdev, struct sk_buff *skb) | |||
| 3023 | hci_conn_drop(conn); | 3119 | hci_conn_drop(conn); |
| 3024 | } | 3120 | } |
| 3025 | 3121 | ||
| 3026 | if (!test_bit(HCI_PAIRABLE, &hdev->dev_flags)) | 3122 | if (!test_bit(HCI_BONDABLE, &hdev->dev_flags) && |
| 3123 | !test_bit(HCI_CONN_AUTH_INITIATOR, &conn->flags)) { | ||
| 3027 | hci_send_cmd(hdev, HCI_OP_PIN_CODE_NEG_REPLY, | 3124 | hci_send_cmd(hdev, HCI_OP_PIN_CODE_NEG_REPLY, |
| 3028 | sizeof(ev->bdaddr), &ev->bdaddr); | 3125 | sizeof(ev->bdaddr), &ev->bdaddr); |
| 3029 | else if (test_bit(HCI_MGMT, &hdev->dev_flags)) { | 3126 | } else if (test_bit(HCI_MGMT, &hdev->dev_flags)) { |
| 3030 | u8 secure; | 3127 | u8 secure; |
| 3031 | 3128 | ||
| 3032 | if (conn->pending_sec_level == BT_SECURITY_HIGH) | 3129 | if (conn->pending_sec_level == BT_SECURITY_HIGH) |
| @@ -3065,12 +3162,6 @@ static void hci_link_key_request_evt(struct hci_dev *hdev, struct sk_buff *skb) | |||
| 3065 | BT_DBG("%s found key type %u for %pMR", hdev->name, key->type, | 3162 | BT_DBG("%s found key type %u for %pMR", hdev->name, key->type, |
| 3066 | &ev->bdaddr); | 3163 | &ev->bdaddr); |
| 3067 | 3164 | ||
| 3068 | if (!test_bit(HCI_DEBUG_KEYS, &hdev->dev_flags) && | ||
| 3069 | key->type == HCI_LK_DEBUG_COMBINATION) { | ||
| 3070 | BT_DBG("%s ignoring debug key", hdev->name); | ||
| 3071 | goto not_found; | ||
| 3072 | } | ||
| 3073 | |||
| 3074 | conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &ev->bdaddr); | 3165 | conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &ev->bdaddr); |
| 3075 | if (conn) { | 3166 | if (conn) { |
| 3076 | if ((key->type == HCI_LK_UNAUTH_COMBINATION_P192 || | 3167 | if ((key->type == HCI_LK_UNAUTH_COMBINATION_P192 || |
| @@ -3110,6 +3201,8 @@ static void hci_link_key_notify_evt(struct hci_dev *hdev, struct sk_buff *skb) | |||
| 3110 | { | 3201 | { |
| 3111 | struct hci_ev_link_key_notify *ev = (void *) skb->data; | 3202 | struct hci_ev_link_key_notify *ev = (void *) skb->data; |
| 3112 | struct hci_conn *conn; | 3203 | struct hci_conn *conn; |
| 3204 | struct link_key *key; | ||
| 3205 | bool persistent; | ||
| 3113 | u8 pin_len = 0; | 3206 | u8 pin_len = 0; |
| 3114 | 3207 | ||
| 3115 | BT_DBG("%s", hdev->name); | 3208 | BT_DBG("%s", hdev->name); |
| @@ -3128,10 +3221,33 @@ static void hci_link_key_notify_evt(struct hci_dev *hdev, struct sk_buff *skb) | |||
| 3128 | hci_conn_drop(conn); | 3221 | hci_conn_drop(conn); |
| 3129 | } | 3222 | } |
| 3130 | 3223 | ||
| 3131 | if (test_bit(HCI_MGMT, &hdev->dev_flags)) | 3224 | if (!test_bit(HCI_MGMT, &hdev->dev_flags)) |
| 3132 | hci_add_link_key(hdev, conn, 1, &ev->bdaddr, ev->link_key, | 3225 | goto unlock; |
| 3133 | ev->key_type, pin_len); | 3226 | |
| 3227 | key = hci_add_link_key(hdev, conn, &ev->bdaddr, ev->link_key, | ||
| 3228 | ev->key_type, pin_len, &persistent); | ||
| 3229 | if (!key) | ||
| 3230 | goto unlock; | ||
| 3231 | |||
| 3232 | mgmt_new_link_key(hdev, key, persistent); | ||
| 3233 | |||
| 3234 | /* Keep debug keys around only if the HCI_KEEP_DEBUG_KEYS flag | ||
| 3235 | * is set. If it's not set simply remove the key from the kernel | ||
| 3236 | * list (we've still notified user space about it but with | ||
| 3237 | * store_hint being 0). | ||
| 3238 | */ | ||
| 3239 | if (key->type == HCI_LK_DEBUG_COMBINATION && | ||
| 3240 | !test_bit(HCI_KEEP_DEBUG_KEYS, &hdev->dev_flags)) { | ||
| 3241 | list_del(&key->list); | ||
| 3242 | kfree(key); | ||
| 3243 | } else if (conn) { | ||
| 3244 | if (persistent) | ||
| 3245 | clear_bit(HCI_CONN_FLUSH_KEY, &conn->flags); | ||
| 3246 | else | ||
| 3247 | set_bit(HCI_CONN_FLUSH_KEY, &conn->flags); | ||
| 3248 | } | ||
| 3134 | 3249 | ||
| 3250 | unlock: | ||
| 3135 | hci_dev_unlock(hdev); | 3251 | hci_dev_unlock(hdev); |
| 3136 | } | 3252 | } |
| 3137 | 3253 | ||
| @@ -3197,7 +3313,6 @@ static void hci_inquiry_result_with_rssi_evt(struct hci_dev *hdev, | |||
| 3197 | { | 3313 | { |
| 3198 | struct inquiry_data data; | 3314 | struct inquiry_data data; |
| 3199 | int num_rsp = *((__u8 *) skb->data); | 3315 | int num_rsp = *((__u8 *) skb->data); |
| 3200 | bool name_known, ssp; | ||
| 3201 | 3316 | ||
| 3202 | BT_DBG("%s num_rsp %d", hdev->name, num_rsp); | 3317 | BT_DBG("%s num_rsp %d", hdev->name, num_rsp); |
| 3203 | 3318 | ||
| @@ -3214,6 +3329,8 @@ static void hci_inquiry_result_with_rssi_evt(struct hci_dev *hdev, | |||
| 3214 | info = (void *) (skb->data + 1); | 3329 | info = (void *) (skb->data + 1); |
| 3215 | 3330 | ||
| 3216 | for (; num_rsp; num_rsp--, info++) { | 3331 | for (; num_rsp; num_rsp--, info++) { |
| 3332 | u32 flags; | ||
| 3333 | |||
| 3217 | bacpy(&data.bdaddr, &info->bdaddr); | 3334 | bacpy(&data.bdaddr, &info->bdaddr); |
| 3218 | data.pscan_rep_mode = info->pscan_rep_mode; | 3335 | data.pscan_rep_mode = info->pscan_rep_mode; |
| 3219 | data.pscan_period_mode = info->pscan_period_mode; | 3336 | data.pscan_period_mode = info->pscan_period_mode; |
| @@ -3223,16 +3340,18 @@ static void hci_inquiry_result_with_rssi_evt(struct hci_dev *hdev, | |||
| 3223 | data.rssi = info->rssi; | 3340 | data.rssi = info->rssi; |
| 3224 | data.ssp_mode = 0x00; | 3341 | data.ssp_mode = 0x00; |
| 3225 | 3342 | ||
| 3226 | name_known = hci_inquiry_cache_update(hdev, &data, | 3343 | flags = hci_inquiry_cache_update(hdev, &data, false); |
| 3227 | false, &ssp); | 3344 | |
| 3228 | mgmt_device_found(hdev, &info->bdaddr, ACL_LINK, 0x00, | 3345 | mgmt_device_found(hdev, &info->bdaddr, ACL_LINK, 0x00, |
| 3229 | info->dev_class, info->rssi, | 3346 | info->dev_class, info->rssi, |
| 3230 | !name_known, ssp, NULL, 0, NULL, 0); | 3347 | flags, NULL, 0, NULL, 0); |
| 3231 | } | 3348 | } |
| 3232 | } else { | 3349 | } else { |
| 3233 | struct inquiry_info_with_rssi *info = (void *) (skb->data + 1); | 3350 | struct inquiry_info_with_rssi *info = (void *) (skb->data + 1); |
| 3234 | 3351 | ||
| 3235 | for (; num_rsp; num_rsp--, info++) { | 3352 | for (; num_rsp; num_rsp--, info++) { |
| 3353 | u32 flags; | ||
| 3354 | |||
| 3236 | bacpy(&data.bdaddr, &info->bdaddr); | 3355 | bacpy(&data.bdaddr, &info->bdaddr); |
| 3237 | data.pscan_rep_mode = info->pscan_rep_mode; | 3356 | data.pscan_rep_mode = info->pscan_rep_mode; |
| 3238 | data.pscan_period_mode = info->pscan_period_mode; | 3357 | data.pscan_period_mode = info->pscan_period_mode; |
| @@ -3241,11 +3360,12 @@ static void hci_inquiry_result_with_rssi_evt(struct hci_dev *hdev, | |||
| 3241 | data.clock_offset = info->clock_offset; | 3360 | data.clock_offset = info->clock_offset; |
| 3242 | data.rssi = info->rssi; | 3361 | data.rssi = info->rssi; |
| 3243 | data.ssp_mode = 0x00; | 3362 | data.ssp_mode = 0x00; |
| 3244 | name_known = hci_inquiry_cache_update(hdev, &data, | 3363 | |
| 3245 | false, &ssp); | 3364 | flags = hci_inquiry_cache_update(hdev, &data, false); |
| 3365 | |||
| 3246 | mgmt_device_found(hdev, &info->bdaddr, ACL_LINK, 0x00, | 3366 | mgmt_device_found(hdev, &info->bdaddr, ACL_LINK, 0x00, |
| 3247 | info->dev_class, info->rssi, | 3367 | info->dev_class, info->rssi, |
| 3248 | !name_known, ssp, NULL, 0, NULL, 0); | 3368 | flags, NULL, 0, NULL, 0); |
| 3249 | } | 3369 | } |
| 3250 | } | 3370 | } |
| 3251 | 3371 | ||
| @@ -3348,6 +3468,7 @@ static void hci_sync_conn_complete_evt(struct hci_dev *hdev, | |||
| 3348 | hci_conn_add_sysfs(conn); | 3468 | hci_conn_add_sysfs(conn); |
| 3349 | break; | 3469 | break; |
| 3350 | 3470 | ||
| 3471 | case 0x10: /* Connection Accept Timeout */ | ||
| 3351 | case 0x0d: /* Connection Rejected due to Limited Resources */ | 3472 | case 0x0d: /* Connection Rejected due to Limited Resources */ |
| 3352 | case 0x11: /* Unsupported Feature or Parameter Value */ | 3473 | case 0x11: /* Unsupported Feature or Parameter Value */ |
| 3353 | case 0x1c: /* SCO interval rejected */ | 3474 | case 0x1c: /* SCO interval rejected */ |
| @@ -3411,7 +3532,8 @@ static void hci_extended_inquiry_result_evt(struct hci_dev *hdev, | |||
| 3411 | hci_dev_lock(hdev); | 3532 | hci_dev_lock(hdev); |
| 3412 | 3533 | ||
| 3413 | for (; num_rsp; num_rsp--, info++) { | 3534 | for (; num_rsp; num_rsp--, info++) { |
| 3414 | bool name_known, ssp; | 3535 | u32 flags; |
| 3536 | bool name_known; | ||
| 3415 | 3537 | ||
| 3416 | bacpy(&data.bdaddr, &info->bdaddr); | 3538 | bacpy(&data.bdaddr, &info->bdaddr); |
| 3417 | data.pscan_rep_mode = info->pscan_rep_mode; | 3539 | data.pscan_rep_mode = info->pscan_rep_mode; |
| @@ -3429,12 +3551,13 @@ static void hci_extended_inquiry_result_evt(struct hci_dev *hdev, | |||
| 3429 | else | 3551 | else |
| 3430 | name_known = true; | 3552 | name_known = true; |
| 3431 | 3553 | ||
| 3432 | name_known = hci_inquiry_cache_update(hdev, &data, name_known, | 3554 | flags = hci_inquiry_cache_update(hdev, &data, name_known); |
| 3433 | &ssp); | 3555 | |
| 3434 | eir_len = eir_get_length(info->data, sizeof(info->data)); | 3556 | eir_len = eir_get_length(info->data, sizeof(info->data)); |
| 3557 | |||
| 3435 | mgmt_device_found(hdev, &info->bdaddr, ACL_LINK, 0x00, | 3558 | mgmt_device_found(hdev, &info->bdaddr, ACL_LINK, 0x00, |
| 3436 | info->dev_class, info->rssi, !name_known, | 3559 | info->dev_class, info->rssi, |
| 3437 | ssp, info->data, eir_len, NULL, 0); | 3560 | flags, info->data, eir_len, NULL, 0); |
| 3438 | } | 3561 | } |
| 3439 | 3562 | ||
| 3440 | hci_dev_unlock(hdev); | 3563 | hci_dev_unlock(hdev); |
| @@ -3526,7 +3649,11 @@ static void hci_io_capa_request_evt(struct hci_dev *hdev, struct sk_buff *skb) | |||
| 3526 | if (!test_bit(HCI_MGMT, &hdev->dev_flags)) | 3649 | if (!test_bit(HCI_MGMT, &hdev->dev_flags)) |
| 3527 | goto unlock; | 3650 | goto unlock; |
| 3528 | 3651 | ||
| 3529 | if (test_bit(HCI_PAIRABLE, &hdev->dev_flags) || | 3652 | /* Allow pairing if we're pairable, the initiators of the |
| 3653 | * pairing or if the remote is not requesting bonding. | ||
| 3654 | */ | ||
| 3655 | if (test_bit(HCI_BONDABLE, &hdev->dev_flags) || | ||
| 3656 | test_bit(HCI_CONN_AUTH_INITIATOR, &conn->flags) || | ||
| 3530 | (conn->remote_auth & ~0x01) == HCI_AT_NO_BONDING) { | 3657 | (conn->remote_auth & ~0x01) == HCI_AT_NO_BONDING) { |
| 3531 | struct hci_cp_io_capability_reply cp; | 3658 | struct hci_cp_io_capability_reply cp; |
| 3532 | 3659 | ||
| @@ -3538,23 +3665,24 @@ static void hci_io_capa_request_evt(struct hci_dev *hdev, struct sk_buff *skb) | |||
| 3538 | 3665 | ||
| 3539 | /* If we are initiators, there is no remote information yet */ | 3666 | /* If we are initiators, there is no remote information yet */ |
| 3540 | if (conn->remote_auth == 0xff) { | 3667 | if (conn->remote_auth == 0xff) { |
| 3541 | cp.authentication = conn->auth_type; | ||
| 3542 | |||
| 3543 | /* Request MITM protection if our IO caps allow it | 3668 | /* Request MITM protection if our IO caps allow it |
| 3544 | * except for the no-bonding case. | 3669 | * except for the no-bonding case. |
| 3545 | * conn->auth_type is not updated here since | ||
| 3546 | * that might cause the user confirmation to be | ||
| 3547 | * rejected in case the remote doesn't have the | ||
| 3548 | * IO capabilities for MITM. | ||
| 3549 | */ | 3670 | */ |
| 3550 | if (conn->io_capability != HCI_IO_NO_INPUT_OUTPUT && | 3671 | if (conn->io_capability != HCI_IO_NO_INPUT_OUTPUT && |
| 3551 | cp.authentication != HCI_AT_NO_BONDING) | 3672 | conn->auth_type != HCI_AT_NO_BONDING) |
| 3552 | cp.authentication |= 0x01; | 3673 | conn->auth_type |= 0x01; |
| 3553 | } else { | 3674 | } else { |
| 3554 | conn->auth_type = hci_get_auth_req(conn); | 3675 | conn->auth_type = hci_get_auth_req(conn); |
| 3555 | cp.authentication = conn->auth_type; | ||
| 3556 | } | 3676 | } |
| 3557 | 3677 | ||
| 3678 | /* If we're not bondable, force one of the non-bondable | ||
| 3679 | * authentication requirement values. | ||
| 3680 | */ | ||
| 3681 | if (!test_bit(HCI_BONDABLE, &hdev->dev_flags)) | ||
| 3682 | conn->auth_type &= HCI_AT_NO_BONDING_MITM; | ||
| 3683 | |||
| 3684 | cp.authentication = conn->auth_type; | ||
| 3685 | |||
| 3558 | if (hci_find_remote_oob_data(hdev, &conn->dst) && | 3686 | if (hci_find_remote_oob_data(hdev, &conn->dst) && |
| 3559 | (conn->out || test_bit(HCI_CONN_REMOTE_OOB, &conn->flags))) | 3687 | (conn->out || test_bit(HCI_CONN_REMOTE_OOB, &conn->flags))) |
| 3560 | cp.oob_data = 0x01; | 3688 | cp.oob_data = 0x01; |
| @@ -3621,9 +3749,12 @@ static void hci_user_confirm_request_evt(struct hci_dev *hdev, | |||
| 3621 | rem_mitm = (conn->remote_auth & 0x01); | 3749 | rem_mitm = (conn->remote_auth & 0x01); |
| 3622 | 3750 | ||
| 3623 | /* If we require MITM but the remote device can't provide that | 3751 | /* If we require MITM but the remote device can't provide that |
| 3624 | * (it has NoInputNoOutput) then reject the confirmation request | 3752 | * (it has NoInputNoOutput) then reject the confirmation |
| 3753 | * request. We check the security level here since it doesn't | ||
| 3754 | * necessarily match conn->auth_type. | ||
| 3625 | */ | 3755 | */ |
| 3626 | if (loc_mitm && conn->remote_cap == HCI_IO_NO_INPUT_OUTPUT) { | 3756 | if (conn->pending_sec_level > BT_SECURITY_MEDIUM && |
| 3757 | conn->remote_cap == HCI_IO_NO_INPUT_OUTPUT) { | ||
| 3627 | BT_DBG("Rejecting request: remote device can't provide MITM"); | 3758 | BT_DBG("Rejecting request: remote device can't provide MITM"); |
| 3628 | hci_send_cmd(hdev, HCI_OP_USER_CONFIRM_NEG_REPLY, | 3759 | hci_send_cmd(hdev, HCI_OP_USER_CONFIRM_NEG_REPLY, |
| 3629 | sizeof(ev->bdaddr), &ev->bdaddr); | 3760 | sizeof(ev->bdaddr), &ev->bdaddr); |
| @@ -3637,9 +3768,11 @@ static void hci_user_confirm_request_evt(struct hci_dev *hdev, | |||
| 3637 | /* If we're not the initiators request authorization to | 3768 | /* If we're not the initiators request authorization to |
| 3638 | * proceed from user space (mgmt_user_confirm with | 3769 | * proceed from user space (mgmt_user_confirm with |
| 3639 | * confirm_hint set to 1). The exception is if neither | 3770 | * confirm_hint set to 1). The exception is if neither |
| 3640 | * side had MITM in which case we do auto-accept. | 3771 | * side had MITM or if the local IO capability is |
| 3772 | * NoInputNoOutput, in which case we do auto-accept | ||
| 3641 | */ | 3773 | */ |
| 3642 | if (!test_bit(HCI_CONN_AUTH_PEND, &conn->flags) && | 3774 | if (!test_bit(HCI_CONN_AUTH_PEND, &conn->flags) && |
| 3775 | conn->io_capability != HCI_IO_NO_INPUT_OUTPUT && | ||
| 3643 | (loc_mitm || rem_mitm)) { | 3776 | (loc_mitm || rem_mitm)) { |
| 3644 | BT_DBG("Confirming auto-accept as acceptor"); | 3777 | BT_DBG("Confirming auto-accept as acceptor"); |
| 3645 | confirm_hint = 1; | 3778 | confirm_hint = 1; |
| @@ -3753,6 +3886,9 @@ static void hci_simple_pair_complete_evt(struct hci_dev *hdev, | |||
| 3753 | if (!conn) | 3886 | if (!conn) |
| 3754 | goto unlock; | 3887 | goto unlock; |
| 3755 | 3888 | ||
| 3889 | /* Reset the authentication requirement to unknown */ | ||
| 3890 | conn->remote_auth = 0xff; | ||
| 3891 | |||
| 3756 | /* To avoid duplicate auth_failed events to user space we check | 3892 | /* To avoid duplicate auth_failed events to user space we check |
| 3757 | * the HCI_CONN_AUTH_PEND flag which will be set if we | 3893 | * the HCI_CONN_AUTH_PEND flag which will be set if we |
| 3758 | * initiated the authentication. A traditional auth_complete | 3894 | * initiated the authentication. A traditional auth_complete |
| @@ -3967,16 +4103,23 @@ static void hci_disconn_phylink_complete_evt(struct hci_dev *hdev, | |||
| 3967 | static void hci_le_conn_complete_evt(struct hci_dev *hdev, struct sk_buff *skb) | 4103 | static void hci_le_conn_complete_evt(struct hci_dev *hdev, struct sk_buff *skb) |
| 3968 | { | 4104 | { |
| 3969 | struct hci_ev_le_conn_complete *ev = (void *) skb->data; | 4105 | struct hci_ev_le_conn_complete *ev = (void *) skb->data; |
| 4106 | struct hci_conn_params *params; | ||
| 3970 | struct hci_conn *conn; | 4107 | struct hci_conn *conn; |
| 3971 | struct smp_irk *irk; | 4108 | struct smp_irk *irk; |
| 4109 | u8 addr_type; | ||
| 3972 | 4110 | ||
| 3973 | BT_DBG("%s status 0x%2.2x", hdev->name, ev->status); | 4111 | BT_DBG("%s status 0x%2.2x", hdev->name, ev->status); |
| 3974 | 4112 | ||
| 3975 | hci_dev_lock(hdev); | 4113 | hci_dev_lock(hdev); |
| 3976 | 4114 | ||
| 4115 | /* All controllers implicitly stop advertising in the event of a | ||
| 4116 | * connection, so ensure that the state bit is cleared. | ||
| 4117 | */ | ||
| 4118 | clear_bit(HCI_LE_ADV, &hdev->dev_flags); | ||
| 4119 | |||
| 3977 | conn = hci_conn_hash_lookup_state(hdev, LE_LINK, BT_CONNECT); | 4120 | conn = hci_conn_hash_lookup_state(hdev, LE_LINK, BT_CONNECT); |
| 3978 | if (!conn) { | 4121 | if (!conn) { |
| 3979 | conn = hci_conn_add(hdev, LE_LINK, &ev->bdaddr); | 4122 | conn = hci_conn_add(hdev, LE_LINK, &ev->bdaddr, ev->role); |
| 3980 | if (!conn) { | 4123 | if (!conn) { |
| 3981 | BT_ERR("No memory for new connection"); | 4124 | BT_ERR("No memory for new connection"); |
| 3982 | goto unlock; | 4125 | goto unlock; |
| @@ -3984,11 +4127,6 @@ static void hci_le_conn_complete_evt(struct hci_dev *hdev, struct sk_buff *skb) | |||
| 3984 | 4127 | ||
| 3985 | conn->dst_type = ev->bdaddr_type; | 4128 | conn->dst_type = ev->bdaddr_type; |
| 3986 | 4129 | ||
| 3987 | if (ev->role == LE_CONN_ROLE_MASTER) { | ||
| 3988 | conn->out = true; | ||
| 3989 | conn->link_mode |= HCI_LM_MASTER; | ||
| 3990 | } | ||
| 3991 | |||
| 3992 | /* If we didn't have a hci_conn object previously | 4130 | /* If we didn't have a hci_conn object previously |
| 3993 | * but we're in master role this must be something | 4131 | * but we're in master role this must be something |
| 3994 | * initiated using a white list. Since white list based | 4132 | * initiated using a white list. Since white list based |
| @@ -4025,6 +4163,14 @@ static void hci_le_conn_complete_evt(struct hci_dev *hdev, struct sk_buff *skb) | |||
| 4025 | 4163 | ||
| 4026 | conn->init_addr_type = ev->bdaddr_type; | 4164 | conn->init_addr_type = ev->bdaddr_type; |
| 4027 | bacpy(&conn->init_addr, &ev->bdaddr); | 4165 | bacpy(&conn->init_addr, &ev->bdaddr); |
| 4166 | |||
| 4167 | /* For incoming connections, set the default minimum | ||
| 4168 | * and maximum connection interval. They will be used | ||
| 4169 | * to check if the parameters are in range and if not | ||
| 4170 | * trigger the connection update procedure. | ||
| 4171 | */ | ||
| 4172 | conn->le_conn_min_interval = hdev->le_conn_min_interval; | ||
| 4173 | conn->le_conn_max_interval = hdev->le_conn_max_interval; | ||
| 4028 | } | 4174 | } |
| 4029 | 4175 | ||
| 4030 | /* Lookup the identity address from the stored connection | 4176 | /* Lookup the identity address from the stored connection |
| @@ -4042,11 +4188,22 @@ static void hci_le_conn_complete_evt(struct hci_dev *hdev, struct sk_buff *skb) | |||
| 4042 | conn->dst_type = irk->addr_type; | 4188 | conn->dst_type = irk->addr_type; |
| 4043 | } | 4189 | } |
| 4044 | 4190 | ||
| 4191 | if (conn->dst_type == ADDR_LE_DEV_PUBLIC) | ||
| 4192 | addr_type = BDADDR_LE_PUBLIC; | ||
| 4193 | else | ||
| 4194 | addr_type = BDADDR_LE_RANDOM; | ||
| 4195 | |||
| 4045 | if (ev->status) { | 4196 | if (ev->status) { |
| 4046 | hci_le_conn_failed(conn, ev->status); | 4197 | hci_le_conn_failed(conn, ev->status); |
| 4047 | goto unlock; | 4198 | goto unlock; |
| 4048 | } | 4199 | } |
| 4049 | 4200 | ||
| 4201 | /* Drop the connection if the device is blocked */ | ||
| 4202 | if (hci_bdaddr_list_lookup(&hdev->blacklist, &conn->dst, addr_type)) { | ||
| 4203 | hci_conn_drop(conn); | ||
| 4204 | goto unlock; | ||
| 4205 | } | ||
| 4206 | |||
| 4050 | if (!test_and_set_bit(HCI_CONN_MGMT_CONNECTED, &conn->flags)) | 4207 | if (!test_and_set_bit(HCI_CONN_MGMT_CONNECTED, &conn->flags)) |
| 4051 | mgmt_device_connected(hdev, &conn->dst, conn->type, | 4208 | mgmt_device_connected(hdev, &conn->dst, conn->type, |
| 4052 | conn->dst_type, 0, NULL, 0, NULL); | 4209 | conn->dst_type, 0, NULL, 0, NULL); |
| @@ -4055,40 +4212,98 @@ static void hci_le_conn_complete_evt(struct hci_dev *hdev, struct sk_buff *skb) | |||
| 4055 | conn->handle = __le16_to_cpu(ev->handle); | 4212 | conn->handle = __le16_to_cpu(ev->handle); |
| 4056 | conn->state = BT_CONNECTED; | 4213 | conn->state = BT_CONNECTED; |
| 4057 | 4214 | ||
| 4058 | if (test_bit(HCI_6LOWPAN_ENABLED, &hdev->dev_flags)) | 4215 | conn->le_conn_interval = le16_to_cpu(ev->interval); |
| 4059 | set_bit(HCI_CONN_6LOWPAN, &conn->flags); | 4216 | conn->le_conn_latency = le16_to_cpu(ev->latency); |
| 4217 | conn->le_supv_timeout = le16_to_cpu(ev->supervision_timeout); | ||
| 4060 | 4218 | ||
| 4061 | hci_conn_add_sysfs(conn); | 4219 | hci_conn_add_sysfs(conn); |
| 4062 | 4220 | ||
| 4063 | hci_proto_connect_cfm(conn, ev->status); | 4221 | hci_proto_connect_cfm(conn, ev->status); |
| 4064 | 4222 | ||
| 4065 | hci_pend_le_conn_del(hdev, &conn->dst, conn->dst_type); | 4223 | params = hci_conn_params_lookup(hdev, &conn->dst, conn->dst_type); |
| 4224 | if (params) | ||
| 4225 | list_del_init(¶ms->action); | ||
| 4066 | 4226 | ||
| 4067 | unlock: | 4227 | unlock: |
| 4228 | hci_update_background_scan(hdev); | ||
| 4229 | hci_dev_unlock(hdev); | ||
| 4230 | } | ||
| 4231 | |||
| 4232 | static void hci_le_conn_update_complete_evt(struct hci_dev *hdev, | ||
| 4233 | struct sk_buff *skb) | ||
| 4234 | { | ||
| 4235 | struct hci_ev_le_conn_update_complete *ev = (void *) skb->data; | ||
| 4236 | struct hci_conn *conn; | ||
| 4237 | |||
| 4238 | BT_DBG("%s status 0x%2.2x", hdev->name, ev->status); | ||
| 4239 | |||
| 4240 | if (ev->status) | ||
| 4241 | return; | ||
| 4242 | |||
| 4243 | hci_dev_lock(hdev); | ||
| 4244 | |||
| 4245 | conn = hci_conn_hash_lookup_handle(hdev, __le16_to_cpu(ev->handle)); | ||
| 4246 | if (conn) { | ||
| 4247 | conn->le_conn_interval = le16_to_cpu(ev->interval); | ||
| 4248 | conn->le_conn_latency = le16_to_cpu(ev->latency); | ||
| 4249 | conn->le_supv_timeout = le16_to_cpu(ev->supervision_timeout); | ||
| 4250 | } | ||
| 4251 | |||
| 4068 | hci_dev_unlock(hdev); | 4252 | hci_dev_unlock(hdev); |
| 4069 | } | 4253 | } |
| 4070 | 4254 | ||
| 4071 | /* This function requires the caller holds hdev->lock */ | 4255 | /* This function requires the caller holds hdev->lock */ |
| 4072 | static void check_pending_le_conn(struct hci_dev *hdev, bdaddr_t *addr, | 4256 | static void check_pending_le_conn(struct hci_dev *hdev, bdaddr_t *addr, |
| 4073 | u8 addr_type) | 4257 | u8 addr_type, u8 adv_type) |
| 4074 | { | 4258 | { |
| 4075 | struct hci_conn *conn; | 4259 | struct hci_conn *conn; |
| 4076 | struct smp_irk *irk; | 4260 | struct hci_conn_params *params; |
| 4261 | |||
| 4262 | /* If the event is not connectable don't proceed further */ | ||
| 4263 | if (adv_type != LE_ADV_IND && adv_type != LE_ADV_DIRECT_IND) | ||
| 4264 | return; | ||
| 4077 | 4265 | ||
| 4078 | /* If this is a resolvable address, we should resolve it and then | 4266 | /* Ignore if the device is blocked */ |
| 4079 | * update address and address type variables. | 4267 | if (hci_bdaddr_list_lookup(&hdev->blacklist, addr, addr_type)) |
| 4268 | return; | ||
| 4269 | |||
| 4270 | /* Most controller will fail if we try to create new connections | ||
| 4271 | * while we have an existing one in slave role. | ||
| 4080 | */ | 4272 | */ |
| 4081 | irk = hci_get_irk(hdev, addr, addr_type); | 4273 | if (hdev->conn_hash.le_num_slave > 0) |
| 4082 | if (irk) { | 4274 | return; |
| 4083 | addr = &irk->bdaddr; | ||
| 4084 | addr_type = irk->addr_type; | ||
| 4085 | } | ||
| 4086 | 4275 | ||
| 4087 | if (!hci_pend_le_conn_lookup(hdev, addr, addr_type)) | 4276 | /* If we're not connectable only connect devices that we have in |
| 4277 | * our pend_le_conns list. | ||
| 4278 | */ | ||
| 4279 | params = hci_pend_le_action_lookup(&hdev->pend_le_conns, | ||
| 4280 | addr, addr_type); | ||
| 4281 | if (!params) | ||
| 4088 | return; | 4282 | return; |
| 4089 | 4283 | ||
| 4284 | switch (params->auto_connect) { | ||
| 4285 | case HCI_AUTO_CONN_DIRECT: | ||
| 4286 | /* Only devices advertising with ADV_DIRECT_IND are | ||
| 4287 | * triggering a connection attempt. This is allowing | ||
| 4288 | * incoming connections from slave devices. | ||
| 4289 | */ | ||
| 4290 | if (adv_type != LE_ADV_DIRECT_IND) | ||
| 4291 | return; | ||
| 4292 | break; | ||
| 4293 | case HCI_AUTO_CONN_ALWAYS: | ||
| 4294 | /* Devices advertising with ADV_IND or ADV_DIRECT_IND | ||
| 4295 | * are triggering a connection attempt. This means | ||
| 4296 | * that incoming connectioms from slave device are | ||
| 4297 | * accepted and also outgoing connections to slave | ||
| 4298 | * devices are established when found. | ||
| 4299 | */ | ||
| 4300 | break; | ||
| 4301 | default: | ||
| 4302 | return; | ||
| 4303 | } | ||
| 4304 | |||
| 4090 | conn = hci_connect_le(hdev, addr, addr_type, BT_SECURITY_LOW, | 4305 | conn = hci_connect_le(hdev, addr, addr_type, BT_SECURITY_LOW, |
| 4091 | HCI_AT_NO_BONDING); | 4306 | HCI_LE_AUTOCONN_TIMEOUT, HCI_ROLE_MASTER); |
| 4092 | if (!IS_ERR(conn)) | 4307 | if (!IS_ERR(conn)) |
| 4093 | return; | 4308 | return; |
| 4094 | 4309 | ||
| @@ -4109,15 +4324,62 @@ static void process_adv_report(struct hci_dev *hdev, u8 type, bdaddr_t *bdaddr, | |||
| 4109 | u8 bdaddr_type, s8 rssi, u8 *data, u8 len) | 4324 | u8 bdaddr_type, s8 rssi, u8 *data, u8 len) |
| 4110 | { | 4325 | { |
| 4111 | struct discovery_state *d = &hdev->discovery; | 4326 | struct discovery_state *d = &hdev->discovery; |
| 4327 | struct smp_irk *irk; | ||
| 4112 | bool match; | 4328 | bool match; |
| 4329 | u32 flags; | ||
| 4330 | |||
| 4331 | /* Check if we need to convert to identity address */ | ||
| 4332 | irk = hci_get_irk(hdev, bdaddr, bdaddr_type); | ||
| 4333 | if (irk) { | ||
| 4334 | bdaddr = &irk->bdaddr; | ||
| 4335 | bdaddr_type = irk->addr_type; | ||
| 4336 | } | ||
| 4113 | 4337 | ||
| 4114 | /* Passive scanning shouldn't trigger any device found events */ | 4338 | /* Check if we have been requested to connect to this device */ |
| 4339 | check_pending_le_conn(hdev, bdaddr, bdaddr_type, type); | ||
| 4340 | |||
| 4341 | /* Passive scanning shouldn't trigger any device found events, | ||
| 4342 | * except for devices marked as CONN_REPORT for which we do send | ||
| 4343 | * device found events. | ||
| 4344 | */ | ||
| 4115 | if (hdev->le_scan_type == LE_SCAN_PASSIVE) { | 4345 | if (hdev->le_scan_type == LE_SCAN_PASSIVE) { |
| 4116 | if (type == LE_ADV_IND || type == LE_ADV_DIRECT_IND) | 4346 | if (type == LE_ADV_DIRECT_IND) |
| 4117 | check_pending_le_conn(hdev, bdaddr, bdaddr_type); | 4347 | return; |
| 4348 | |||
| 4349 | if (!hci_pend_le_action_lookup(&hdev->pend_le_reports, | ||
| 4350 | bdaddr, bdaddr_type)) | ||
| 4351 | return; | ||
| 4352 | |||
| 4353 | if (type == LE_ADV_NONCONN_IND || type == LE_ADV_SCAN_IND) | ||
| 4354 | flags = MGMT_DEV_FOUND_NOT_CONNECTABLE; | ||
| 4355 | else | ||
| 4356 | flags = 0; | ||
| 4357 | mgmt_device_found(hdev, bdaddr, LE_LINK, bdaddr_type, NULL, | ||
| 4358 | rssi, flags, data, len, NULL, 0); | ||
| 4118 | return; | 4359 | return; |
| 4119 | } | 4360 | } |
| 4120 | 4361 | ||
| 4362 | /* When receiving non-connectable or scannable undirected | ||
| 4363 | * advertising reports, this means that the remote device is | ||
| 4364 | * not connectable and then clearly indicate this in the | ||
| 4365 | * device found event. | ||
| 4366 | * | ||
| 4367 | * When receiving a scan response, then there is no way to | ||
| 4368 | * know if the remote device is connectable or not. However | ||
| 4369 | * since scan responses are merged with a previously seen | ||
| 4370 | * advertising report, the flags field from that report | ||
| 4371 | * will be used. | ||
| 4372 | * | ||
| 4373 | * In the really unlikely case that a controller get confused | ||
| 4374 | * and just sends a scan response event, then it is marked as | ||
| 4375 | * not connectable as well. | ||
| 4376 | */ | ||
| 4377 | if (type == LE_ADV_NONCONN_IND || type == LE_ADV_SCAN_IND || | ||
| 4378 | type == LE_ADV_SCAN_RSP) | ||
| 4379 | flags = MGMT_DEV_FOUND_NOT_CONNECTABLE; | ||
| 4380 | else | ||
| 4381 | flags = 0; | ||
| 4382 | |||
| 4121 | /* If there's nothing pending either store the data from this | 4383 | /* If there's nothing pending either store the data from this |
| 4122 | * event or send an immediate device found event if the data | 4384 | * event or send an immediate device found event if the data |
| 4123 | * should not be stored for later. | 4385 | * should not be stored for later. |
| @@ -4128,12 +4390,12 @@ static void process_adv_report(struct hci_dev *hdev, u8 type, bdaddr_t *bdaddr, | |||
| 4128 | */ | 4390 | */ |
| 4129 | if (type == LE_ADV_IND || type == LE_ADV_SCAN_IND) { | 4391 | if (type == LE_ADV_IND || type == LE_ADV_SCAN_IND) { |
| 4130 | store_pending_adv_report(hdev, bdaddr, bdaddr_type, | 4392 | store_pending_adv_report(hdev, bdaddr, bdaddr_type, |
| 4131 | rssi, data, len); | 4393 | rssi, flags, data, len); |
| 4132 | return; | 4394 | return; |
| 4133 | } | 4395 | } |
| 4134 | 4396 | ||
| 4135 | mgmt_device_found(hdev, bdaddr, LE_LINK, bdaddr_type, NULL, | 4397 | mgmt_device_found(hdev, bdaddr, LE_LINK, bdaddr_type, NULL, |
| 4136 | rssi, 0, 1, data, len, NULL, 0); | 4398 | rssi, flags, data, len, NULL, 0); |
| 4137 | return; | 4399 | return; |
| 4138 | } | 4400 | } |
| 4139 | 4401 | ||
| @@ -4150,7 +4412,7 @@ static void process_adv_report(struct hci_dev *hdev, u8 type, bdaddr_t *bdaddr, | |||
| 4150 | if (!match) | 4412 | if (!match) |
| 4151 | mgmt_device_found(hdev, &d->last_adv_addr, LE_LINK, | 4413 | mgmt_device_found(hdev, &d->last_adv_addr, LE_LINK, |
| 4152 | d->last_adv_addr_type, NULL, | 4414 | d->last_adv_addr_type, NULL, |
| 4153 | d->last_adv_rssi, 0, 1, | 4415 | d->last_adv_rssi, d->last_adv_flags, |
| 4154 | d->last_adv_data, | 4416 | d->last_adv_data, |
| 4155 | d->last_adv_data_len, NULL, 0); | 4417 | d->last_adv_data_len, NULL, 0); |
| 4156 | 4418 | ||
| @@ -4159,7 +4421,7 @@ static void process_adv_report(struct hci_dev *hdev, u8 type, bdaddr_t *bdaddr, | |||
| 4159 | */ | 4421 | */ |
| 4160 | if (type == LE_ADV_IND || type == LE_ADV_SCAN_IND) { | 4422 | if (type == LE_ADV_IND || type == LE_ADV_SCAN_IND) { |
| 4161 | store_pending_adv_report(hdev, bdaddr, bdaddr_type, | 4423 | store_pending_adv_report(hdev, bdaddr, bdaddr_type, |
| 4162 | rssi, data, len); | 4424 | rssi, flags, data, len); |
| 4163 | return; | 4425 | return; |
| 4164 | } | 4426 | } |
| 4165 | 4427 | ||
| @@ -4168,7 +4430,7 @@ static void process_adv_report(struct hci_dev *hdev, u8 type, bdaddr_t *bdaddr, | |||
| 4168 | */ | 4430 | */ |
| 4169 | clear_pending_adv_report(hdev); | 4431 | clear_pending_adv_report(hdev); |
| 4170 | mgmt_device_found(hdev, bdaddr, LE_LINK, bdaddr_type, NULL, | 4432 | mgmt_device_found(hdev, bdaddr, LE_LINK, bdaddr_type, NULL, |
| 4171 | rssi, 0, 1, data, len, NULL, 0); | 4433 | rssi, flags, data, len, NULL, 0); |
| 4172 | return; | 4434 | return; |
| 4173 | } | 4435 | } |
| 4174 | 4436 | ||
| @@ -4177,8 +4439,8 @@ static void process_adv_report(struct hci_dev *hdev, u8 type, bdaddr_t *bdaddr, | |||
| 4177 | * sending a merged device found event. | 4439 | * sending a merged device found event. |
| 4178 | */ | 4440 | */ |
| 4179 | mgmt_device_found(hdev, &d->last_adv_addr, LE_LINK, | 4441 | mgmt_device_found(hdev, &d->last_adv_addr, LE_LINK, |
| 4180 | d->last_adv_addr_type, NULL, rssi, 0, 1, data, len, | 4442 | d->last_adv_addr_type, NULL, rssi, d->last_adv_flags, |
| 4181 | d->last_adv_data, d->last_adv_data_len); | 4443 | d->last_adv_data, d->last_adv_data_len, data, len); |
| 4182 | clear_pending_adv_report(hdev); | 4444 | clear_pending_adv_report(hdev); |
| 4183 | } | 4445 | } |
| 4184 | 4446 | ||
| @@ -4219,7 +4481,7 @@ static void hci_le_ltk_request_evt(struct hci_dev *hdev, struct sk_buff *skb) | |||
| 4219 | if (conn == NULL) | 4481 | if (conn == NULL) |
| 4220 | goto not_found; | 4482 | goto not_found; |
| 4221 | 4483 | ||
| 4222 | ltk = hci_find_ltk(hdev, ev->ediv, ev->rand, conn->out); | 4484 | ltk = hci_find_ltk(hdev, ev->ediv, ev->rand, conn->role); |
| 4223 | if (ltk == NULL) | 4485 | if (ltk == NULL) |
| 4224 | goto not_found; | 4486 | goto not_found; |
| 4225 | 4487 | ||
| @@ -4241,9 +4503,12 @@ static void hci_le_ltk_request_evt(struct hci_dev *hdev, struct sk_buff *skb) | |||
| 4241 | * distribute the keys. Later, security can be re-established | 4503 | * distribute the keys. Later, security can be re-established |
| 4242 | * using a distributed LTK. | 4504 | * using a distributed LTK. |
| 4243 | */ | 4505 | */ |
| 4244 | if (ltk->type == HCI_SMP_STK_SLAVE) { | 4506 | if (ltk->type == SMP_STK) { |
| 4507 | set_bit(HCI_CONN_STK_ENCRYPT, &conn->flags); | ||
| 4245 | list_del(<k->list); | 4508 | list_del(<k->list); |
| 4246 | kfree(ltk); | 4509 | kfree(ltk); |
| 4510 | } else { | ||
| 4511 | clear_bit(HCI_CONN_STK_ENCRYPT, &conn->flags); | ||
| 4247 | } | 4512 | } |
| 4248 | 4513 | ||
| 4249 | hci_dev_unlock(hdev); | 4514 | hci_dev_unlock(hdev); |
| @@ -4256,6 +4521,76 @@ not_found: | |||
| 4256 | hci_dev_unlock(hdev); | 4521 | hci_dev_unlock(hdev); |
| 4257 | } | 4522 | } |
| 4258 | 4523 | ||
| 4524 | static void send_conn_param_neg_reply(struct hci_dev *hdev, u16 handle, | ||
| 4525 | u8 reason) | ||
| 4526 | { | ||
| 4527 | struct hci_cp_le_conn_param_req_neg_reply cp; | ||
| 4528 | |||
| 4529 | cp.handle = cpu_to_le16(handle); | ||
| 4530 | cp.reason = reason; | ||
| 4531 | |||
| 4532 | hci_send_cmd(hdev, HCI_OP_LE_CONN_PARAM_REQ_NEG_REPLY, sizeof(cp), | ||
| 4533 | &cp); | ||
| 4534 | } | ||
| 4535 | |||
| 4536 | static void hci_le_remote_conn_param_req_evt(struct hci_dev *hdev, | ||
| 4537 | struct sk_buff *skb) | ||
| 4538 | { | ||
| 4539 | struct hci_ev_le_remote_conn_param_req *ev = (void *) skb->data; | ||
| 4540 | struct hci_cp_le_conn_param_req_reply cp; | ||
| 4541 | struct hci_conn *hcon; | ||
| 4542 | u16 handle, min, max, latency, timeout; | ||
| 4543 | |||
| 4544 | handle = le16_to_cpu(ev->handle); | ||
| 4545 | min = le16_to_cpu(ev->interval_min); | ||
| 4546 | max = le16_to_cpu(ev->interval_max); | ||
| 4547 | latency = le16_to_cpu(ev->latency); | ||
| 4548 | timeout = le16_to_cpu(ev->timeout); | ||
| 4549 | |||
| 4550 | hcon = hci_conn_hash_lookup_handle(hdev, handle); | ||
| 4551 | if (!hcon || hcon->state != BT_CONNECTED) | ||
| 4552 | return send_conn_param_neg_reply(hdev, handle, | ||
| 4553 | HCI_ERROR_UNKNOWN_CONN_ID); | ||
| 4554 | |||
| 4555 | if (hci_check_conn_params(min, max, latency, timeout)) | ||
| 4556 | return send_conn_param_neg_reply(hdev, handle, | ||
| 4557 | HCI_ERROR_INVALID_LL_PARAMS); | ||
| 4558 | |||
| 4559 | if (hcon->role == HCI_ROLE_MASTER) { | ||
| 4560 | struct hci_conn_params *params; | ||
| 4561 | u8 store_hint; | ||
| 4562 | |||
| 4563 | hci_dev_lock(hdev); | ||
| 4564 | |||
| 4565 | params = hci_conn_params_lookup(hdev, &hcon->dst, | ||
| 4566 | hcon->dst_type); | ||
| 4567 | if (params) { | ||
| 4568 | params->conn_min_interval = min; | ||
| 4569 | params->conn_max_interval = max; | ||
| 4570 | params->conn_latency = latency; | ||
| 4571 | params->supervision_timeout = timeout; | ||
| 4572 | store_hint = 0x01; | ||
| 4573 | } else{ | ||
| 4574 | store_hint = 0x00; | ||
| 4575 | } | ||
| 4576 | |||
| 4577 | hci_dev_unlock(hdev); | ||
| 4578 | |||
| 4579 | mgmt_new_conn_param(hdev, &hcon->dst, hcon->dst_type, | ||
| 4580 | store_hint, min, max, latency, timeout); | ||
| 4581 | } | ||
| 4582 | |||
| 4583 | cp.handle = ev->handle; | ||
| 4584 | cp.interval_min = ev->interval_min; | ||
| 4585 | cp.interval_max = ev->interval_max; | ||
| 4586 | cp.latency = ev->latency; | ||
| 4587 | cp.timeout = ev->timeout; | ||
| 4588 | cp.min_ce_len = 0; | ||
| 4589 | cp.max_ce_len = 0; | ||
| 4590 | |||
| 4591 | hci_send_cmd(hdev, HCI_OP_LE_CONN_PARAM_REQ_REPLY, sizeof(cp), &cp); | ||
| 4592 | } | ||
| 4593 | |||
| 4259 | static void hci_le_meta_evt(struct hci_dev *hdev, struct sk_buff *skb) | 4594 | static void hci_le_meta_evt(struct hci_dev *hdev, struct sk_buff *skb) |
| 4260 | { | 4595 | { |
| 4261 | struct hci_ev_le_meta *le_ev = (void *) skb->data; | 4596 | struct hci_ev_le_meta *le_ev = (void *) skb->data; |
| @@ -4267,6 +4602,10 @@ static void hci_le_meta_evt(struct hci_dev *hdev, struct sk_buff *skb) | |||
| 4267 | hci_le_conn_complete_evt(hdev, skb); | 4602 | hci_le_conn_complete_evt(hdev, skb); |
| 4268 | break; | 4603 | break; |
| 4269 | 4604 | ||
| 4605 | case HCI_EV_LE_CONN_UPDATE_COMPLETE: | ||
| 4606 | hci_le_conn_update_complete_evt(hdev, skb); | ||
| 4607 | break; | ||
| 4608 | |||
| 4270 | case HCI_EV_LE_ADVERTISING_REPORT: | 4609 | case HCI_EV_LE_ADVERTISING_REPORT: |
| 4271 | hci_le_adv_report_evt(hdev, skb); | 4610 | hci_le_adv_report_evt(hdev, skb); |
| 4272 | break; | 4611 | break; |
| @@ -4275,6 +4614,10 @@ static void hci_le_meta_evt(struct hci_dev *hdev, struct sk_buff *skb) | |||
| 4275 | hci_le_ltk_request_evt(hdev, skb); | 4614 | hci_le_ltk_request_evt(hdev, skb); |
| 4276 | break; | 4615 | break; |
| 4277 | 4616 | ||
| 4617 | case HCI_EV_LE_REMOTE_CONN_PARAM_REQ: | ||
| 4618 | hci_le_remote_conn_param_req_evt(hdev, skb); | ||
| 4619 | break; | ||
| 4620 | |||
| 4278 | default: | 4621 | default: |
| 4279 | break; | 4622 | break; |
| 4280 | } | 4623 | } |
| @@ -4306,7 +4649,7 @@ void hci_event_packet(struct hci_dev *hdev, struct sk_buff *skb) | |||
| 4306 | /* Received events are (currently) only needed when a request is | 4649 | /* Received events are (currently) only needed when a request is |
| 4307 | * ongoing so avoid unnecessary memory allocation. | 4650 | * ongoing so avoid unnecessary memory allocation. |
| 4308 | */ | 4651 | */ |
| 4309 | if (hdev->req_status == HCI_REQ_PEND) { | 4652 | if (hci_req_pending(hdev)) { |
| 4310 | kfree_skb(hdev->recv_evt); | 4653 | kfree_skb(hdev->recv_evt); |
| 4311 | hdev->recv_evt = skb_clone(skb, GFP_KERNEL); | 4654 | hdev->recv_evt = skb_clone(skb, GFP_KERNEL); |
| 4312 | } | 4655 | } |
diff --git a/net/bluetooth/hci_sock.c b/net/bluetooth/hci_sock.c index 80d25c150a65..115f149362ba 100644 --- a/net/bluetooth/hci_sock.c +++ b/net/bluetooth/hci_sock.c | |||
| @@ -35,13 +35,32 @@ static atomic_t monitor_promisc = ATOMIC_INIT(0); | |||
| 35 | 35 | ||
| 36 | /* ----- HCI socket interface ----- */ | 36 | /* ----- HCI socket interface ----- */ |
| 37 | 37 | ||
| 38 | /* Socket info */ | ||
| 39 | #define hci_pi(sk) ((struct hci_pinfo *) sk) | ||
| 40 | |||
| 41 | struct hci_pinfo { | ||
| 42 | struct bt_sock bt; | ||
| 43 | struct hci_dev *hdev; | ||
| 44 | struct hci_filter filter; | ||
| 45 | __u32 cmsg_mask; | ||
| 46 | unsigned short channel; | ||
| 47 | }; | ||
| 48 | |||
| 38 | static inline int hci_test_bit(int nr, void *addr) | 49 | static inline int hci_test_bit(int nr, void *addr) |
| 39 | { | 50 | { |
| 40 | return *((__u32 *) addr + (nr >> 5)) & ((__u32) 1 << (nr & 31)); | 51 | return *((__u32 *) addr + (nr >> 5)) & ((__u32) 1 << (nr & 31)); |
| 41 | } | 52 | } |
| 42 | 53 | ||
| 43 | /* Security filter */ | 54 | /* Security filter */ |
| 44 | static struct hci_sec_filter hci_sec_filter = { | 55 | #define HCI_SFLT_MAX_OGF 5 |
| 56 | |||
| 57 | struct hci_sec_filter { | ||
| 58 | __u32 type_mask; | ||
| 59 | __u32 event_mask[2]; | ||
| 60 | __u32 ocf_mask[HCI_SFLT_MAX_OGF + 1][4]; | ||
| 61 | }; | ||
| 62 | |||
| 63 | static const struct hci_sec_filter hci_sec_filter = { | ||
| 45 | /* Packet types */ | 64 | /* Packet types */ |
| 46 | 0x10, | 65 | 0x10, |
| 47 | /* Events */ | 66 | /* Events */ |
| @@ -481,7 +500,7 @@ static int hci_sock_blacklist_add(struct hci_dev *hdev, void __user *arg) | |||
| 481 | 500 | ||
| 482 | hci_dev_lock(hdev); | 501 | hci_dev_lock(hdev); |
| 483 | 502 | ||
| 484 | err = hci_blacklist_add(hdev, &bdaddr, BDADDR_BREDR); | 503 | err = hci_bdaddr_list_add(&hdev->blacklist, &bdaddr, BDADDR_BREDR); |
| 485 | 504 | ||
| 486 | hci_dev_unlock(hdev); | 505 | hci_dev_unlock(hdev); |
| 487 | 506 | ||
| @@ -498,7 +517,7 @@ static int hci_sock_blacklist_del(struct hci_dev *hdev, void __user *arg) | |||
| 498 | 517 | ||
| 499 | hci_dev_lock(hdev); | 518 | hci_dev_lock(hdev); |
| 500 | 519 | ||
| 501 | err = hci_blacklist_del(hdev, &bdaddr, BDADDR_BREDR); | 520 | err = hci_bdaddr_list_del(&hdev->blacklist, &bdaddr, BDADDR_BREDR); |
| 502 | 521 | ||
| 503 | hci_dev_unlock(hdev); | 522 | hci_dev_unlock(hdev); |
| 504 | 523 | ||
| @@ -517,6 +536,9 @@ static int hci_sock_bound_ioctl(struct sock *sk, unsigned int cmd, | |||
| 517 | if (test_bit(HCI_USER_CHANNEL, &hdev->dev_flags)) | 536 | if (test_bit(HCI_USER_CHANNEL, &hdev->dev_flags)) |
| 518 | return -EBUSY; | 537 | return -EBUSY; |
| 519 | 538 | ||
| 539 | if (test_bit(HCI_UNCONFIGURED, &hdev->dev_flags)) | ||
| 540 | return -EOPNOTSUPP; | ||
| 541 | |||
| 520 | if (hdev->dev_type != HCI_BREDR) | 542 | if (hdev->dev_type != HCI_BREDR) |
| 521 | return -EOPNOTSUPP; | 543 | return -EOPNOTSUPP; |
| 522 | 544 | ||
| @@ -690,7 +712,8 @@ static int hci_sock_bind(struct socket *sock, struct sockaddr *addr, | |||
| 690 | 712 | ||
| 691 | if (test_bit(HCI_UP, &hdev->flags) || | 713 | if (test_bit(HCI_UP, &hdev->flags) || |
| 692 | test_bit(HCI_INIT, &hdev->flags) || | 714 | test_bit(HCI_INIT, &hdev->flags) || |
| 693 | test_bit(HCI_SETUP, &hdev->dev_flags)) { | 715 | test_bit(HCI_SETUP, &hdev->dev_flags) || |
| 716 | test_bit(HCI_CONFIG, &hdev->dev_flags)) { | ||
| 694 | err = -EBUSY; | 717 | err = -EBUSY; |
| 695 | hci_dev_put(hdev); | 718 | hci_dev_put(hdev); |
| 696 | goto done; | 719 | goto done; |
| @@ -960,7 +983,7 @@ static int hci_sock_sendmsg(struct kiocb *iocb, struct socket *sock, | |||
| 960 | goto drop; | 983 | goto drop; |
| 961 | } | 984 | } |
| 962 | 985 | ||
| 963 | if (test_bit(HCI_RAW, &hdev->flags) || (ogf == 0x3f)) { | 986 | if (ogf == 0x3f) { |
| 964 | skb_queue_tail(&hdev->raw_q, skb); | 987 | skb_queue_tail(&hdev->raw_q, skb); |
| 965 | queue_work(hdev->workqueue, &hdev->tx_work); | 988 | queue_work(hdev->workqueue, &hdev->tx_work); |
| 966 | } else { | 989 | } else { |
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, | |||
| 154 | (!!test_bit(LED_COMPOSE, dev->led) << 3) | | 154 | (!!test_bit(LED_COMPOSE, dev->led) << 3) | |
| 155 | (!!test_bit(LED_SCROLLL, dev->led) << 2) | | 155 | (!!test_bit(LED_SCROLLL, dev->led) << 2) | |
| 156 | (!!test_bit(LED_CAPSL, dev->led) << 1) | | 156 | (!!test_bit(LED_CAPSL, dev->led) << 1) | |
| 157 | (!!test_bit(LED_NUML, dev->led)); | 157 | (!!test_bit(LED_NUML, dev->led) << 0); |
| 158 | 158 | ||
| 159 | if (session->leds == newleds) | 159 | if (session->leds == newleds) |
| 160 | return 0; | 160 | return 0; |
diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c index 323f23cd2c37..46547b920f88 100644 --- a/net/bluetooth/l2cap_core.c +++ b/net/bluetooth/l2cap_core.c | |||
| @@ -40,14 +40,13 @@ | |||
| 40 | #include "smp.h" | 40 | #include "smp.h" |
| 41 | #include "a2mp.h" | 41 | #include "a2mp.h" |
| 42 | #include "amp.h" | 42 | #include "amp.h" |
| 43 | #include "6lowpan.h" | ||
| 44 | 43 | ||
| 45 | #define LE_FLOWCTL_MAX_CREDITS 65535 | 44 | #define LE_FLOWCTL_MAX_CREDITS 65535 |
| 46 | 45 | ||
| 47 | bool disable_ertm; | 46 | bool disable_ertm; |
| 48 | 47 | ||
| 49 | static u32 l2cap_feat_mask = L2CAP_FEAT_FIXED_CHAN | L2CAP_FEAT_UCD; | 48 | static u32 l2cap_feat_mask = L2CAP_FEAT_FIXED_CHAN | L2CAP_FEAT_UCD; |
| 50 | static u8 l2cap_fixed_chan[8] = { L2CAP_FC_L2CAP | L2CAP_FC_CONNLESS, }; | 49 | static u8 l2cap_fixed_chan[8] = { L2CAP_FC_SIG_BREDR | L2CAP_FC_CONNLESS, }; |
| 51 | 50 | ||
| 52 | static LIST_HEAD(chan_list); | 51 | static LIST_HEAD(chan_list); |
| 53 | static DEFINE_RWLOCK(chan_list_lock); | 52 | static DEFINE_RWLOCK(chan_list_lock); |
| @@ -205,6 +204,7 @@ done: | |||
| 205 | write_unlock(&chan_list_lock); | 204 | write_unlock(&chan_list_lock); |
| 206 | return err; | 205 | return err; |
| 207 | } | 206 | } |
| 207 | EXPORT_SYMBOL_GPL(l2cap_add_psm); | ||
| 208 | 208 | ||
| 209 | int l2cap_add_scid(struct l2cap_chan *chan, __u16 scid) | 209 | int l2cap_add_scid(struct l2cap_chan *chan, __u16 scid) |
| 210 | { | 210 | { |
| @@ -437,6 +437,7 @@ struct l2cap_chan *l2cap_chan_create(void) | |||
| 437 | 437 | ||
| 438 | return chan; | 438 | return chan; |
| 439 | } | 439 | } |
| 440 | EXPORT_SYMBOL_GPL(l2cap_chan_create); | ||
| 440 | 441 | ||
| 441 | static void l2cap_chan_destroy(struct kref *kref) | 442 | static void l2cap_chan_destroy(struct kref *kref) |
| 442 | { | 443 | { |
| @@ -464,6 +465,7 @@ void l2cap_chan_put(struct l2cap_chan *c) | |||
| 464 | 465 | ||
| 465 | kref_put(&c->kref, l2cap_chan_destroy); | 466 | kref_put(&c->kref, l2cap_chan_destroy); |
| 466 | } | 467 | } |
| 468 | EXPORT_SYMBOL_GPL(l2cap_chan_put); | ||
| 467 | 469 | ||
| 468 | void l2cap_chan_set_defaults(struct l2cap_chan *chan) | 470 | void l2cap_chan_set_defaults(struct l2cap_chan *chan) |
| 469 | { | 471 | { |
| @@ -482,6 +484,7 @@ void l2cap_chan_set_defaults(struct l2cap_chan *chan) | |||
| 482 | 484 | ||
| 483 | set_bit(FLAG_FORCE_ACTIVE, &chan->flags); | 485 | set_bit(FLAG_FORCE_ACTIVE, &chan->flags); |
| 484 | } | 486 | } |
| 487 | EXPORT_SYMBOL_GPL(l2cap_chan_set_defaults); | ||
| 485 | 488 | ||
| 486 | static void l2cap_le_flowctl_init(struct l2cap_chan *chan) | 489 | static void l2cap_le_flowctl_init(struct l2cap_chan *chan) |
| 487 | { | 490 | { |
| @@ -614,6 +617,7 @@ void l2cap_chan_del(struct l2cap_chan *chan, int err) | |||
| 614 | 617 | ||
| 615 | return; | 618 | return; |
| 616 | } | 619 | } |
| 620 | EXPORT_SYMBOL_GPL(l2cap_chan_del); | ||
| 617 | 621 | ||
| 618 | void l2cap_conn_update_id_addr(struct hci_conn *hcon) | 622 | void l2cap_conn_update_id_addr(struct hci_conn *hcon) |
| 619 | { | 623 | { |
| @@ -717,6 +721,7 @@ void l2cap_chan_close(struct l2cap_chan *chan, int reason) | |||
| 717 | break; | 721 | break; |
| 718 | } | 722 | } |
| 719 | } | 723 | } |
| 724 | EXPORT_SYMBOL(l2cap_chan_close); | ||
| 720 | 725 | ||
| 721 | static inline u8 l2cap_get_auth_type(struct l2cap_chan *chan) | 726 | static inline u8 l2cap_get_auth_type(struct l2cap_chan *chan) |
| 722 | { | 727 | { |
| @@ -770,7 +775,7 @@ static inline u8 l2cap_get_auth_type(struct l2cap_chan *chan) | |||
| 770 | } | 775 | } |
| 771 | 776 | ||
| 772 | /* Service level security */ | 777 | /* Service level security */ |
| 773 | int l2cap_chan_check_security(struct l2cap_chan *chan) | 778 | int l2cap_chan_check_security(struct l2cap_chan *chan, bool initiator) |
| 774 | { | 779 | { |
| 775 | struct l2cap_conn *conn = chan->conn; | 780 | struct l2cap_conn *conn = chan->conn; |
| 776 | __u8 auth_type; | 781 | __u8 auth_type; |
| @@ -780,7 +785,8 @@ int l2cap_chan_check_security(struct l2cap_chan *chan) | |||
| 780 | 785 | ||
| 781 | auth_type = l2cap_get_auth_type(chan); | 786 | auth_type = l2cap_get_auth_type(chan); |
| 782 | 787 | ||
| 783 | return hci_conn_security(conn->hcon, chan->sec_level, auth_type); | 788 | return hci_conn_security(conn->hcon, chan->sec_level, auth_type, |
| 789 | initiator); | ||
| 784 | } | 790 | } |
| 785 | 791 | ||
| 786 | static u8 l2cap_get_ident(struct l2cap_conn *conn) | 792 | static u8 l2cap_get_ident(struct l2cap_conn *conn) |
| @@ -793,14 +799,14 @@ static u8 l2cap_get_ident(struct l2cap_conn *conn) | |||
| 793 | * 200 - 254 are used by utilities like l2ping, etc. | 799 | * 200 - 254 are used by utilities like l2ping, etc. |
| 794 | */ | 800 | */ |
| 795 | 801 | ||
| 796 | spin_lock(&conn->lock); | 802 | mutex_lock(&conn->ident_lock); |
| 797 | 803 | ||
| 798 | if (++conn->tx_ident > 128) | 804 | if (++conn->tx_ident > 128) |
| 799 | conn->tx_ident = 1; | 805 | conn->tx_ident = 1; |
| 800 | 806 | ||
| 801 | id = conn->tx_ident; | 807 | id = conn->tx_ident; |
| 802 | 808 | ||
| 803 | spin_unlock(&conn->lock); | 809 | mutex_unlock(&conn->ident_lock); |
| 804 | 810 | ||
| 805 | return id; | 811 | return id; |
| 806 | } | 812 | } |
| @@ -1273,7 +1279,7 @@ static void l2cap_do_start(struct l2cap_chan *chan) | |||
| 1273 | if (!(conn->info_state & L2CAP_INFO_FEAT_MASK_REQ_DONE)) | 1279 | if (!(conn->info_state & L2CAP_INFO_FEAT_MASK_REQ_DONE)) |
| 1274 | return; | 1280 | return; |
| 1275 | 1281 | ||
| 1276 | if (l2cap_chan_check_security(chan) && | 1282 | if (l2cap_chan_check_security(chan, true) && |
| 1277 | __l2cap_no_conn_pending(chan)) { | 1283 | __l2cap_no_conn_pending(chan)) { |
| 1278 | l2cap_start_connection(chan); | 1284 | l2cap_start_connection(chan); |
| 1279 | } | 1285 | } |
| @@ -1352,7 +1358,7 @@ static void l2cap_conn_start(struct l2cap_conn *conn) | |||
| 1352 | } | 1358 | } |
| 1353 | 1359 | ||
| 1354 | if (chan->state == BT_CONNECT) { | 1360 | if (chan->state == BT_CONNECT) { |
| 1355 | if (!l2cap_chan_check_security(chan) || | 1361 | if (!l2cap_chan_check_security(chan, true) || |
| 1356 | !__l2cap_no_conn_pending(chan)) { | 1362 | !__l2cap_no_conn_pending(chan)) { |
| 1357 | l2cap_chan_unlock(chan); | 1363 | l2cap_chan_unlock(chan); |
| 1358 | continue; | 1364 | continue; |
| @@ -1374,7 +1380,7 @@ static void l2cap_conn_start(struct l2cap_conn *conn) | |||
| 1374 | rsp.scid = cpu_to_le16(chan->dcid); | 1380 | rsp.scid = cpu_to_le16(chan->dcid); |
| 1375 | rsp.dcid = cpu_to_le16(chan->scid); | 1381 | rsp.dcid = cpu_to_le16(chan->scid); |
| 1376 | 1382 | ||
| 1377 | if (l2cap_chan_check_security(chan)) { | 1383 | if (l2cap_chan_check_security(chan, false)) { |
| 1378 | if (test_bit(FLAG_DEFER_SETUP, &chan->flags)) { | 1384 | if (test_bit(FLAG_DEFER_SETUP, &chan->flags)) { |
| 1379 | rsp.result = cpu_to_le16(L2CAP_CR_PEND); | 1385 | rsp.result = cpu_to_le16(L2CAP_CR_PEND); |
| 1380 | rsp.status = cpu_to_le16(L2CAP_CS_AUTHOR_PEND); | 1386 | rsp.status = cpu_to_le16(L2CAP_CS_AUTHOR_PEND); |
| @@ -1455,13 +1461,12 @@ static struct l2cap_chan *l2cap_global_chan_by_scid(int state, u16 cid, | |||
| 1455 | static void l2cap_le_conn_ready(struct l2cap_conn *conn) | 1461 | static void l2cap_le_conn_ready(struct l2cap_conn *conn) |
| 1456 | { | 1462 | { |
| 1457 | struct hci_conn *hcon = conn->hcon; | 1463 | struct hci_conn *hcon = conn->hcon; |
| 1464 | struct hci_dev *hdev = hcon->hdev; | ||
| 1458 | struct l2cap_chan *chan, *pchan; | 1465 | struct l2cap_chan *chan, *pchan; |
| 1459 | u8 dst_type; | 1466 | u8 dst_type; |
| 1460 | 1467 | ||
| 1461 | BT_DBG(""); | 1468 | BT_DBG(""); |
| 1462 | 1469 | ||
| 1463 | bt_6lowpan_add_conn(conn); | ||
| 1464 | |||
| 1465 | /* Check if we have socket listening on cid */ | 1470 | /* Check if we have socket listening on cid */ |
| 1466 | pchan = l2cap_global_chan_by_scid(BT_LISTEN, L2CAP_CID_ATT, | 1471 | pchan = l2cap_global_chan_by_scid(BT_LISTEN, L2CAP_CID_ATT, |
| 1467 | &hcon->src, &hcon->dst); | 1472 | &hcon->src, &hcon->dst); |
| @@ -1475,9 +1480,28 @@ static void l2cap_le_conn_ready(struct l2cap_conn *conn) | |||
| 1475 | dst_type = bdaddr_type(hcon, hcon->dst_type); | 1480 | dst_type = bdaddr_type(hcon, hcon->dst_type); |
| 1476 | 1481 | ||
| 1477 | /* If device is blocked, do not create a channel for it */ | 1482 | /* If device is blocked, do not create a channel for it */ |
| 1478 | if (hci_blacklist_lookup(hcon->hdev, &hcon->dst, dst_type)) | 1483 | if (hci_bdaddr_list_lookup(&hdev->blacklist, &hcon->dst, dst_type)) |
| 1479 | return; | 1484 | return; |
| 1480 | 1485 | ||
| 1486 | /* For LE slave connections, make sure the connection interval | ||
| 1487 | * is in the range of the minium and maximum interval that has | ||
| 1488 | * been configured for this connection. If not, then trigger | ||
| 1489 | * the connection update procedure. | ||
| 1490 | */ | ||
| 1491 | if (hcon->role == HCI_ROLE_SLAVE && | ||
| 1492 | (hcon->le_conn_interval < hcon->le_conn_min_interval || | ||
| 1493 | hcon->le_conn_interval > hcon->le_conn_max_interval)) { | ||
| 1494 | struct l2cap_conn_param_update_req req; | ||
| 1495 | |||
| 1496 | req.min = cpu_to_le16(hcon->le_conn_min_interval); | ||
| 1497 | req.max = cpu_to_le16(hcon->le_conn_max_interval); | ||
| 1498 | req.latency = cpu_to_le16(hcon->le_conn_latency); | ||
| 1499 | req.to_multiplier = cpu_to_le16(hcon->le_supv_timeout); | ||
| 1500 | |||
| 1501 | l2cap_send_cmd(conn, l2cap_get_ident(conn), | ||
| 1502 | L2CAP_CONN_PARAM_UPDATE_REQ, sizeof(req), &req); | ||
| 1503 | } | ||
| 1504 | |||
| 1481 | l2cap_chan_lock(pchan); | 1505 | l2cap_chan_lock(pchan); |
| 1482 | 1506 | ||
| 1483 | chan = pchan->ops->new_connection(pchan); | 1507 | chan = pchan->ops->new_connection(pchan); |
| @@ -2118,7 +2142,8 @@ static inline int l2cap_skbuff_fromiovec(struct l2cap_chan *chan, | |||
| 2118 | struct sk_buff **frag; | 2142 | struct sk_buff **frag; |
| 2119 | int sent = 0; | 2143 | int sent = 0; |
| 2120 | 2144 | ||
| 2121 | if (memcpy_fromiovec(skb_put(skb, count), msg->msg_iov, count)) | 2145 | if (chan->ops->memcpy_fromiovec(chan, skb_put(skb, count), |
| 2146 | msg->msg_iov, count)) | ||
| 2122 | return -EFAULT; | 2147 | return -EFAULT; |
| 2123 | 2148 | ||
| 2124 | sent += count; | 2149 | sent += count; |
| @@ -2131,18 +2156,17 @@ static inline int l2cap_skbuff_fromiovec(struct l2cap_chan *chan, | |||
| 2131 | 2156 | ||
| 2132 | count = min_t(unsigned int, conn->mtu, len); | 2157 | count = min_t(unsigned int, conn->mtu, len); |
| 2133 | 2158 | ||
| 2134 | tmp = chan->ops->alloc_skb(chan, count, | 2159 | tmp = chan->ops->alloc_skb(chan, 0, count, |
| 2135 | msg->msg_flags & MSG_DONTWAIT); | 2160 | msg->msg_flags & MSG_DONTWAIT); |
| 2136 | if (IS_ERR(tmp)) | 2161 | if (IS_ERR(tmp)) |
| 2137 | return PTR_ERR(tmp); | 2162 | return PTR_ERR(tmp); |
| 2138 | 2163 | ||
| 2139 | *frag = tmp; | 2164 | *frag = tmp; |
| 2140 | 2165 | ||
| 2141 | if (memcpy_fromiovec(skb_put(*frag, count), msg->msg_iov, count)) | 2166 | if (chan->ops->memcpy_fromiovec(chan, skb_put(*frag, count), |
| 2167 | msg->msg_iov, count)) | ||
| 2142 | return -EFAULT; | 2168 | return -EFAULT; |
| 2143 | 2169 | ||
| 2144 | (*frag)->priority = skb->priority; | ||
| 2145 | |||
| 2146 | sent += count; | 2170 | sent += count; |
| 2147 | len -= count; | 2171 | len -= count; |
| 2148 | 2172 | ||
| @@ -2156,26 +2180,23 @@ static inline int l2cap_skbuff_fromiovec(struct l2cap_chan *chan, | |||
| 2156 | } | 2180 | } |
| 2157 | 2181 | ||
| 2158 | static struct sk_buff *l2cap_create_connless_pdu(struct l2cap_chan *chan, | 2182 | static struct sk_buff *l2cap_create_connless_pdu(struct l2cap_chan *chan, |
| 2159 | struct msghdr *msg, size_t len, | 2183 | struct msghdr *msg, size_t len) |
| 2160 | u32 priority) | ||
| 2161 | { | 2184 | { |
| 2162 | struct l2cap_conn *conn = chan->conn; | 2185 | struct l2cap_conn *conn = chan->conn; |
| 2163 | struct sk_buff *skb; | 2186 | struct sk_buff *skb; |
| 2164 | int err, count, hlen = L2CAP_HDR_SIZE + L2CAP_PSMLEN_SIZE; | 2187 | int err, count, hlen = L2CAP_HDR_SIZE + L2CAP_PSMLEN_SIZE; |
| 2165 | struct l2cap_hdr *lh; | 2188 | struct l2cap_hdr *lh; |
| 2166 | 2189 | ||
| 2167 | BT_DBG("chan %p psm 0x%2.2x len %zu priority %u", chan, | 2190 | BT_DBG("chan %p psm 0x%2.2x len %zu", chan, |
| 2168 | __le16_to_cpu(chan->psm), len, priority); | 2191 | __le16_to_cpu(chan->psm), len); |
| 2169 | 2192 | ||
| 2170 | count = min_t(unsigned int, (conn->mtu - hlen), len); | 2193 | count = min_t(unsigned int, (conn->mtu - hlen), len); |
| 2171 | 2194 | ||
| 2172 | skb = chan->ops->alloc_skb(chan, count + hlen, | 2195 | skb = chan->ops->alloc_skb(chan, hlen, count, |
| 2173 | msg->msg_flags & MSG_DONTWAIT); | 2196 | msg->msg_flags & MSG_DONTWAIT); |
| 2174 | if (IS_ERR(skb)) | 2197 | if (IS_ERR(skb)) |
| 2175 | return skb; | 2198 | return skb; |
| 2176 | 2199 | ||
| 2177 | skb->priority = priority; | ||
| 2178 | |||
| 2179 | /* Create L2CAP header */ | 2200 | /* Create L2CAP header */ |
| 2180 | lh = (struct l2cap_hdr *) skb_put(skb, L2CAP_HDR_SIZE); | 2201 | lh = (struct l2cap_hdr *) skb_put(skb, L2CAP_HDR_SIZE); |
| 2181 | lh->cid = cpu_to_le16(chan->dcid); | 2202 | lh->cid = cpu_to_le16(chan->dcid); |
| @@ -2191,8 +2212,7 @@ static struct sk_buff *l2cap_create_connless_pdu(struct l2cap_chan *chan, | |||
| 2191 | } | 2212 | } |
| 2192 | 2213 | ||
| 2193 | static struct sk_buff *l2cap_create_basic_pdu(struct l2cap_chan *chan, | 2214 | static struct sk_buff *l2cap_create_basic_pdu(struct l2cap_chan *chan, |
| 2194 | struct msghdr *msg, size_t len, | 2215 | struct msghdr *msg, size_t len) |
| 2195 | u32 priority) | ||
| 2196 | { | 2216 | { |
| 2197 | struct l2cap_conn *conn = chan->conn; | 2217 | struct l2cap_conn *conn = chan->conn; |
| 2198 | struct sk_buff *skb; | 2218 | struct sk_buff *skb; |
| @@ -2203,13 +2223,11 @@ static struct sk_buff *l2cap_create_basic_pdu(struct l2cap_chan *chan, | |||
| 2203 | 2223 | ||
| 2204 | count = min_t(unsigned int, (conn->mtu - L2CAP_HDR_SIZE), len); | 2224 | count = min_t(unsigned int, (conn->mtu - L2CAP_HDR_SIZE), len); |
| 2205 | 2225 | ||
| 2206 | skb = chan->ops->alloc_skb(chan, count + L2CAP_HDR_SIZE, | 2226 | skb = chan->ops->alloc_skb(chan, L2CAP_HDR_SIZE, count, |
| 2207 | msg->msg_flags & MSG_DONTWAIT); | 2227 | msg->msg_flags & MSG_DONTWAIT); |
| 2208 | if (IS_ERR(skb)) | 2228 | if (IS_ERR(skb)) |
| 2209 | return skb; | 2229 | return skb; |
| 2210 | 2230 | ||
| 2211 | skb->priority = priority; | ||
| 2212 | |||
| 2213 | /* Create L2CAP header */ | 2231 | /* Create L2CAP header */ |
| 2214 | lh = (struct l2cap_hdr *) skb_put(skb, L2CAP_HDR_SIZE); | 2232 | lh = (struct l2cap_hdr *) skb_put(skb, L2CAP_HDR_SIZE); |
| 2215 | lh->cid = cpu_to_le16(chan->dcid); | 2233 | lh->cid = cpu_to_le16(chan->dcid); |
| @@ -2247,7 +2265,7 @@ static struct sk_buff *l2cap_create_iframe_pdu(struct l2cap_chan *chan, | |||
| 2247 | 2265 | ||
| 2248 | count = min_t(unsigned int, (conn->mtu - hlen), len); | 2266 | count = min_t(unsigned int, (conn->mtu - hlen), len); |
| 2249 | 2267 | ||
| 2250 | skb = chan->ops->alloc_skb(chan, count + hlen, | 2268 | skb = chan->ops->alloc_skb(chan, hlen, count, |
| 2251 | msg->msg_flags & MSG_DONTWAIT); | 2269 | msg->msg_flags & MSG_DONTWAIT); |
| 2252 | if (IS_ERR(skb)) | 2270 | if (IS_ERR(skb)) |
| 2253 | return skb; | 2271 | return skb; |
| @@ -2368,7 +2386,7 @@ static struct sk_buff *l2cap_create_le_flowctl_pdu(struct l2cap_chan *chan, | |||
| 2368 | 2386 | ||
| 2369 | count = min_t(unsigned int, (conn->mtu - hlen), len); | 2387 | count = min_t(unsigned int, (conn->mtu - hlen), len); |
| 2370 | 2388 | ||
| 2371 | skb = chan->ops->alloc_skb(chan, count + hlen, | 2389 | skb = chan->ops->alloc_skb(chan, hlen, count, |
| 2372 | msg->msg_flags & MSG_DONTWAIT); | 2390 | msg->msg_flags & MSG_DONTWAIT); |
| 2373 | if (IS_ERR(skb)) | 2391 | if (IS_ERR(skb)) |
| 2374 | return skb; | 2392 | return skb; |
| @@ -2430,8 +2448,7 @@ static int l2cap_segment_le_sdu(struct l2cap_chan *chan, | |||
| 2430 | return 0; | 2448 | return 0; |
| 2431 | } | 2449 | } |
| 2432 | 2450 | ||
| 2433 | int l2cap_chan_send(struct l2cap_chan *chan, struct msghdr *msg, size_t len, | 2451 | int l2cap_chan_send(struct l2cap_chan *chan, struct msghdr *msg, size_t len) |
| 2434 | u32 priority) | ||
| 2435 | { | 2452 | { |
| 2436 | struct sk_buff *skb; | 2453 | struct sk_buff *skb; |
| 2437 | int err; | 2454 | int err; |
| @@ -2442,7 +2459,7 @@ int l2cap_chan_send(struct l2cap_chan *chan, struct msghdr *msg, size_t len, | |||
| 2442 | 2459 | ||
| 2443 | /* Connectionless channel */ | 2460 | /* Connectionless channel */ |
| 2444 | if (chan->chan_type == L2CAP_CHAN_CONN_LESS) { | 2461 | if (chan->chan_type == L2CAP_CHAN_CONN_LESS) { |
| 2445 | skb = l2cap_create_connless_pdu(chan, msg, len, priority); | 2462 | skb = l2cap_create_connless_pdu(chan, msg, len); |
| 2446 | if (IS_ERR(skb)) | 2463 | if (IS_ERR(skb)) |
| 2447 | return PTR_ERR(skb); | 2464 | return PTR_ERR(skb); |
| 2448 | 2465 | ||
| @@ -2499,7 +2516,7 @@ int l2cap_chan_send(struct l2cap_chan *chan, struct msghdr *msg, size_t len, | |||
| 2499 | return -EMSGSIZE; | 2516 | return -EMSGSIZE; |
| 2500 | 2517 | ||
| 2501 | /* Create a basic PDU */ | 2518 | /* Create a basic PDU */ |
| 2502 | skb = l2cap_create_basic_pdu(chan, msg, len, priority); | 2519 | skb = l2cap_create_basic_pdu(chan, msg, len); |
| 2503 | if (IS_ERR(skb)) | 2520 | if (IS_ERR(skb)) |
| 2504 | return PTR_ERR(skb); | 2521 | return PTR_ERR(skb); |
| 2505 | 2522 | ||
| @@ -2562,6 +2579,7 @@ int l2cap_chan_send(struct l2cap_chan *chan, struct msghdr *msg, size_t len, | |||
| 2562 | 2579 | ||
| 2563 | return err; | 2580 | return err; |
| 2564 | } | 2581 | } |
| 2582 | EXPORT_SYMBOL_GPL(l2cap_chan_send); | ||
| 2565 | 2583 | ||
| 2566 | static void l2cap_send_srej(struct l2cap_chan *chan, u16 txseq) | 2584 | static void l2cap_send_srej(struct l2cap_chan *chan, u16 txseq) |
| 2567 | { | 2585 | { |
| @@ -3217,6 +3235,9 @@ done: | |||
| 3217 | 3235 | ||
| 3218 | switch (chan->mode) { | 3236 | switch (chan->mode) { |
| 3219 | case L2CAP_MODE_BASIC: | 3237 | case L2CAP_MODE_BASIC: |
| 3238 | if (disable_ertm) | ||
| 3239 | break; | ||
| 3240 | |||
| 3220 | if (!(chan->conn->feat_mask & L2CAP_FEAT_ERTM) && | 3241 | if (!(chan->conn->feat_mask & L2CAP_FEAT_ERTM) && |
| 3221 | !(chan->conn->feat_mask & L2CAP_FEAT_STREAMING)) | 3242 | !(chan->conn->feat_mask & L2CAP_FEAT_STREAMING)) |
| 3222 | break; | 3243 | break; |
| @@ -3829,7 +3850,7 @@ static struct l2cap_chan *l2cap_connect(struct l2cap_conn *conn, | |||
| 3829 | chan->ident = cmd->ident; | 3850 | chan->ident = cmd->ident; |
| 3830 | 3851 | ||
| 3831 | if (conn->info_state & L2CAP_INFO_FEAT_MASK_REQ_DONE) { | 3852 | if (conn->info_state & L2CAP_INFO_FEAT_MASK_REQ_DONE) { |
| 3832 | if (l2cap_chan_check_security(chan)) { | 3853 | if (l2cap_chan_check_security(chan, false)) { |
| 3833 | if (test_bit(FLAG_DEFER_SETUP, &chan->flags)) { | 3854 | if (test_bit(FLAG_DEFER_SETUP, &chan->flags)) { |
| 3834 | l2cap_state_change(chan, BT_CONNECT2); | 3855 | l2cap_state_change(chan, BT_CONNECT2); |
| 3835 | result = L2CAP_CR_PEND; | 3856 | result = L2CAP_CR_PEND; |
| @@ -5197,27 +5218,6 @@ static inline int l2cap_move_channel_confirm_rsp(struct l2cap_conn *conn, | |||
| 5197 | return 0; | 5218 | return 0; |
| 5198 | } | 5219 | } |
| 5199 | 5220 | ||
| 5200 | static inline int l2cap_check_conn_param(u16 min, u16 max, u16 latency, | ||
| 5201 | u16 to_multiplier) | ||
| 5202 | { | ||
| 5203 | u16 max_latency; | ||
| 5204 | |||
| 5205 | if (min > max || min < 6 || max > 3200) | ||
| 5206 | return -EINVAL; | ||
| 5207 | |||
| 5208 | if (to_multiplier < 10 || to_multiplier > 3200) | ||
| 5209 | return -EINVAL; | ||
| 5210 | |||
| 5211 | if (max >= to_multiplier * 8) | ||
| 5212 | return -EINVAL; | ||
| 5213 | |||
| 5214 | max_latency = (to_multiplier * 8 / max) - 1; | ||
| 5215 | if (latency > 499 || latency > max_latency) | ||
| 5216 | return -EINVAL; | ||
| 5217 | |||
| 5218 | return 0; | ||
| 5219 | } | ||
| 5220 | |||
| 5221 | static inline int l2cap_conn_param_update_req(struct l2cap_conn *conn, | 5221 | static inline int l2cap_conn_param_update_req(struct l2cap_conn *conn, |
| 5222 | struct l2cap_cmd_hdr *cmd, | 5222 | struct l2cap_cmd_hdr *cmd, |
| 5223 | u16 cmd_len, u8 *data) | 5223 | u16 cmd_len, u8 *data) |
| @@ -5228,7 +5228,7 @@ static inline int l2cap_conn_param_update_req(struct l2cap_conn *conn, | |||
| 5228 | u16 min, max, latency, to_multiplier; | 5228 | u16 min, max, latency, to_multiplier; |
| 5229 | int err; | 5229 | int err; |
| 5230 | 5230 | ||
| 5231 | if (!(hcon->link_mode & HCI_LM_MASTER)) | 5231 | if (hcon->role != HCI_ROLE_MASTER) |
| 5232 | return -EINVAL; | 5232 | return -EINVAL; |
| 5233 | 5233 | ||
| 5234 | if (cmd_len != sizeof(struct l2cap_conn_param_update_req)) | 5234 | if (cmd_len != sizeof(struct l2cap_conn_param_update_req)) |
| @@ -5245,7 +5245,7 @@ static inline int l2cap_conn_param_update_req(struct l2cap_conn *conn, | |||
| 5245 | 5245 | ||
| 5246 | memset(&rsp, 0, sizeof(rsp)); | 5246 | memset(&rsp, 0, sizeof(rsp)); |
| 5247 | 5247 | ||
| 5248 | err = l2cap_check_conn_param(min, max, latency, to_multiplier); | 5248 | err = hci_check_conn_params(min, max, latency, to_multiplier); |
| 5249 | if (err) | 5249 | if (err) |
| 5250 | rsp.result = cpu_to_le16(L2CAP_CONN_PARAM_REJECTED); | 5250 | rsp.result = cpu_to_le16(L2CAP_CONN_PARAM_REJECTED); |
| 5251 | else | 5251 | else |
| @@ -5254,8 +5254,16 @@ static inline int l2cap_conn_param_update_req(struct l2cap_conn *conn, | |||
| 5254 | l2cap_send_cmd(conn, cmd->ident, L2CAP_CONN_PARAM_UPDATE_RSP, | 5254 | l2cap_send_cmd(conn, cmd->ident, L2CAP_CONN_PARAM_UPDATE_RSP, |
| 5255 | sizeof(rsp), &rsp); | 5255 | sizeof(rsp), &rsp); |
| 5256 | 5256 | ||
| 5257 | if (!err) | 5257 | if (!err) { |
| 5258 | hci_le_conn_update(hcon, min, max, latency, to_multiplier); | 5258 | u8 store_hint; |
| 5259 | |||
| 5260 | store_hint = hci_le_conn_update(hcon, min, max, latency, | ||
| 5261 | to_multiplier); | ||
| 5262 | mgmt_new_conn_param(hcon->hdev, &hcon->dst, hcon->dst_type, | ||
| 5263 | store_hint, min, max, latency, | ||
| 5264 | to_multiplier); | ||
| 5265 | |||
| 5266 | } | ||
| 5259 | 5267 | ||
| 5260 | return 0; | 5268 | return 0; |
| 5261 | } | 5269 | } |
| @@ -6879,9 +6887,6 @@ static void l2cap_att_channel(struct l2cap_conn *conn, | |||
| 6879 | 6887 | ||
| 6880 | BT_DBG("chan %p, len %d", chan, skb->len); | 6888 | BT_DBG("chan %p, len %d", chan, skb->len); |
| 6881 | 6889 | ||
| 6882 | if (hci_blacklist_lookup(hcon->hdev, &hcon->dst, hcon->dst_type)) | ||
| 6883 | goto drop; | ||
| 6884 | |||
| 6885 | if (chan->imtu < skb->len) | 6890 | if (chan->imtu < skb->len) |
| 6886 | goto drop; | 6891 | goto drop; |
| 6887 | 6892 | ||
| @@ -6914,6 +6919,16 @@ static void l2cap_recv_frame(struct l2cap_conn *conn, struct sk_buff *skb) | |||
| 6914 | return; | 6919 | return; |
| 6915 | } | 6920 | } |
| 6916 | 6921 | ||
| 6922 | /* Since we can't actively block incoming LE connections we must | ||
| 6923 | * at least ensure that we ignore incoming data from them. | ||
| 6924 | */ | ||
| 6925 | if (hcon->type == LE_LINK && | ||
| 6926 | hci_bdaddr_list_lookup(&hcon->hdev->blacklist, &hcon->dst, | ||
| 6927 | bdaddr_type(hcon, hcon->dst_type))) { | ||
| 6928 | kfree_skb(skb); | ||
| 6929 | return; | ||
| 6930 | } | ||
| 6931 | |||
| 6917 | BT_DBG("len %d, cid 0x%4.4x", len, cid); | 6932 | BT_DBG("len %d, cid 0x%4.4x", len, cid); |
| 6918 | 6933 | ||
| 6919 | switch (cid) { | 6934 | switch (cid) { |
| @@ -6940,10 +6955,6 @@ static void l2cap_recv_frame(struct l2cap_conn *conn, struct sk_buff *skb) | |||
| 6940 | l2cap_conn_del(conn->hcon, EACCES); | 6955 | l2cap_conn_del(conn->hcon, EACCES); |
| 6941 | break; | 6956 | break; |
| 6942 | 6957 | ||
| 6943 | case L2CAP_FC_6LOWPAN: | ||
| 6944 | bt_6lowpan_recv(conn, skb); | ||
| 6945 | break; | ||
| 6946 | |||
| 6947 | default: | 6958 | default: |
| 6948 | l2cap_data_channel(conn, cid, skb); | 6959 | l2cap_data_channel(conn, cid, skb); |
| 6949 | break; | 6960 | break; |
| @@ -6974,7 +6985,7 @@ static struct l2cap_conn *l2cap_conn_add(struct hci_conn *hcon) | |||
| 6974 | if (!hchan) | 6985 | if (!hchan) |
| 6975 | return NULL; | 6986 | return NULL; |
| 6976 | 6987 | ||
| 6977 | conn = kzalloc(sizeof(struct l2cap_conn), GFP_KERNEL); | 6988 | conn = kzalloc(sizeof(*conn), GFP_KERNEL); |
| 6978 | if (!conn) { | 6989 | if (!conn) { |
| 6979 | hci_chan_del(hchan); | 6990 | hci_chan_del(hchan); |
| 6980 | return NULL; | 6991 | return NULL; |
| @@ -7006,7 +7017,7 @@ static struct l2cap_conn *l2cap_conn_add(struct hci_conn *hcon) | |||
| 7006 | conn->hs_enabled = test_bit(HCI_HS_ENABLED, | 7017 | conn->hs_enabled = test_bit(HCI_HS_ENABLED, |
| 7007 | &hcon->hdev->dev_flags); | 7018 | &hcon->hdev->dev_flags); |
| 7008 | 7019 | ||
| 7009 | spin_lock_init(&conn->lock); | 7020 | mutex_init(&conn->ident_lock); |
| 7010 | mutex_init(&conn->chan_lock); | 7021 | mutex_init(&conn->chan_lock); |
| 7011 | 7022 | ||
| 7012 | INIT_LIST_HEAD(&conn->chan_l); | 7023 | INIT_LIST_HEAD(&conn->chan_l); |
| @@ -7042,7 +7053,6 @@ int l2cap_chan_connect(struct l2cap_chan *chan, __le16 psm, u16 cid, | |||
| 7042 | struct l2cap_conn *conn; | 7053 | struct l2cap_conn *conn; |
| 7043 | struct hci_conn *hcon; | 7054 | struct hci_conn *hcon; |
| 7044 | struct hci_dev *hdev; | 7055 | struct hci_dev *hdev; |
| 7045 | __u8 auth_type; | ||
| 7046 | int err; | 7056 | int err; |
| 7047 | 7057 | ||
| 7048 | BT_DBG("%pMR -> %pMR (type %u) psm 0x%2.2x", &chan->src, dst, | 7058 | BT_DBG("%pMR -> %pMR (type %u) psm 0x%2.2x", &chan->src, dst, |
| @@ -7084,7 +7094,7 @@ int l2cap_chan_connect(struct l2cap_chan *chan, __le16 psm, u16 cid, | |||
| 7084 | break; | 7094 | break; |
| 7085 | /* fall through */ | 7095 | /* fall through */ |
| 7086 | default: | 7096 | default: |
| 7087 | err = -ENOTSUPP; | 7097 | err = -EOPNOTSUPP; |
| 7088 | goto done; | 7098 | goto done; |
| 7089 | } | 7099 | } |
| 7090 | 7100 | ||
| @@ -7118,9 +7128,9 @@ int l2cap_chan_connect(struct l2cap_chan *chan, __le16 psm, u16 cid, | |||
| 7118 | chan->psm = psm; | 7128 | chan->psm = psm; |
| 7119 | chan->dcid = cid; | 7129 | chan->dcid = cid; |
| 7120 | 7130 | ||
| 7121 | auth_type = l2cap_get_auth_type(chan); | ||
| 7122 | |||
| 7123 | if (bdaddr_type_is_le(dst_type)) { | 7131 | if (bdaddr_type_is_le(dst_type)) { |
| 7132 | u8 role; | ||
| 7133 | |||
| 7124 | /* Convert from L2CAP channel address type to HCI address type | 7134 | /* Convert from L2CAP channel address type to HCI address type |
| 7125 | */ | 7135 | */ |
| 7126 | if (dst_type == BDADDR_LE_PUBLIC) | 7136 | if (dst_type == BDADDR_LE_PUBLIC) |
| @@ -7128,9 +7138,15 @@ int l2cap_chan_connect(struct l2cap_chan *chan, __le16 psm, u16 cid, | |||
| 7128 | else | 7138 | else |
| 7129 | dst_type = ADDR_LE_DEV_RANDOM; | 7139 | dst_type = ADDR_LE_DEV_RANDOM; |
| 7130 | 7140 | ||
| 7141 | if (test_bit(HCI_ADVERTISING, &hdev->dev_flags)) | ||
| 7142 | role = HCI_ROLE_SLAVE; | ||
| 7143 | else | ||
| 7144 | role = HCI_ROLE_MASTER; | ||
| 7145 | |||
| 7131 | hcon = hci_connect_le(hdev, dst, dst_type, chan->sec_level, | 7146 | hcon = hci_connect_le(hdev, dst, dst_type, chan->sec_level, |
| 7132 | auth_type); | 7147 | HCI_LE_CONN_TIMEOUT, role); |
| 7133 | } else { | 7148 | } else { |
| 7149 | u8 auth_type = l2cap_get_auth_type(chan); | ||
| 7134 | hcon = hci_connect_acl(hdev, dst, chan->sec_level, auth_type); | 7150 | hcon = hci_connect_acl(hdev, dst, chan->sec_level, auth_type); |
| 7135 | } | 7151 | } |
| 7136 | 7152 | ||
| @@ -7176,7 +7192,7 @@ int l2cap_chan_connect(struct l2cap_chan *chan, __le16 psm, u16 cid, | |||
| 7176 | if (hcon->state == BT_CONNECTED) { | 7192 | if (hcon->state == BT_CONNECTED) { |
| 7177 | if (chan->chan_type != L2CAP_CHAN_CONN_ORIENTED) { | 7193 | if (chan->chan_type != L2CAP_CHAN_CONN_ORIENTED) { |
| 7178 | __clear_chan_timer(chan); | 7194 | __clear_chan_timer(chan); |
| 7179 | if (l2cap_chan_check_security(chan)) | 7195 | if (l2cap_chan_check_security(chan, true)) |
| 7180 | l2cap_state_change(chan, BT_CONNECTED); | 7196 | l2cap_state_change(chan, BT_CONNECTED); |
| 7181 | } else | 7197 | } else |
| 7182 | l2cap_do_start(chan); | 7198 | l2cap_do_start(chan); |
| @@ -7190,6 +7206,7 @@ done: | |||
| 7190 | hci_dev_put(hdev); | 7206 | hci_dev_put(hdev); |
| 7191 | return err; | 7207 | return err; |
| 7192 | } | 7208 | } |
| 7209 | EXPORT_SYMBOL_GPL(l2cap_chan_connect); | ||
| 7193 | 7210 | ||
| 7194 | /* ---- L2CAP interface with lower layer (HCI) ---- */ | 7211 | /* ---- L2CAP interface with lower layer (HCI) ---- */ |
| 7195 | 7212 | ||
| @@ -7252,8 +7269,6 @@ void l2cap_disconn_cfm(struct hci_conn *hcon, u8 reason) | |||
| 7252 | { | 7269 | { |
| 7253 | BT_DBG("hcon %p reason %d", hcon, reason); | 7270 | BT_DBG("hcon %p reason %d", hcon, reason); |
| 7254 | 7271 | ||
| 7255 | bt_6lowpan_del_conn(hcon->l2cap_data); | ||
| 7256 | |||
| 7257 | l2cap_conn_del(hcon, bt_to_errno(reason)); | 7272 | l2cap_conn_del(hcon, bt_to_errno(reason)); |
| 7258 | } | 7273 | } |
| 7259 | 7274 | ||
| @@ -7536,14 +7551,11 @@ int __init l2cap_init(void) | |||
| 7536 | debugfs_create_u16("l2cap_le_default_mps", 0644, bt_debugfs, | 7551 | debugfs_create_u16("l2cap_le_default_mps", 0644, bt_debugfs, |
| 7537 | &le_default_mps); | 7552 | &le_default_mps); |
| 7538 | 7553 | ||
| 7539 | bt_6lowpan_init(); | ||
| 7540 | |||
| 7541 | return 0; | 7554 | return 0; |
| 7542 | } | 7555 | } |
| 7543 | 7556 | ||
| 7544 | void l2cap_exit(void) | 7557 | void l2cap_exit(void) |
| 7545 | { | 7558 | { |
| 7546 | bt_6lowpan_cleanup(); | ||
| 7547 | debugfs_remove(l2cap_debugfs); | 7559 | debugfs_remove(l2cap_debugfs); |
| 7548 | l2cap_cleanup_sockets(); | 7560 | l2cap_cleanup_sockets(); |
| 7549 | } | 7561 | } |
diff --git a/net/bluetooth/l2cap_sock.c b/net/bluetooth/l2cap_sock.c index e1378693cc90..1884f72083c2 100644 --- a/net/bluetooth/l2cap_sock.c +++ b/net/bluetooth/l2cap_sock.c | |||
| @@ -279,7 +279,7 @@ static int l2cap_sock_listen(struct socket *sock, int backlog) | |||
| 279 | break; | 279 | break; |
| 280 | /* fall through */ | 280 | /* fall through */ |
| 281 | default: | 281 | default: |
| 282 | err = -ENOTSUPP; | 282 | err = -EOPNOTSUPP; |
| 283 | goto done; | 283 | goto done; |
| 284 | } | 284 | } |
| 285 | 285 | ||
| @@ -361,7 +361,8 @@ static int l2cap_sock_getname(struct socket *sock, struct sockaddr *addr, | |||
| 361 | BT_DBG("sock %p, sk %p", sock, sk); | 361 | BT_DBG("sock %p, sk %p", sock, sk); |
| 362 | 362 | ||
| 363 | if (peer && sk->sk_state != BT_CONNECTED && | 363 | if (peer && sk->sk_state != BT_CONNECTED && |
| 364 | sk->sk_state != BT_CONNECT && sk->sk_state != BT_CONNECT2) | 364 | sk->sk_state != BT_CONNECT && sk->sk_state != BT_CONNECT2 && |
| 365 | sk->sk_state != BT_CONFIG) | ||
| 365 | return -ENOTCONN; | 366 | return -ENOTCONN; |
| 366 | 367 | ||
| 367 | memset(la, 0, sizeof(struct sockaddr_l2)); | 368 | memset(la, 0, sizeof(struct sockaddr_l2)); |
| @@ -796,7 +797,7 @@ static int l2cap_sock_setsockopt(struct socket *sock, int level, int optname, | |||
| 796 | } else if ((sk->sk_state == BT_CONNECT2 && | 797 | } else if ((sk->sk_state == BT_CONNECT2 && |
| 797 | test_bit(BT_SK_DEFER_SETUP, &bt_sk(sk)->flags)) || | 798 | test_bit(BT_SK_DEFER_SETUP, &bt_sk(sk)->flags)) || |
| 798 | sk->sk_state == BT_CONNECTED) { | 799 | sk->sk_state == BT_CONNECTED) { |
| 799 | if (!l2cap_chan_check_security(chan)) | 800 | if (!l2cap_chan_check_security(chan, true)) |
| 800 | set_bit(BT_SK_SUSPEND, &bt_sk(sk)->flags); | 801 | set_bit(BT_SK_SUSPEND, &bt_sk(sk)->flags); |
| 801 | else | 802 | else |
| 802 | sk->sk_state_change(sk); | 803 | sk->sk_state_change(sk); |
| @@ -964,7 +965,7 @@ static int l2cap_sock_sendmsg(struct kiocb *iocb, struct socket *sock, | |||
| 964 | return err; | 965 | return err; |
| 965 | 966 | ||
| 966 | l2cap_chan_lock(chan); | 967 | l2cap_chan_lock(chan); |
| 967 | err = l2cap_chan_send(chan, msg, len, sk->sk_priority); | 968 | err = l2cap_chan_send(chan, msg, len); |
| 968 | l2cap_chan_unlock(chan); | 969 | l2cap_chan_unlock(chan); |
| 969 | 970 | ||
| 970 | return err; | 971 | return err; |
| @@ -1111,7 +1112,8 @@ static int l2cap_sock_shutdown(struct socket *sock, int how) | |||
| 1111 | l2cap_chan_close(chan, 0); | 1112 | l2cap_chan_close(chan, 0); |
| 1112 | lock_sock(sk); | 1113 | lock_sock(sk); |
| 1113 | 1114 | ||
| 1114 | if (sock_flag(sk, SOCK_LINGER) && sk->sk_lingertime) | 1115 | if (sock_flag(sk, SOCK_LINGER) && sk->sk_lingertime && |
| 1116 | !(current->flags & PF_EXITING)) | ||
| 1115 | err = bt_sock_wait_state(sk, BT_CLOSED, | 1117 | err = bt_sock_wait_state(sk, BT_CLOSED, |
| 1116 | sk->sk_lingertime); | 1118 | sk->sk_lingertime); |
| 1117 | } | 1119 | } |
| @@ -1292,6 +1294,7 @@ static void l2cap_sock_state_change_cb(struct l2cap_chan *chan, int state, | |||
| 1292 | } | 1294 | } |
| 1293 | 1295 | ||
| 1294 | static struct sk_buff *l2cap_sock_alloc_skb_cb(struct l2cap_chan *chan, | 1296 | static struct sk_buff *l2cap_sock_alloc_skb_cb(struct l2cap_chan *chan, |
| 1297 | unsigned long hdr_len, | ||
| 1295 | unsigned long len, int nb) | 1298 | unsigned long len, int nb) |
| 1296 | { | 1299 | { |
| 1297 | struct sock *sk = chan->data; | 1300 | struct sock *sk = chan->data; |
| @@ -1299,17 +1302,26 @@ static struct sk_buff *l2cap_sock_alloc_skb_cb(struct l2cap_chan *chan, | |||
| 1299 | int err; | 1302 | int err; |
| 1300 | 1303 | ||
| 1301 | l2cap_chan_unlock(chan); | 1304 | l2cap_chan_unlock(chan); |
| 1302 | skb = bt_skb_send_alloc(sk, len, nb, &err); | 1305 | skb = bt_skb_send_alloc(sk, hdr_len + len, nb, &err); |
| 1303 | l2cap_chan_lock(chan); | 1306 | l2cap_chan_lock(chan); |
| 1304 | 1307 | ||
| 1305 | if (!skb) | 1308 | if (!skb) |
| 1306 | return ERR_PTR(err); | 1309 | return ERR_PTR(err); |
| 1307 | 1310 | ||
| 1311 | skb->priority = sk->sk_priority; | ||
| 1312 | |||
| 1308 | bt_cb(skb)->chan = chan; | 1313 | bt_cb(skb)->chan = chan; |
| 1309 | 1314 | ||
| 1310 | return skb; | 1315 | return skb; |
| 1311 | } | 1316 | } |
| 1312 | 1317 | ||
| 1318 | static int l2cap_sock_memcpy_fromiovec_cb(struct l2cap_chan *chan, | ||
| 1319 | unsigned char *kdata, | ||
| 1320 | struct iovec *iov, int len) | ||
| 1321 | { | ||
| 1322 | return memcpy_fromiovec(kdata, iov, len); | ||
| 1323 | } | ||
| 1324 | |||
| 1313 | static void l2cap_sock_ready_cb(struct l2cap_chan *chan) | 1325 | static void l2cap_sock_ready_cb(struct l2cap_chan *chan) |
| 1314 | { | 1326 | { |
| 1315 | struct sock *sk = chan->data; | 1327 | struct sock *sk = chan->data; |
| @@ -1375,20 +1387,21 @@ static void l2cap_sock_suspend_cb(struct l2cap_chan *chan) | |||
| 1375 | sk->sk_state_change(sk); | 1387 | sk->sk_state_change(sk); |
| 1376 | } | 1388 | } |
| 1377 | 1389 | ||
| 1378 | static struct l2cap_ops l2cap_chan_ops = { | 1390 | static const struct l2cap_ops l2cap_chan_ops = { |
| 1379 | .name = "L2CAP Socket Interface", | 1391 | .name = "L2CAP Socket Interface", |
| 1380 | .new_connection = l2cap_sock_new_connection_cb, | 1392 | .new_connection = l2cap_sock_new_connection_cb, |
| 1381 | .recv = l2cap_sock_recv_cb, | 1393 | .recv = l2cap_sock_recv_cb, |
| 1382 | .close = l2cap_sock_close_cb, | 1394 | .close = l2cap_sock_close_cb, |
| 1383 | .teardown = l2cap_sock_teardown_cb, | 1395 | .teardown = l2cap_sock_teardown_cb, |
| 1384 | .state_change = l2cap_sock_state_change_cb, | 1396 | .state_change = l2cap_sock_state_change_cb, |
| 1385 | .ready = l2cap_sock_ready_cb, | 1397 | .ready = l2cap_sock_ready_cb, |
| 1386 | .defer = l2cap_sock_defer_cb, | 1398 | .defer = l2cap_sock_defer_cb, |
| 1387 | .resume = l2cap_sock_resume_cb, | 1399 | .resume = l2cap_sock_resume_cb, |
| 1388 | .suspend = l2cap_sock_suspend_cb, | 1400 | .suspend = l2cap_sock_suspend_cb, |
| 1389 | .set_shutdown = l2cap_sock_set_shutdown_cb, | 1401 | .set_shutdown = l2cap_sock_set_shutdown_cb, |
| 1390 | .get_sndtimeo = l2cap_sock_get_sndtimeo_cb, | 1402 | .get_sndtimeo = l2cap_sock_get_sndtimeo_cb, |
| 1391 | .alloc_skb = l2cap_sock_alloc_skb_cb, | 1403 | .alloc_skb = l2cap_sock_alloc_skb_cb, |
| 1404 | .memcpy_fromiovec = l2cap_sock_memcpy_fromiovec_cb, | ||
| 1392 | }; | 1405 | }; |
| 1393 | 1406 | ||
| 1394 | static void l2cap_sock_destruct(struct sock *sk) | 1407 | static void l2cap_sock_destruct(struct sock *sk) |
diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index af8e0a6243b7..b8554d429d88 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c | |||
| @@ -35,7 +35,7 @@ | |||
| 35 | #include "smp.h" | 35 | #include "smp.h" |
| 36 | 36 | ||
| 37 | #define MGMT_VERSION 1 | 37 | #define MGMT_VERSION 1 |
| 38 | #define MGMT_REVISION 6 | 38 | #define MGMT_REVISION 7 |
| 39 | 39 | ||
| 40 | static const u16 mgmt_commands[] = { | 40 | static const u16 mgmt_commands[] = { |
| 41 | MGMT_OP_READ_INDEX_LIST, | 41 | MGMT_OP_READ_INDEX_LIST, |
| @@ -44,7 +44,7 @@ static const u16 mgmt_commands[] = { | |||
| 44 | MGMT_OP_SET_DISCOVERABLE, | 44 | MGMT_OP_SET_DISCOVERABLE, |
| 45 | MGMT_OP_SET_CONNECTABLE, | 45 | MGMT_OP_SET_CONNECTABLE, |
| 46 | MGMT_OP_SET_FAST_CONNECTABLE, | 46 | MGMT_OP_SET_FAST_CONNECTABLE, |
| 47 | MGMT_OP_SET_PAIRABLE, | 47 | MGMT_OP_SET_BONDABLE, |
| 48 | MGMT_OP_SET_LINK_SECURITY, | 48 | MGMT_OP_SET_LINK_SECURITY, |
| 49 | MGMT_OP_SET_SSP, | 49 | MGMT_OP_SET_SSP, |
| 50 | MGMT_OP_SET_HS, | 50 | MGMT_OP_SET_HS, |
| @@ -85,6 +85,14 @@ static const u16 mgmt_commands[] = { | |||
| 85 | MGMT_OP_SET_PRIVACY, | 85 | MGMT_OP_SET_PRIVACY, |
| 86 | MGMT_OP_LOAD_IRKS, | 86 | MGMT_OP_LOAD_IRKS, |
| 87 | MGMT_OP_GET_CONN_INFO, | 87 | MGMT_OP_GET_CONN_INFO, |
| 88 | MGMT_OP_GET_CLOCK_INFO, | ||
| 89 | MGMT_OP_ADD_DEVICE, | ||
| 90 | MGMT_OP_REMOVE_DEVICE, | ||
| 91 | MGMT_OP_LOAD_CONN_PARAM, | ||
| 92 | MGMT_OP_READ_UNCONF_INDEX_LIST, | ||
| 93 | MGMT_OP_READ_CONFIG_INFO, | ||
| 94 | MGMT_OP_SET_EXTERNAL_CONFIG, | ||
| 95 | MGMT_OP_SET_PUBLIC_ADDRESS, | ||
| 88 | }; | 96 | }; |
| 89 | 97 | ||
| 90 | static const u16 mgmt_events[] = { | 98 | static const u16 mgmt_events[] = { |
| @@ -111,6 +119,12 @@ static const u16 mgmt_events[] = { | |||
| 111 | MGMT_EV_PASSKEY_NOTIFY, | 119 | MGMT_EV_PASSKEY_NOTIFY, |
| 112 | MGMT_EV_NEW_IRK, | 120 | MGMT_EV_NEW_IRK, |
| 113 | MGMT_EV_NEW_CSRK, | 121 | MGMT_EV_NEW_CSRK, |
| 122 | MGMT_EV_DEVICE_ADDED, | ||
| 123 | MGMT_EV_DEVICE_REMOVED, | ||
| 124 | MGMT_EV_NEW_CONN_PARAM, | ||
| 125 | MGMT_EV_UNCONF_INDEX_ADDED, | ||
| 126 | MGMT_EV_UNCONF_INDEX_REMOVED, | ||
| 127 | MGMT_EV_NEW_CONFIG_OPTIONS, | ||
| 114 | }; | 128 | }; |
| 115 | 129 | ||
| 116 | #define CACHE_TIMEOUT msecs_to_jiffies(2 * 1000) | 130 | #define CACHE_TIMEOUT msecs_to_jiffies(2 * 1000) |
| @@ -200,6 +214,36 @@ static u8 mgmt_status(u8 hci_status) | |||
| 200 | return MGMT_STATUS_FAILED; | 214 | return MGMT_STATUS_FAILED; |
| 201 | } | 215 | } |
| 202 | 216 | ||
| 217 | static int mgmt_event(u16 event, struct hci_dev *hdev, void *data, u16 data_len, | ||
| 218 | struct sock *skip_sk) | ||
| 219 | { | ||
| 220 | struct sk_buff *skb; | ||
| 221 | struct mgmt_hdr *hdr; | ||
| 222 | |||
| 223 | skb = alloc_skb(sizeof(*hdr) + data_len, GFP_KERNEL); | ||
| 224 | if (!skb) | ||
| 225 | return -ENOMEM; | ||
| 226 | |||
| 227 | hdr = (void *) skb_put(skb, sizeof(*hdr)); | ||
| 228 | hdr->opcode = cpu_to_le16(event); | ||
| 229 | if (hdev) | ||
| 230 | hdr->index = cpu_to_le16(hdev->id); | ||
| 231 | else | ||
| 232 | hdr->index = cpu_to_le16(MGMT_INDEX_NONE); | ||
| 233 | hdr->len = cpu_to_le16(data_len); | ||
| 234 | |||
| 235 | if (data) | ||
| 236 | memcpy(skb_put(skb, data_len), data, data_len); | ||
| 237 | |||
| 238 | /* Time stamp */ | ||
| 239 | __net_timestamp(skb); | ||
| 240 | |||
| 241 | hci_send_to_control(skb, skip_sk); | ||
| 242 | kfree_skb(skb); | ||
| 243 | |||
| 244 | return 0; | ||
| 245 | } | ||
| 246 | |||
| 203 | static int cmd_status(struct sock *sk, u16 index, u16 cmd, u8 status) | 247 | static int cmd_status(struct sock *sk, u16 index, u16 cmd, u8 status) |
| 204 | { | 248 | { |
| 205 | struct sk_buff *skb; | 249 | struct sk_buff *skb; |
| @@ -327,7 +371,8 @@ static int read_index_list(struct sock *sk, struct hci_dev *hdev, void *data, | |||
| 327 | 371 | ||
| 328 | count = 0; | 372 | count = 0; |
| 329 | list_for_each_entry(d, &hci_dev_list, list) { | 373 | list_for_each_entry(d, &hci_dev_list, list) { |
| 330 | if (d->dev_type == HCI_BREDR) | 374 | if (d->dev_type == HCI_BREDR && |
| 375 | !test_bit(HCI_UNCONFIGURED, &d->dev_flags)) | ||
| 331 | count++; | 376 | count++; |
| 332 | } | 377 | } |
| 333 | 378 | ||
| @@ -340,13 +385,19 @@ static int read_index_list(struct sock *sk, struct hci_dev *hdev, void *data, | |||
| 340 | 385 | ||
| 341 | count = 0; | 386 | count = 0; |
| 342 | list_for_each_entry(d, &hci_dev_list, list) { | 387 | list_for_each_entry(d, &hci_dev_list, list) { |
| 343 | if (test_bit(HCI_SETUP, &d->dev_flags)) | 388 | if (test_bit(HCI_SETUP, &d->dev_flags) || |
| 389 | test_bit(HCI_CONFIG, &d->dev_flags) || | ||
| 390 | test_bit(HCI_USER_CHANNEL, &d->dev_flags)) | ||
| 344 | continue; | 391 | continue; |
| 345 | 392 | ||
| 346 | if (test_bit(HCI_USER_CHANNEL, &d->dev_flags)) | 393 | /* Devices marked as raw-only are neither configured |
| 394 | * nor unconfigured controllers. | ||
| 395 | */ | ||
| 396 | if (test_bit(HCI_QUIRK_RAW_DEVICE, &d->quirks)) | ||
| 347 | continue; | 397 | continue; |
| 348 | 398 | ||
| 349 | if (d->dev_type == HCI_BREDR) { | 399 | if (d->dev_type == HCI_BREDR && |
| 400 | !test_bit(HCI_UNCONFIGURED, &d->dev_flags)) { | ||
| 350 | rp->index[count++] = cpu_to_le16(d->id); | 401 | rp->index[count++] = cpu_to_le16(d->id); |
| 351 | BT_DBG("Added hci%u", d->id); | 402 | BT_DBG("Added hci%u", d->id); |
| 352 | } | 403 | } |
| @@ -365,19 +416,151 @@ static int read_index_list(struct sock *sk, struct hci_dev *hdev, void *data, | |||
| 365 | return err; | 416 | return err; |
| 366 | } | 417 | } |
| 367 | 418 | ||
| 419 | static int read_unconf_index_list(struct sock *sk, struct hci_dev *hdev, | ||
| 420 | void *data, u16 data_len) | ||
| 421 | { | ||
| 422 | struct mgmt_rp_read_unconf_index_list *rp; | ||
| 423 | struct hci_dev *d; | ||
| 424 | size_t rp_len; | ||
| 425 | u16 count; | ||
| 426 | int err; | ||
| 427 | |||
| 428 | BT_DBG("sock %p", sk); | ||
| 429 | |||
| 430 | read_lock(&hci_dev_list_lock); | ||
| 431 | |||
| 432 | count = 0; | ||
| 433 | list_for_each_entry(d, &hci_dev_list, list) { | ||
| 434 | if (d->dev_type == HCI_BREDR && | ||
| 435 | test_bit(HCI_UNCONFIGURED, &d->dev_flags)) | ||
| 436 | count++; | ||
| 437 | } | ||
| 438 | |||
| 439 | rp_len = sizeof(*rp) + (2 * count); | ||
| 440 | rp = kmalloc(rp_len, GFP_ATOMIC); | ||
| 441 | if (!rp) { | ||
| 442 | read_unlock(&hci_dev_list_lock); | ||
| 443 | return -ENOMEM; | ||
| 444 | } | ||
| 445 | |||
| 446 | count = 0; | ||
| 447 | list_for_each_entry(d, &hci_dev_list, list) { | ||
| 448 | if (test_bit(HCI_SETUP, &d->dev_flags) || | ||
| 449 | test_bit(HCI_CONFIG, &d->dev_flags) || | ||
| 450 | test_bit(HCI_USER_CHANNEL, &d->dev_flags)) | ||
| 451 | continue; | ||
| 452 | |||
| 453 | /* Devices marked as raw-only are neither configured | ||
| 454 | * nor unconfigured controllers. | ||
| 455 | */ | ||
| 456 | if (test_bit(HCI_QUIRK_RAW_DEVICE, &d->quirks)) | ||
| 457 | continue; | ||
| 458 | |||
| 459 | if (d->dev_type == HCI_BREDR && | ||
| 460 | test_bit(HCI_UNCONFIGURED, &d->dev_flags)) { | ||
| 461 | rp->index[count++] = cpu_to_le16(d->id); | ||
| 462 | BT_DBG("Added hci%u", d->id); | ||
| 463 | } | ||
| 464 | } | ||
| 465 | |||
| 466 | rp->num_controllers = cpu_to_le16(count); | ||
| 467 | rp_len = sizeof(*rp) + (2 * count); | ||
| 468 | |||
| 469 | read_unlock(&hci_dev_list_lock); | ||
| 470 | |||
| 471 | err = cmd_complete(sk, MGMT_INDEX_NONE, MGMT_OP_READ_UNCONF_INDEX_LIST, | ||
| 472 | 0, rp, rp_len); | ||
| 473 | |||
| 474 | kfree(rp); | ||
| 475 | |||
| 476 | return err; | ||
| 477 | } | ||
| 478 | |||
| 479 | static bool is_configured(struct hci_dev *hdev) | ||
| 480 | { | ||
| 481 | if (test_bit(HCI_QUIRK_EXTERNAL_CONFIG, &hdev->quirks) && | ||
| 482 | !test_bit(HCI_EXT_CONFIGURED, &hdev->dev_flags)) | ||
| 483 | return false; | ||
| 484 | |||
| 485 | if (test_bit(HCI_QUIRK_INVALID_BDADDR, &hdev->quirks) && | ||
| 486 | !bacmp(&hdev->public_addr, BDADDR_ANY)) | ||
| 487 | return false; | ||
| 488 | |||
| 489 | return true; | ||
| 490 | } | ||
| 491 | |||
| 492 | static __le32 get_missing_options(struct hci_dev *hdev) | ||
| 493 | { | ||
| 494 | u32 options = 0; | ||
| 495 | |||
| 496 | if (test_bit(HCI_QUIRK_EXTERNAL_CONFIG, &hdev->quirks) && | ||
| 497 | !test_bit(HCI_EXT_CONFIGURED, &hdev->dev_flags)) | ||
| 498 | options |= MGMT_OPTION_EXTERNAL_CONFIG; | ||
| 499 | |||
| 500 | if (test_bit(HCI_QUIRK_INVALID_BDADDR, &hdev->quirks) && | ||
| 501 | !bacmp(&hdev->public_addr, BDADDR_ANY)) | ||
| 502 | options |= MGMT_OPTION_PUBLIC_ADDRESS; | ||
| 503 | |||
| 504 | return cpu_to_le32(options); | ||
| 505 | } | ||
| 506 | |||
| 507 | static int new_options(struct hci_dev *hdev, struct sock *skip) | ||
| 508 | { | ||
| 509 | __le32 options = get_missing_options(hdev); | ||
| 510 | |||
| 511 | return mgmt_event(MGMT_EV_NEW_CONFIG_OPTIONS, hdev, &options, | ||
| 512 | sizeof(options), skip); | ||
| 513 | } | ||
| 514 | |||
| 515 | static int send_options_rsp(struct sock *sk, u16 opcode, struct hci_dev *hdev) | ||
| 516 | { | ||
| 517 | __le32 options = get_missing_options(hdev); | ||
| 518 | |||
| 519 | return cmd_complete(sk, hdev->id, opcode, 0, &options, | ||
| 520 | sizeof(options)); | ||
| 521 | } | ||
| 522 | |||
| 523 | static int read_config_info(struct sock *sk, struct hci_dev *hdev, | ||
| 524 | void *data, u16 data_len) | ||
| 525 | { | ||
| 526 | struct mgmt_rp_read_config_info rp; | ||
| 527 | u32 options = 0; | ||
| 528 | |||
| 529 | BT_DBG("sock %p %s", sk, hdev->name); | ||
| 530 | |||
| 531 | hci_dev_lock(hdev); | ||
| 532 | |||
| 533 | memset(&rp, 0, sizeof(rp)); | ||
| 534 | rp.manufacturer = cpu_to_le16(hdev->manufacturer); | ||
| 535 | |||
| 536 | if (test_bit(HCI_QUIRK_EXTERNAL_CONFIG, &hdev->quirks)) | ||
| 537 | options |= MGMT_OPTION_EXTERNAL_CONFIG; | ||
| 538 | |||
| 539 | if (hdev->set_bdaddr) | ||
| 540 | options |= MGMT_OPTION_PUBLIC_ADDRESS; | ||
| 541 | |||
| 542 | rp.supported_options = cpu_to_le32(options); | ||
| 543 | rp.missing_options = get_missing_options(hdev); | ||
| 544 | |||
| 545 | hci_dev_unlock(hdev); | ||
| 546 | |||
| 547 | return cmd_complete(sk, hdev->id, MGMT_OP_READ_CONFIG_INFO, 0, &rp, | ||
| 548 | sizeof(rp)); | ||
| 549 | } | ||
| 550 | |||
| 368 | static u32 get_supported_settings(struct hci_dev *hdev) | 551 | static u32 get_supported_settings(struct hci_dev *hdev) |
| 369 | { | 552 | { |
| 370 | u32 settings = 0; | 553 | u32 settings = 0; |
| 371 | 554 | ||
| 372 | settings |= MGMT_SETTING_POWERED; | 555 | settings |= MGMT_SETTING_POWERED; |
| 373 | settings |= MGMT_SETTING_PAIRABLE; | 556 | settings |= MGMT_SETTING_BONDABLE; |
| 374 | settings |= MGMT_SETTING_DEBUG_KEYS; | 557 | settings |= MGMT_SETTING_DEBUG_KEYS; |
| 558 | settings |= MGMT_SETTING_CONNECTABLE; | ||
| 559 | settings |= MGMT_SETTING_DISCOVERABLE; | ||
| 375 | 560 | ||
| 376 | if (lmp_bredr_capable(hdev)) { | 561 | if (lmp_bredr_capable(hdev)) { |
| 377 | settings |= MGMT_SETTING_CONNECTABLE; | ||
| 378 | if (hdev->hci_ver >= BLUETOOTH_VER_1_2) | 562 | if (hdev->hci_ver >= BLUETOOTH_VER_1_2) |
| 379 | settings |= MGMT_SETTING_FAST_CONNECTABLE; | 563 | settings |= MGMT_SETTING_FAST_CONNECTABLE; |
| 380 | settings |= MGMT_SETTING_DISCOVERABLE; | ||
| 381 | settings |= MGMT_SETTING_BREDR; | 564 | settings |= MGMT_SETTING_BREDR; |
| 382 | settings |= MGMT_SETTING_LINK_SECURITY; | 565 | settings |= MGMT_SETTING_LINK_SECURITY; |
| 383 | 566 | ||
| @@ -387,7 +570,7 @@ static u32 get_supported_settings(struct hci_dev *hdev) | |||
| 387 | } | 570 | } |
| 388 | 571 | ||
| 389 | if (lmp_sc_capable(hdev) || | 572 | if (lmp_sc_capable(hdev) || |
| 390 | test_bit(HCI_FORCE_SC, &hdev->dev_flags)) | 573 | test_bit(HCI_FORCE_SC, &hdev->dbg_flags)) |
| 391 | settings |= MGMT_SETTING_SECURE_CONN; | 574 | settings |= MGMT_SETTING_SECURE_CONN; |
| 392 | } | 575 | } |
| 393 | 576 | ||
| @@ -397,6 +580,10 @@ static u32 get_supported_settings(struct hci_dev *hdev) | |||
| 397 | settings |= MGMT_SETTING_PRIVACY; | 580 | settings |= MGMT_SETTING_PRIVACY; |
| 398 | } | 581 | } |
| 399 | 582 | ||
| 583 | if (test_bit(HCI_QUIRK_EXTERNAL_CONFIG, &hdev->quirks) || | ||
| 584 | hdev->set_bdaddr) | ||
| 585 | settings |= MGMT_SETTING_CONFIGURATION; | ||
| 586 | |||
| 400 | return settings; | 587 | return settings; |
| 401 | } | 588 | } |
| 402 | 589 | ||
| @@ -416,8 +603,8 @@ static u32 get_current_settings(struct hci_dev *hdev) | |||
| 416 | if (test_bit(HCI_DISCOVERABLE, &hdev->dev_flags)) | 603 | if (test_bit(HCI_DISCOVERABLE, &hdev->dev_flags)) |
| 417 | settings |= MGMT_SETTING_DISCOVERABLE; | 604 | settings |= MGMT_SETTING_DISCOVERABLE; |
| 418 | 605 | ||
| 419 | if (test_bit(HCI_PAIRABLE, &hdev->dev_flags)) | 606 | if (test_bit(HCI_BONDABLE, &hdev->dev_flags)) |
| 420 | settings |= MGMT_SETTING_PAIRABLE; | 607 | settings |= MGMT_SETTING_BONDABLE; |
| 421 | 608 | ||
| 422 | if (test_bit(HCI_BREDR_ENABLED, &hdev->dev_flags)) | 609 | if (test_bit(HCI_BREDR_ENABLED, &hdev->dev_flags)) |
| 423 | settings |= MGMT_SETTING_BREDR; | 610 | settings |= MGMT_SETTING_BREDR; |
| @@ -440,7 +627,7 @@ static u32 get_current_settings(struct hci_dev *hdev) | |||
| 440 | if (test_bit(HCI_SC_ENABLED, &hdev->dev_flags)) | 627 | if (test_bit(HCI_SC_ENABLED, &hdev->dev_flags)) |
| 441 | settings |= MGMT_SETTING_SECURE_CONN; | 628 | settings |= MGMT_SETTING_SECURE_CONN; |
| 442 | 629 | ||
| 443 | if (test_bit(HCI_DEBUG_KEYS, &hdev->dev_flags)) | 630 | if (test_bit(HCI_KEEP_DEBUG_KEYS, &hdev->dev_flags)) |
| 444 | settings |= MGMT_SETTING_DEBUG_KEYS; | 631 | settings |= MGMT_SETTING_DEBUG_KEYS; |
| 445 | 632 | ||
| 446 | if (test_bit(HCI_PRIVACY, &hdev->dev_flags)) | 633 | if (test_bit(HCI_PRIVACY, &hdev->dev_flags)) |
| @@ -571,6 +758,22 @@ static struct pending_cmd *mgmt_pending_find(u16 opcode, struct hci_dev *hdev) | |||
| 571 | return NULL; | 758 | return NULL; |
| 572 | } | 759 | } |
| 573 | 760 | ||
| 761 | static struct pending_cmd *mgmt_pending_find_data(u16 opcode, | ||
| 762 | struct hci_dev *hdev, | ||
| 763 | const void *data) | ||
| 764 | { | ||
| 765 | struct pending_cmd *cmd; | ||
| 766 | |||
| 767 | list_for_each_entry(cmd, &hdev->mgmt_pending, list) { | ||
| 768 | if (cmd->user_data != data) | ||
| 769 | continue; | ||
| 770 | if (cmd->opcode == opcode) | ||
| 771 | return cmd; | ||
| 772 | } | ||
| 773 | |||
| 774 | return NULL; | ||
| 775 | } | ||
| 776 | |||
| 574 | static u8 create_scan_rsp_data(struct hci_dev *hdev, u8 *ptr) | 777 | static u8 create_scan_rsp_data(struct hci_dev *hdev, u8 *ptr) |
| 575 | { | 778 | { |
| 576 | u8 ad_len = 0; | 779 | u8 ad_len = 0; |
| @@ -703,6 +906,16 @@ static void update_adv_data(struct hci_request *req) | |||
| 703 | hci_req_add(req, HCI_OP_LE_SET_ADV_DATA, sizeof(cp), &cp); | 906 | hci_req_add(req, HCI_OP_LE_SET_ADV_DATA, sizeof(cp), &cp); |
| 704 | } | 907 | } |
| 705 | 908 | ||
| 909 | int mgmt_update_adv_data(struct hci_dev *hdev) | ||
| 910 | { | ||
| 911 | struct hci_request req; | ||
| 912 | |||
| 913 | hci_req_init(&req, hdev); | ||
| 914 | update_adv_data(&req); | ||
| 915 | |||
| 916 | return hci_req_run(&req, NULL); | ||
| 917 | } | ||
| 918 | |||
| 706 | static void create_eir(struct hci_dev *hdev, u8 *data) | 919 | static void create_eir(struct hci_dev *hdev, u8 *data) |
| 707 | { | 920 | { |
| 708 | u8 *ptr = data; | 921 | u8 *ptr = data; |
| @@ -836,6 +1049,13 @@ static bool get_connectable(struct hci_dev *hdev) | |||
| 836 | return test_bit(HCI_CONNECTABLE, &hdev->dev_flags); | 1049 | return test_bit(HCI_CONNECTABLE, &hdev->dev_flags); |
| 837 | } | 1050 | } |
| 838 | 1051 | ||
| 1052 | static void disable_advertising(struct hci_request *req) | ||
| 1053 | { | ||
| 1054 | u8 enable = 0x00; | ||
| 1055 | |||
| 1056 | hci_req_add(req, HCI_OP_LE_SET_ADV_ENABLE, sizeof(enable), &enable); | ||
| 1057 | } | ||
| 1058 | |||
| 839 | static void enable_advertising(struct hci_request *req) | 1059 | static void enable_advertising(struct hci_request *req) |
| 840 | { | 1060 | { |
| 841 | struct hci_dev *hdev = req->hdev; | 1061 | struct hci_dev *hdev = req->hdev; |
| @@ -843,12 +1063,18 @@ static void enable_advertising(struct hci_request *req) | |||
| 843 | u8 own_addr_type, enable = 0x01; | 1063 | u8 own_addr_type, enable = 0x01; |
| 844 | bool connectable; | 1064 | bool connectable; |
| 845 | 1065 | ||
| 846 | /* Clear the HCI_ADVERTISING bit temporarily so that the | 1066 | if (hci_conn_num(hdev, LE_LINK) > 0) |
| 1067 | return; | ||
| 1068 | |||
| 1069 | if (test_bit(HCI_LE_ADV, &hdev->dev_flags)) | ||
| 1070 | disable_advertising(req); | ||
| 1071 | |||
| 1072 | /* Clear the HCI_LE_ADV bit temporarily so that the | ||
| 847 | * hci_update_random_address knows that it's safe to go ahead | 1073 | * hci_update_random_address knows that it's safe to go ahead |
| 848 | * and write a new random address. The flag will be set back on | 1074 | * and write a new random address. The flag will be set back on |
| 849 | * as soon as the SET_ADV_ENABLE HCI command completes. | 1075 | * as soon as the SET_ADV_ENABLE HCI command completes. |
| 850 | */ | 1076 | */ |
| 851 | clear_bit(HCI_ADVERTISING, &hdev->dev_flags); | 1077 | clear_bit(HCI_LE_ADV, &hdev->dev_flags); |
| 852 | 1078 | ||
| 853 | connectable = get_connectable(hdev); | 1079 | connectable = get_connectable(hdev); |
| 854 | 1080 | ||
| @@ -860,8 +1086,8 @@ static void enable_advertising(struct hci_request *req) | |||
| 860 | return; | 1086 | return; |
| 861 | 1087 | ||
| 862 | memset(&cp, 0, sizeof(cp)); | 1088 | memset(&cp, 0, sizeof(cp)); |
| 863 | cp.min_interval = cpu_to_le16(0x0800); | 1089 | cp.min_interval = cpu_to_le16(hdev->le_adv_min_interval); |
| 864 | cp.max_interval = cpu_to_le16(0x0800); | 1090 | cp.max_interval = cpu_to_le16(hdev->le_adv_max_interval); |
| 865 | cp.type = connectable ? LE_ADV_IND : LE_ADV_NONCONN_IND; | 1091 | cp.type = connectable ? LE_ADV_IND : LE_ADV_NONCONN_IND; |
| 866 | cp.own_address_type = own_addr_type; | 1092 | cp.own_address_type = own_addr_type; |
| 867 | cp.channel_map = hdev->le_adv_channel_map; | 1093 | cp.channel_map = hdev->le_adv_channel_map; |
| @@ -871,13 +1097,6 @@ static void enable_advertising(struct hci_request *req) | |||
| 871 | hci_req_add(req, HCI_OP_LE_SET_ADV_ENABLE, sizeof(enable), &enable); | 1097 | hci_req_add(req, HCI_OP_LE_SET_ADV_ENABLE, sizeof(enable), &enable); |
| 872 | } | 1098 | } |
| 873 | 1099 | ||
| 874 | static void disable_advertising(struct hci_request *req) | ||
| 875 | { | ||
| 876 | u8 enable = 0x00; | ||
| 877 | |||
| 878 | hci_req_add(req, HCI_OP_LE_SET_ADV_ENABLE, sizeof(enable), &enable); | ||
| 879 | } | ||
| 880 | |||
| 881 | static void service_cache_off(struct work_struct *work) | 1100 | static void service_cache_off(struct work_struct *work) |
| 882 | { | 1101 | { |
| 883 | struct hci_dev *hdev = container_of(work, struct hci_dev, | 1102 | struct hci_dev *hdev = container_of(work, struct hci_dev, |
| @@ -909,19 +1128,14 @@ static void rpa_expired(struct work_struct *work) | |||
| 909 | 1128 | ||
| 910 | set_bit(HCI_RPA_EXPIRED, &hdev->dev_flags); | 1129 | set_bit(HCI_RPA_EXPIRED, &hdev->dev_flags); |
| 911 | 1130 | ||
| 912 | if (!test_bit(HCI_ADVERTISING, &hdev->dev_flags) || | 1131 | if (!test_bit(HCI_ADVERTISING, &hdev->dev_flags)) |
| 913 | hci_conn_num(hdev, LE_LINK) > 0) | ||
| 914 | return; | 1132 | return; |
| 915 | 1133 | ||
| 916 | /* The generation of a new RPA and programming it into the | 1134 | /* The generation of a new RPA and programming it into the |
| 917 | * controller happens in the enable_advertising() function. | 1135 | * controller happens in the enable_advertising() function. |
| 918 | */ | 1136 | */ |
| 919 | |||
| 920 | hci_req_init(&req, hdev); | 1137 | hci_req_init(&req, hdev); |
| 921 | |||
| 922 | disable_advertising(&req); | ||
| 923 | enable_advertising(&req); | 1138 | enable_advertising(&req); |
| 924 | |||
| 925 | hci_req_run(&req, NULL); | 1139 | hci_req_run(&req, NULL); |
| 926 | } | 1140 | } |
| 927 | 1141 | ||
| @@ -938,7 +1152,7 @@ static void mgmt_init_hdev(struct sock *sk, struct hci_dev *hdev) | |||
| 938 | * for mgmt we require user-space to explicitly enable | 1152 | * for mgmt we require user-space to explicitly enable |
| 939 | * it | 1153 | * it |
| 940 | */ | 1154 | */ |
| 941 | clear_bit(HCI_PAIRABLE, &hdev->dev_flags); | 1155 | clear_bit(HCI_BONDABLE, &hdev->dev_flags); |
| 942 | } | 1156 | } |
| 943 | 1157 | ||
| 944 | static int read_controller_info(struct sock *sk, struct hci_dev *hdev, | 1158 | static int read_controller_info(struct sock *sk, struct hci_dev *hdev, |
| @@ -984,7 +1198,7 @@ static struct pending_cmd *mgmt_pending_add(struct sock *sk, u16 opcode, | |||
| 984 | { | 1198 | { |
| 985 | struct pending_cmd *cmd; | 1199 | struct pending_cmd *cmd; |
| 986 | 1200 | ||
| 987 | cmd = kmalloc(sizeof(*cmd), GFP_KERNEL); | 1201 | cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); |
| 988 | if (!cmd) | 1202 | if (!cmd) |
| 989 | return NULL; | 1203 | return NULL; |
| 990 | 1204 | ||
| @@ -1047,7 +1261,7 @@ static void clean_up_hci_complete(struct hci_dev *hdev, u8 status) | |||
| 1047 | } | 1261 | } |
| 1048 | } | 1262 | } |
| 1049 | 1263 | ||
| 1050 | static void hci_stop_discovery(struct hci_request *req) | 1264 | static bool hci_stop_discovery(struct hci_request *req) |
| 1051 | { | 1265 | { |
| 1052 | struct hci_dev *hdev = req->hdev; | 1266 | struct hci_dev *hdev = req->hdev; |
| 1053 | struct hci_cp_remote_name_req_cancel cp; | 1267 | struct hci_cp_remote_name_req_cancel cp; |
| @@ -1062,32 +1276,39 @@ static void hci_stop_discovery(struct hci_request *req) | |||
| 1062 | hci_req_add_le_scan_disable(req); | 1276 | hci_req_add_le_scan_disable(req); |
| 1063 | } | 1277 | } |
| 1064 | 1278 | ||
| 1065 | break; | 1279 | return true; |
| 1066 | 1280 | ||
| 1067 | case DISCOVERY_RESOLVING: | 1281 | case DISCOVERY_RESOLVING: |
| 1068 | e = hci_inquiry_cache_lookup_resolve(hdev, BDADDR_ANY, | 1282 | e = hci_inquiry_cache_lookup_resolve(hdev, BDADDR_ANY, |
| 1069 | NAME_PENDING); | 1283 | NAME_PENDING); |
| 1070 | if (!e) | 1284 | if (!e) |
| 1071 | return; | 1285 | break; |
| 1072 | 1286 | ||
| 1073 | bacpy(&cp.bdaddr, &e->data.bdaddr); | 1287 | bacpy(&cp.bdaddr, &e->data.bdaddr); |
| 1074 | hci_req_add(req, HCI_OP_REMOTE_NAME_REQ_CANCEL, sizeof(cp), | 1288 | hci_req_add(req, HCI_OP_REMOTE_NAME_REQ_CANCEL, sizeof(cp), |
| 1075 | &cp); | 1289 | &cp); |
| 1076 | 1290 | ||
| 1077 | break; | 1291 | return true; |
| 1078 | 1292 | ||
| 1079 | default: | 1293 | default: |
| 1080 | /* Passive scanning */ | 1294 | /* Passive scanning */ |
| 1081 | if (test_bit(HCI_LE_SCAN, &hdev->dev_flags)) | 1295 | if (test_bit(HCI_LE_SCAN, &hdev->dev_flags)) { |
| 1082 | hci_req_add_le_scan_disable(req); | 1296 | hci_req_add_le_scan_disable(req); |
| 1297 | return true; | ||
| 1298 | } | ||
| 1299 | |||
| 1083 | break; | 1300 | break; |
| 1084 | } | 1301 | } |
| 1302 | |||
| 1303 | return false; | ||
| 1085 | } | 1304 | } |
| 1086 | 1305 | ||
| 1087 | static int clean_up_hci_state(struct hci_dev *hdev) | 1306 | static int clean_up_hci_state(struct hci_dev *hdev) |
| 1088 | { | 1307 | { |
| 1089 | struct hci_request req; | 1308 | struct hci_request req; |
| 1090 | struct hci_conn *conn; | 1309 | struct hci_conn *conn; |
| 1310 | bool discov_stopped; | ||
| 1311 | int err; | ||
| 1091 | 1312 | ||
| 1092 | hci_req_init(&req, hdev); | 1313 | hci_req_init(&req, hdev); |
| 1093 | 1314 | ||
| @@ -1097,10 +1318,10 @@ static int clean_up_hci_state(struct hci_dev *hdev) | |||
| 1097 | hci_req_add(&req, HCI_OP_WRITE_SCAN_ENABLE, 1, &scan); | 1318 | hci_req_add(&req, HCI_OP_WRITE_SCAN_ENABLE, 1, &scan); |
| 1098 | } | 1319 | } |
| 1099 | 1320 | ||
| 1100 | if (test_bit(HCI_ADVERTISING, &hdev->dev_flags)) | 1321 | if (test_bit(HCI_LE_ADV, &hdev->dev_flags)) |
| 1101 | disable_advertising(&req); | 1322 | disable_advertising(&req); |
| 1102 | 1323 | ||
| 1103 | hci_stop_discovery(&req); | 1324 | discov_stopped = hci_stop_discovery(&req); |
| 1104 | 1325 | ||
| 1105 | list_for_each_entry(conn, &hdev->conn_hash.list, list) { | 1326 | list_for_each_entry(conn, &hdev->conn_hash.list, list) { |
| 1106 | struct hci_cp_disconnect dc; | 1327 | struct hci_cp_disconnect dc; |
| @@ -1134,7 +1355,11 @@ static int clean_up_hci_state(struct hci_dev *hdev) | |||
| 1134 | } | 1355 | } |
| 1135 | } | 1356 | } |
| 1136 | 1357 | ||
| 1137 | return hci_req_run(&req, clean_up_hci_complete); | 1358 | err = hci_req_run(&req, clean_up_hci_complete); |
| 1359 | if (!err && discov_stopped) | ||
| 1360 | hci_discovery_set_state(hdev, DISCOVERY_STOPPING); | ||
| 1361 | |||
| 1362 | return err; | ||
| 1138 | } | 1363 | } |
| 1139 | 1364 | ||
| 1140 | static int set_powered(struct sock *sk, struct hci_dev *hdev, void *data, | 1365 | static int set_powered(struct sock *sk, struct hci_dev *hdev, void *data, |
| @@ -1203,36 +1428,6 @@ failed: | |||
| 1203 | return err; | 1428 | return err; |
| 1204 | } | 1429 | } |
| 1205 | 1430 | ||
| 1206 | static int mgmt_event(u16 event, struct hci_dev *hdev, void *data, u16 data_len, | ||
| 1207 | struct sock *skip_sk) | ||
| 1208 | { | ||
| 1209 | struct sk_buff *skb; | ||
| 1210 | struct mgmt_hdr *hdr; | ||
| 1211 | |||
| 1212 | skb = alloc_skb(sizeof(*hdr) + data_len, GFP_KERNEL); | ||
| 1213 | if (!skb) | ||
| 1214 | return -ENOMEM; | ||
| 1215 | |||
| 1216 | hdr = (void *) skb_put(skb, sizeof(*hdr)); | ||
| 1217 | hdr->opcode = cpu_to_le16(event); | ||
| 1218 | if (hdev) | ||
| 1219 | hdr->index = cpu_to_le16(hdev->id); | ||
| 1220 | else | ||
| 1221 | hdr->index = cpu_to_le16(MGMT_INDEX_NONE); | ||
| 1222 | hdr->len = cpu_to_le16(data_len); | ||
| 1223 | |||
| 1224 | if (data) | ||
| 1225 | memcpy(skb_put(skb, data_len), data, data_len); | ||
| 1226 | |||
| 1227 | /* Time stamp */ | ||
| 1228 | __net_timestamp(skb); | ||
| 1229 | |||
| 1230 | hci_send_to_control(skb, skip_sk); | ||
| 1231 | kfree_skb(skb); | ||
| 1232 | |||
| 1233 | return 0; | ||
| 1234 | } | ||
| 1235 | |||
| 1236 | static int new_settings(struct hci_dev *hdev, struct sock *skip) | 1431 | static int new_settings(struct hci_dev *hdev, struct sock *skip) |
| 1237 | { | 1432 | { |
| 1238 | __le32 ev; | 1433 | __le32 ev; |
| @@ -1242,6 +1437,11 @@ static int new_settings(struct hci_dev *hdev, struct sock *skip) | |||
| 1242 | return mgmt_event(MGMT_EV_NEW_SETTINGS, hdev, &ev, sizeof(ev), skip); | 1437 | return mgmt_event(MGMT_EV_NEW_SETTINGS, hdev, &ev, sizeof(ev), skip); |
| 1243 | } | 1438 | } |
| 1244 | 1439 | ||
| 1440 | int mgmt_new_settings(struct hci_dev *hdev) | ||
| 1441 | { | ||
| 1442 | return new_settings(hdev, NULL); | ||
| 1443 | } | ||
| 1444 | |||
| 1245 | struct cmd_lookup { | 1445 | struct cmd_lookup { |
| 1246 | struct sock *sk; | 1446 | struct sock *sk; |
| 1247 | struct hci_dev *hdev; | 1447 | struct hci_dev *hdev; |
| @@ -1553,7 +1753,7 @@ static void set_connectable_complete(struct hci_dev *hdev, u8 status) | |||
| 1553 | { | 1753 | { |
| 1554 | struct pending_cmd *cmd; | 1754 | struct pending_cmd *cmd; |
| 1555 | struct mgmt_mode *cp; | 1755 | struct mgmt_mode *cp; |
| 1556 | bool changed; | 1756 | bool conn_changed, discov_changed; |
| 1557 | 1757 | ||
| 1558 | BT_DBG("status 0x%02x", status); | 1758 | BT_DBG("status 0x%02x", status); |
| 1559 | 1759 | ||
| @@ -1570,15 +1770,25 @@ static void set_connectable_complete(struct hci_dev *hdev, u8 status) | |||
| 1570 | } | 1770 | } |
| 1571 | 1771 | ||
| 1572 | cp = cmd->param; | 1772 | cp = cmd->param; |
| 1573 | if (cp->val) | 1773 | if (cp->val) { |
| 1574 | changed = !test_and_set_bit(HCI_CONNECTABLE, &hdev->dev_flags); | 1774 | conn_changed = !test_and_set_bit(HCI_CONNECTABLE, |
| 1575 | else | 1775 | &hdev->dev_flags); |
| 1576 | changed = test_and_clear_bit(HCI_CONNECTABLE, &hdev->dev_flags); | 1776 | discov_changed = false; |
| 1777 | } else { | ||
| 1778 | conn_changed = test_and_clear_bit(HCI_CONNECTABLE, | ||
| 1779 | &hdev->dev_flags); | ||
| 1780 | discov_changed = test_and_clear_bit(HCI_DISCOVERABLE, | ||
| 1781 | &hdev->dev_flags); | ||
| 1782 | } | ||
| 1577 | 1783 | ||
| 1578 | send_settings_rsp(cmd->sk, MGMT_OP_SET_CONNECTABLE, hdev); | 1784 | send_settings_rsp(cmd->sk, MGMT_OP_SET_CONNECTABLE, hdev); |
| 1579 | 1785 | ||
| 1580 | if (changed) | 1786 | if (conn_changed || discov_changed) { |
| 1581 | new_settings(hdev, cmd->sk); | 1787 | new_settings(hdev, cmd->sk); |
| 1788 | if (discov_changed) | ||
| 1789 | mgmt_update_adv_data(hdev); | ||
| 1790 | hci_update_background_scan(hdev); | ||
| 1791 | } | ||
| 1582 | 1792 | ||
| 1583 | remove_cmd: | 1793 | remove_cmd: |
| 1584 | mgmt_pending_remove(cmd); | 1794 | mgmt_pending_remove(cmd); |
| @@ -1607,8 +1817,10 @@ static int set_connectable_update_settings(struct hci_dev *hdev, | |||
| 1607 | if (err < 0) | 1817 | if (err < 0) |
| 1608 | return err; | 1818 | return err; |
| 1609 | 1819 | ||
| 1610 | if (changed) | 1820 | if (changed) { |
| 1821 | hci_update_background_scan(hdev); | ||
| 1611 | return new_settings(hdev, sk); | 1822 | return new_settings(hdev, sk); |
| 1823 | } | ||
| 1612 | 1824 | ||
| 1613 | return 0; | 1825 | return 0; |
| 1614 | } | 1826 | } |
| @@ -1669,7 +1881,18 @@ static int set_connectable(struct sock *sk, struct hci_dev *hdev, void *data, | |||
| 1669 | if (cp->val) { | 1881 | if (cp->val) { |
| 1670 | scan = SCAN_PAGE; | 1882 | scan = SCAN_PAGE; |
| 1671 | } else { | 1883 | } else { |
| 1672 | scan = 0; | 1884 | /* If we don't have any whitelist entries just |
| 1885 | * disable all scanning. If there are entries | ||
| 1886 | * and we had both page and inquiry scanning | ||
| 1887 | * enabled then fall back to only page scanning. | ||
| 1888 | * Otherwise no changes are needed. | ||
| 1889 | */ | ||
| 1890 | if (list_empty(&hdev->whitelist)) | ||
| 1891 | scan = SCAN_DISABLED; | ||
| 1892 | else if (test_bit(HCI_ISCAN, &hdev->flags)) | ||
| 1893 | scan = SCAN_PAGE; | ||
| 1894 | else | ||
| 1895 | goto no_scan_update; | ||
| 1673 | 1896 | ||
| 1674 | if (test_bit(HCI_ISCAN, &hdev->flags) && | 1897 | if (test_bit(HCI_ISCAN, &hdev->flags) && |
| 1675 | hdev->discov_timeout > 0) | 1898 | hdev->discov_timeout > 0) |
| @@ -1679,6 +1902,7 @@ static int set_connectable(struct sock *sk, struct hci_dev *hdev, void *data, | |||
| 1679 | hci_req_add(&req, HCI_OP_WRITE_SCAN_ENABLE, 1, &scan); | 1902 | hci_req_add(&req, HCI_OP_WRITE_SCAN_ENABLE, 1, &scan); |
| 1680 | } | 1903 | } |
| 1681 | 1904 | ||
| 1905 | no_scan_update: | ||
| 1682 | /* If we're going from non-connectable to connectable or | 1906 | /* If we're going from non-connectable to connectable or |
| 1683 | * vice-versa when fast connectable is enabled ensure that fast | 1907 | * vice-versa when fast connectable is enabled ensure that fast |
| 1684 | * connectable gets disabled. write_fast_connectable won't do | 1908 | * connectable gets disabled. write_fast_connectable won't do |
| @@ -1688,11 +1912,9 @@ static int set_connectable(struct sock *sk, struct hci_dev *hdev, void *data, | |||
| 1688 | if (cp->val || test_bit(HCI_FAST_CONNECTABLE, &hdev->dev_flags)) | 1912 | if (cp->val || test_bit(HCI_FAST_CONNECTABLE, &hdev->dev_flags)) |
| 1689 | write_fast_connectable(&req, false); | 1913 | write_fast_connectable(&req, false); |
| 1690 | 1914 | ||
| 1691 | if (test_bit(HCI_ADVERTISING, &hdev->dev_flags) && | 1915 | /* Update the advertising parameters if necessary */ |
| 1692 | hci_conn_num(hdev, LE_LINK) == 0) { | 1916 | if (test_bit(HCI_ADVERTISING, &hdev->dev_flags)) |
| 1693 | disable_advertising(&req); | ||
| 1694 | enable_advertising(&req); | 1917 | enable_advertising(&req); |
| 1695 | } | ||
| 1696 | 1918 | ||
| 1697 | err = hci_req_run(&req, set_connectable_complete); | 1919 | err = hci_req_run(&req, set_connectable_complete); |
| 1698 | if (err < 0) { | 1920 | if (err < 0) { |
| @@ -1708,7 +1930,7 @@ failed: | |||
| 1708 | return err; | 1930 | return err; |
| 1709 | } | 1931 | } |
| 1710 | 1932 | ||
| 1711 | static int set_pairable(struct sock *sk, struct hci_dev *hdev, void *data, | 1933 | static int set_bondable(struct sock *sk, struct hci_dev *hdev, void *data, |
| 1712 | u16 len) | 1934 | u16 len) |
| 1713 | { | 1935 | { |
| 1714 | struct mgmt_mode *cp = data; | 1936 | struct mgmt_mode *cp = data; |
| @@ -1718,17 +1940,17 @@ static int set_pairable(struct sock *sk, struct hci_dev *hdev, void *data, | |||
| 1718 | BT_DBG("request for %s", hdev->name); | 1940 | BT_DBG("request for %s", hdev->name); |
| 1719 | 1941 | ||
| 1720 | if (cp->val != 0x00 && cp->val != 0x01) | 1942 | if (cp->val != 0x00 && cp->val != 0x01) |
| 1721 | return cmd_status(sk, hdev->id, MGMT_OP_SET_PAIRABLE, | 1943 | return cmd_status(sk, hdev->id, MGMT_OP_SET_BONDABLE, |
| 1722 | MGMT_STATUS_INVALID_PARAMS); | 1944 | MGMT_STATUS_INVALID_PARAMS); |
| 1723 | 1945 | ||
| 1724 | hci_dev_lock(hdev); | 1946 | hci_dev_lock(hdev); |
| 1725 | 1947 | ||
| 1726 | if (cp->val) | 1948 | if (cp->val) |
| 1727 | changed = !test_and_set_bit(HCI_PAIRABLE, &hdev->dev_flags); | 1949 | changed = !test_and_set_bit(HCI_BONDABLE, &hdev->dev_flags); |
| 1728 | else | 1950 | else |
| 1729 | changed = test_and_clear_bit(HCI_PAIRABLE, &hdev->dev_flags); | 1951 | changed = test_and_clear_bit(HCI_BONDABLE, &hdev->dev_flags); |
| 1730 | 1952 | ||
| 1731 | err = send_settings_rsp(sk, MGMT_OP_SET_PAIRABLE, hdev); | 1953 | err = send_settings_rsp(sk, MGMT_OP_SET_BONDABLE, hdev); |
| 1732 | if (err < 0) | 1954 | if (err < 0) |
| 1733 | goto unlock; | 1955 | goto unlock; |
| 1734 | 1956 | ||
| @@ -1877,6 +2099,10 @@ static int set_ssp(struct sock *sk, struct hci_dev *hdev, void *data, u16 len) | |||
| 1877 | goto failed; | 2099 | goto failed; |
| 1878 | } | 2100 | } |
| 1879 | 2101 | ||
| 2102 | if (!cp->val && test_bit(HCI_USE_DEBUG_KEYS, &hdev->dev_flags)) | ||
| 2103 | hci_send_cmd(hdev, HCI_OP_WRITE_SSP_DEBUG_MODE, | ||
| 2104 | sizeof(cp->val), &cp->val); | ||
| 2105 | |||
| 1880 | err = hci_send_cmd(hdev, HCI_OP_WRITE_SSP_MODE, 1, &cp->val); | 2106 | err = hci_send_cmd(hdev, HCI_OP_WRITE_SSP_MODE, 1, &cp->val); |
| 1881 | if (err < 0) { | 2107 | if (err < 0) { |
| 1882 | mgmt_pending_remove(cmd); | 2108 | mgmt_pending_remove(cmd); |
| @@ -1973,6 +2199,8 @@ static void le_enable_complete(struct hci_dev *hdev, u8 status) | |||
| 1973 | update_scan_rsp_data(&req); | 2199 | update_scan_rsp_data(&req); |
| 1974 | hci_req_run(&req, NULL); | 2200 | hci_req_run(&req, NULL); |
| 1975 | 2201 | ||
| 2202 | hci_update_background_scan(hdev); | ||
| 2203 | |||
| 1976 | hci_dev_unlock(hdev); | 2204 | hci_dev_unlock(hdev); |
| 1977 | } | 2205 | } |
| 1978 | } | 2206 | } |
| @@ -2048,9 +2276,9 @@ static int set_le(struct sock *sk, struct hci_dev *hdev, void *data, u16 len) | |||
| 2048 | 2276 | ||
| 2049 | if (val) { | 2277 | if (val) { |
| 2050 | hci_cp.le = val; | 2278 | hci_cp.le = val; |
| 2051 | hci_cp.simul = lmp_le_br_capable(hdev); | 2279 | hci_cp.simul = 0x00; |
| 2052 | } else { | 2280 | } else { |
| 2053 | if (test_bit(HCI_ADVERTISING, &hdev->dev_flags)) | 2281 | if (test_bit(HCI_LE_ADV, &hdev->dev_flags)) |
| 2054 | disable_advertising(&req); | 2282 | disable_advertising(&req); |
| 2055 | } | 2283 | } |
| 2056 | 2284 | ||
| @@ -2373,6 +2601,8 @@ static int load_link_keys(struct sock *sk, struct hci_dev *hdev, void *data, | |||
| 2373 | u16 len) | 2601 | u16 len) |
| 2374 | { | 2602 | { |
| 2375 | struct mgmt_cp_load_link_keys *cp = data; | 2603 | struct mgmt_cp_load_link_keys *cp = data; |
| 2604 | const u16 max_key_count = ((U16_MAX - sizeof(*cp)) / | ||
| 2605 | sizeof(struct mgmt_link_key_info)); | ||
| 2376 | u16 key_count, expected_len; | 2606 | u16 key_count, expected_len; |
| 2377 | bool changed; | 2607 | bool changed; |
| 2378 | int i; | 2608 | int i; |
| @@ -2384,6 +2614,12 @@ static int load_link_keys(struct sock *sk, struct hci_dev *hdev, void *data, | |||
| 2384 | MGMT_STATUS_NOT_SUPPORTED); | 2614 | MGMT_STATUS_NOT_SUPPORTED); |
| 2385 | 2615 | ||
| 2386 | key_count = __le16_to_cpu(cp->key_count); | 2616 | key_count = __le16_to_cpu(cp->key_count); |
| 2617 | if (key_count > max_key_count) { | ||
| 2618 | BT_ERR("load_link_keys: too big key_count value %u", | ||
| 2619 | key_count); | ||
| 2620 | return cmd_status(sk, hdev->id, MGMT_OP_LOAD_LINK_KEYS, | ||
| 2621 | MGMT_STATUS_INVALID_PARAMS); | ||
| 2622 | } | ||
| 2387 | 2623 | ||
| 2388 | expected_len = sizeof(*cp) + key_count * | 2624 | expected_len = sizeof(*cp) + key_count * |
| 2389 | sizeof(struct mgmt_link_key_info); | 2625 | sizeof(struct mgmt_link_key_info); |
| @@ -2414,9 +2650,11 @@ static int load_link_keys(struct sock *sk, struct hci_dev *hdev, void *data, | |||
| 2414 | hci_link_keys_clear(hdev); | 2650 | hci_link_keys_clear(hdev); |
| 2415 | 2651 | ||
| 2416 | if (cp->debug_keys) | 2652 | if (cp->debug_keys) |
| 2417 | changed = !test_and_set_bit(HCI_DEBUG_KEYS, &hdev->dev_flags); | 2653 | changed = !test_and_set_bit(HCI_KEEP_DEBUG_KEYS, |
| 2654 | &hdev->dev_flags); | ||
| 2418 | else | 2655 | else |
| 2419 | changed = test_and_clear_bit(HCI_DEBUG_KEYS, &hdev->dev_flags); | 2656 | changed = test_and_clear_bit(HCI_KEEP_DEBUG_KEYS, |
| 2657 | &hdev->dev_flags); | ||
| 2420 | 2658 | ||
| 2421 | if (changed) | 2659 | if (changed) |
| 2422 | new_settings(hdev, NULL); | 2660 | new_settings(hdev, NULL); |
| @@ -2424,8 +2662,14 @@ static int load_link_keys(struct sock *sk, struct hci_dev *hdev, void *data, | |||
| 2424 | for (i = 0; i < key_count; i++) { | 2662 | for (i = 0; i < key_count; i++) { |
| 2425 | struct mgmt_link_key_info *key = &cp->keys[i]; | 2663 | struct mgmt_link_key_info *key = &cp->keys[i]; |
| 2426 | 2664 | ||
| 2427 | hci_add_link_key(hdev, NULL, 0, &key->addr.bdaddr, key->val, | 2665 | /* Always ignore debug keys and require a new pairing if |
| 2428 | key->type, key->pin_len); | 2666 | * the user wants to use them. |
| 2667 | */ | ||
| 2668 | if (key->type == HCI_LK_DEBUG_COMBINATION) | ||
| 2669 | continue; | ||
| 2670 | |||
| 2671 | hci_add_link_key(hdev, NULL, &key->addr.bdaddr, key->val, | ||
| 2672 | key->type, key->pin_len, NULL); | ||
| 2429 | } | 2673 | } |
| 2430 | 2674 | ||
| 2431 | cmd_complete(sk, hdev->id, MGMT_OP_LOAD_LINK_KEYS, 0, NULL, 0); | 2675 | cmd_complete(sk, hdev->id, MGMT_OP_LOAD_LINK_KEYS, 0, NULL, 0); |
| @@ -2766,6 +3010,10 @@ static int set_io_capability(struct sock *sk, struct hci_dev *hdev, void *data, | |||
| 2766 | 3010 | ||
| 2767 | BT_DBG(""); | 3011 | BT_DBG(""); |
| 2768 | 3012 | ||
| 3013 | if (cp->io_capability > SMP_IO_KEYBOARD_DISPLAY) | ||
| 3014 | return cmd_complete(sk, hdev->id, MGMT_OP_SET_IO_CAPABILITY, | ||
| 3015 | MGMT_STATUS_INVALID_PARAMS, NULL, 0); | ||
| 3016 | |||
| 2769 | hci_dev_lock(hdev); | 3017 | hci_dev_lock(hdev); |
| 2770 | 3018 | ||
| 2771 | hdev->io_capability = cp->io_capability; | 3019 | hdev->io_capability = cp->io_capability; |
| @@ -2878,6 +3126,11 @@ static int pair_device(struct sock *sk, struct hci_dev *hdev, void *data, | |||
| 2878 | MGMT_STATUS_INVALID_PARAMS, | 3126 | MGMT_STATUS_INVALID_PARAMS, |
| 2879 | &rp, sizeof(rp)); | 3127 | &rp, sizeof(rp)); |
| 2880 | 3128 | ||
| 3129 | if (cp->io_cap > SMP_IO_KEYBOARD_DISPLAY) | ||
| 3130 | return cmd_complete(sk, hdev->id, MGMT_OP_PAIR_DEVICE, | ||
| 3131 | MGMT_STATUS_INVALID_PARAMS, | ||
| 3132 | &rp, sizeof(rp)); | ||
| 3133 | |||
| 2881 | hci_dev_lock(hdev); | 3134 | hci_dev_lock(hdev); |
| 2882 | 3135 | ||
| 2883 | if (!hdev_is_powered(hdev)) { | 3136 | if (!hdev_is_powered(hdev)) { |
| @@ -2902,8 +3155,20 @@ static int pair_device(struct sock *sk, struct hci_dev *hdev, void *data, | |||
| 2902 | else | 3155 | else |
| 2903 | addr_type = ADDR_LE_DEV_RANDOM; | 3156 | addr_type = ADDR_LE_DEV_RANDOM; |
| 2904 | 3157 | ||
| 3158 | /* When pairing a new device, it is expected to remember | ||
| 3159 | * this device for future connections. Adding the connection | ||
| 3160 | * parameter information ahead of time allows tracking | ||
| 3161 | * of the slave preferred values and will speed up any | ||
| 3162 | * further connection establishment. | ||
| 3163 | * | ||
| 3164 | * If connection parameters already exist, then they | ||
| 3165 | * will be kept and this function does nothing. | ||
| 3166 | */ | ||
| 3167 | hci_conn_params_add(hdev, &cp->addr.bdaddr, addr_type); | ||
| 3168 | |||
| 2905 | conn = hci_connect_le(hdev, &cp->addr.bdaddr, addr_type, | 3169 | conn = hci_connect_le(hdev, &cp->addr.bdaddr, addr_type, |
| 2906 | sec_level, auth_type); | 3170 | sec_level, HCI_LE_CONN_TIMEOUT, |
| 3171 | HCI_ROLE_MASTER); | ||
| 2907 | } | 3172 | } |
| 2908 | 3173 | ||
| 2909 | if (IS_ERR(conn)) { | 3174 | if (IS_ERR(conn)) { |
| @@ -2948,8 +3213,8 @@ static int pair_device(struct sock *sk, struct hci_dev *hdev, void *data, | |||
| 2948 | conn->io_capability = cp->io_cap; | 3213 | conn->io_capability = cp->io_cap; |
| 2949 | cmd->user_data = conn; | 3214 | cmd->user_data = conn; |
| 2950 | 3215 | ||
| 2951 | if (conn->state == BT_CONNECTED && | 3216 | if ((conn->state == BT_CONNECTED || conn->state == BT_CONFIG) && |
| 2952 | hci_conn_security(conn, sec_level, auth_type)) | 3217 | hci_conn_security(conn, sec_level, auth_type, true)) |
| 2953 | pairing_complete(cmd, 0); | 3218 | pairing_complete(cmd, 0); |
| 2954 | 3219 | ||
| 2955 | err = 0; | 3220 | err = 0; |
| @@ -3031,14 +3296,7 @@ static int user_pairing_resp(struct sock *sk, struct hci_dev *hdev, | |||
| 3031 | } | 3296 | } |
| 3032 | 3297 | ||
| 3033 | if (addr->type == BDADDR_LE_PUBLIC || addr->type == BDADDR_LE_RANDOM) { | 3298 | if (addr->type == BDADDR_LE_PUBLIC || addr->type == BDADDR_LE_RANDOM) { |
| 3034 | /* Continue with pairing via SMP. The hdev lock must be | ||
| 3035 | * released as SMP may try to recquire it for crypto | ||
| 3036 | * purposes. | ||
| 3037 | */ | ||
| 3038 | hci_dev_unlock(hdev); | ||
| 3039 | err = smp_user_confirm_reply(conn, mgmt_op, passkey); | 3299 | err = smp_user_confirm_reply(conn, mgmt_op, passkey); |
| 3040 | hci_dev_lock(hdev); | ||
| 3041 | |||
| 3042 | if (!err) | 3300 | if (!err) |
| 3043 | err = cmd_complete(sk, hdev->id, mgmt_op, | 3301 | err = cmd_complete(sk, hdev->id, mgmt_op, |
| 3044 | MGMT_STATUS_SUCCESS, addr, | 3302 | MGMT_STATUS_SUCCESS, addr, |
| @@ -3516,11 +3774,21 @@ static int start_discovery(struct sock *sk, struct hci_dev *hdev, | |||
| 3516 | goto failed; | 3774 | goto failed; |
| 3517 | } | 3775 | } |
| 3518 | 3776 | ||
| 3519 | if (test_bit(HCI_ADVERTISING, &hdev->dev_flags)) { | 3777 | if (test_bit(HCI_LE_ADV, &hdev->dev_flags)) { |
| 3520 | err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY, | 3778 | /* Don't let discovery abort an outgoing |
| 3521 | MGMT_STATUS_REJECTED); | 3779 | * connection attempt that's using directed |
| 3522 | mgmt_pending_remove(cmd); | 3780 | * advertising. |
| 3523 | goto failed; | 3781 | */ |
| 3782 | if (hci_conn_hash_lookup_state(hdev, LE_LINK, | ||
| 3783 | BT_CONNECT)) { | ||
| 3784 | err = cmd_status(sk, hdev->id, | ||
| 3785 | MGMT_OP_START_DISCOVERY, | ||
| 3786 | MGMT_STATUS_REJECTED); | ||
| 3787 | mgmt_pending_remove(cmd); | ||
| 3788 | goto failed; | ||
| 3789 | } | ||
| 3790 | |||
| 3791 | disable_advertising(&req); | ||
| 3524 | } | 3792 | } |
| 3525 | 3793 | ||
| 3526 | /* If controller is scanning, it means the background scanning | 3794 | /* If controller is scanning, it means the background scanning |
| @@ -3723,12 +3991,18 @@ static int block_device(struct sock *sk, struct hci_dev *hdev, void *data, | |||
| 3723 | 3991 | ||
| 3724 | hci_dev_lock(hdev); | 3992 | hci_dev_lock(hdev); |
| 3725 | 3993 | ||
| 3726 | err = hci_blacklist_add(hdev, &cp->addr.bdaddr, cp->addr.type); | 3994 | err = hci_bdaddr_list_add(&hdev->blacklist, &cp->addr.bdaddr, |
| 3727 | if (err < 0) | 3995 | cp->addr.type); |
| 3996 | if (err < 0) { | ||
| 3728 | status = MGMT_STATUS_FAILED; | 3997 | status = MGMT_STATUS_FAILED; |
| 3729 | else | 3998 | goto done; |
| 3730 | status = MGMT_STATUS_SUCCESS; | 3999 | } |
| 4000 | |||
| 4001 | mgmt_event(MGMT_EV_DEVICE_BLOCKED, hdev, &cp->addr, sizeof(cp->addr), | ||
| 4002 | sk); | ||
| 4003 | status = MGMT_STATUS_SUCCESS; | ||
| 3731 | 4004 | ||
| 4005 | done: | ||
| 3732 | err = cmd_complete(sk, hdev->id, MGMT_OP_BLOCK_DEVICE, status, | 4006 | err = cmd_complete(sk, hdev->id, MGMT_OP_BLOCK_DEVICE, status, |
| 3733 | &cp->addr, sizeof(cp->addr)); | 4007 | &cp->addr, sizeof(cp->addr)); |
| 3734 | 4008 | ||
| @@ -3753,12 +4027,18 @@ static int unblock_device(struct sock *sk, struct hci_dev *hdev, void *data, | |||
| 3753 | 4027 | ||
| 3754 | hci_dev_lock(hdev); | 4028 | hci_dev_lock(hdev); |
| 3755 | 4029 | ||
| 3756 | err = hci_blacklist_del(hdev, &cp->addr.bdaddr, cp->addr.type); | 4030 | err = hci_bdaddr_list_del(&hdev->blacklist, &cp->addr.bdaddr, |
| 3757 | if (err < 0) | 4031 | cp->addr.type); |
| 4032 | if (err < 0) { | ||
| 3758 | status = MGMT_STATUS_INVALID_PARAMS; | 4033 | status = MGMT_STATUS_INVALID_PARAMS; |
| 3759 | else | 4034 | goto done; |
| 3760 | status = MGMT_STATUS_SUCCESS; | 4035 | } |
| 4036 | |||
| 4037 | mgmt_event(MGMT_EV_DEVICE_UNBLOCKED, hdev, &cp->addr, sizeof(cp->addr), | ||
| 4038 | sk); | ||
| 4039 | status = MGMT_STATUS_SUCCESS; | ||
| 3761 | 4040 | ||
| 4041 | done: | ||
| 3762 | err = cmd_complete(sk, hdev->id, MGMT_OP_UNBLOCK_DEVICE, status, | 4042 | err = cmd_complete(sk, hdev->id, MGMT_OP_UNBLOCK_DEVICE, status, |
| 3763 | &cp->addr, sizeof(cp->addr)); | 4043 | &cp->addr, sizeof(cp->addr)); |
| 3764 | 4044 | ||
| @@ -3813,6 +4093,11 @@ static void set_advertising_complete(struct hci_dev *hdev, u8 status) | |||
| 3813 | return; | 4093 | return; |
| 3814 | } | 4094 | } |
| 3815 | 4095 | ||
| 4096 | if (test_bit(HCI_LE_ADV, &hdev->dev_flags)) | ||
| 4097 | set_bit(HCI_ADVERTISING, &hdev->dev_flags); | ||
| 4098 | else | ||
| 4099 | clear_bit(HCI_ADVERTISING, &hdev->dev_flags); | ||
| 4100 | |||
| 3816 | mgmt_pending_foreach(MGMT_OP_SET_ADVERTISING, hdev, settings_rsp, | 4101 | mgmt_pending_foreach(MGMT_OP_SET_ADVERTISING, hdev, settings_rsp, |
| 3817 | &match); | 4102 | &match); |
| 3818 | 4103 | ||
| @@ -3853,7 +4138,9 @@ static int set_advertising(struct sock *sk, struct hci_dev *hdev, void *data, | |||
| 3853 | * necessary). | 4138 | * necessary). |
| 3854 | */ | 4139 | */ |
| 3855 | if (!hdev_is_powered(hdev) || val == enabled || | 4140 | if (!hdev_is_powered(hdev) || val == enabled || |
| 3856 | hci_conn_num(hdev, LE_LINK) > 0) { | 4141 | hci_conn_num(hdev, LE_LINK) > 0 || |
| 4142 | (test_bit(HCI_LE_SCAN, &hdev->dev_flags) && | ||
| 4143 | hdev->le_scan_type == LE_SCAN_ACTIVE)) { | ||
| 3857 | bool changed = false; | 4144 | bool changed = false; |
| 3858 | 4145 | ||
| 3859 | if (val != test_bit(HCI_ADVERTISING, &hdev->dev_flags)) { | 4146 | if (val != test_bit(HCI_ADVERTISING, &hdev->dev_flags)) { |
| @@ -4105,7 +4392,8 @@ static void set_bredr_scan(struct hci_request *req) | |||
| 4105 | */ | 4392 | */ |
| 4106 | write_fast_connectable(req, false); | 4393 | write_fast_connectable(req, false); |
| 4107 | 4394 | ||
| 4108 | if (test_bit(HCI_CONNECTABLE, &hdev->dev_flags)) | 4395 | if (test_bit(HCI_CONNECTABLE, &hdev->dev_flags) || |
| 4396 | !list_empty(&hdev->whitelist)) | ||
| 4109 | scan |= SCAN_PAGE; | 4397 | scan |= SCAN_PAGE; |
| 4110 | if (test_bit(HCI_DISCOVERABLE, &hdev->dev_flags)) | 4398 | if (test_bit(HCI_DISCOVERABLE, &hdev->dev_flags)) |
| 4111 | scan |= SCAN_INQUIRY; | 4399 | scan |= SCAN_INQUIRY; |
| @@ -4219,7 +4507,8 @@ static int set_bredr(struct sock *sk, struct hci_dev *hdev, void *data, u16 len) | |||
| 4219 | 4507 | ||
| 4220 | hci_req_init(&req, hdev); | 4508 | hci_req_init(&req, hdev); |
| 4221 | 4509 | ||
| 4222 | if (test_bit(HCI_CONNECTABLE, &hdev->dev_flags)) | 4510 | if (test_bit(HCI_CONNECTABLE, &hdev->dev_flags) || |
| 4511 | !list_empty(&hdev->whitelist)) | ||
| 4223 | set_bredr_scan(&req); | 4512 | set_bredr_scan(&req); |
| 4224 | 4513 | ||
| 4225 | /* Since only the advertising data flags will change, there | 4514 | /* Since only the advertising data flags will change, there |
| @@ -4252,7 +4541,7 @@ static int set_secure_conn(struct sock *sk, struct hci_dev *hdev, | |||
| 4252 | status); | 4541 | status); |
| 4253 | 4542 | ||
| 4254 | if (!lmp_sc_capable(hdev) && | 4543 | if (!lmp_sc_capable(hdev) && |
| 4255 | !test_bit(HCI_FORCE_SC, &hdev->dev_flags)) | 4544 | !test_bit(HCI_FORCE_SC, &hdev->dbg_flags)) |
| 4256 | return cmd_status(sk, hdev->id, MGMT_OP_SET_SECURE_CONN, | 4545 | return cmd_status(sk, hdev->id, MGMT_OP_SET_SECURE_CONN, |
| 4257 | MGMT_STATUS_NOT_SUPPORTED); | 4546 | MGMT_STATUS_NOT_SUPPORTED); |
| 4258 | 4547 | ||
| @@ -4328,21 +4617,37 @@ static int set_debug_keys(struct sock *sk, struct hci_dev *hdev, | |||
| 4328 | void *data, u16 len) | 4617 | void *data, u16 len) |
| 4329 | { | 4618 | { |
| 4330 | struct mgmt_mode *cp = data; | 4619 | struct mgmt_mode *cp = data; |
| 4331 | bool changed; | 4620 | bool changed, use_changed; |
| 4332 | int err; | 4621 | int err; |
| 4333 | 4622 | ||
| 4334 | BT_DBG("request for %s", hdev->name); | 4623 | BT_DBG("request for %s", hdev->name); |
| 4335 | 4624 | ||
| 4336 | if (cp->val != 0x00 && cp->val != 0x01) | 4625 | if (cp->val != 0x00 && cp->val != 0x01 && cp->val != 0x02) |
| 4337 | return cmd_status(sk, hdev->id, MGMT_OP_SET_DEBUG_KEYS, | 4626 | return cmd_status(sk, hdev->id, MGMT_OP_SET_DEBUG_KEYS, |
| 4338 | MGMT_STATUS_INVALID_PARAMS); | 4627 | MGMT_STATUS_INVALID_PARAMS); |
| 4339 | 4628 | ||
| 4340 | hci_dev_lock(hdev); | 4629 | hci_dev_lock(hdev); |
| 4341 | 4630 | ||
| 4342 | if (cp->val) | 4631 | if (cp->val) |
| 4343 | changed = !test_and_set_bit(HCI_DEBUG_KEYS, &hdev->dev_flags); | 4632 | changed = !test_and_set_bit(HCI_KEEP_DEBUG_KEYS, |
| 4633 | &hdev->dev_flags); | ||
| 4634 | else | ||
| 4635 | changed = test_and_clear_bit(HCI_KEEP_DEBUG_KEYS, | ||
| 4636 | &hdev->dev_flags); | ||
| 4637 | |||
| 4638 | if (cp->val == 0x02) | ||
| 4639 | use_changed = !test_and_set_bit(HCI_USE_DEBUG_KEYS, | ||
| 4640 | &hdev->dev_flags); | ||
| 4344 | else | 4641 | else |
| 4345 | changed = test_and_clear_bit(HCI_DEBUG_KEYS, &hdev->dev_flags); | 4642 | use_changed = test_and_clear_bit(HCI_USE_DEBUG_KEYS, |
| 4643 | &hdev->dev_flags); | ||
| 4644 | |||
| 4645 | if (hdev_is_powered(hdev) && use_changed && | ||
| 4646 | test_bit(HCI_SSP_ENABLED, &hdev->dev_flags)) { | ||
| 4647 | u8 mode = (cp->val == 0x02) ? 0x01 : 0x00; | ||
| 4648 | hci_send_cmd(hdev, HCI_OP_WRITE_SSP_DEBUG_MODE, | ||
| 4649 | sizeof(mode), &mode); | ||
| 4650 | } | ||
| 4346 | 4651 | ||
| 4347 | err = send_settings_rsp(sk, MGMT_OP_SET_DEBUG_KEYS, hdev); | 4652 | err = send_settings_rsp(sk, MGMT_OP_SET_DEBUG_KEYS, hdev); |
| 4348 | if (err < 0) | 4653 | if (err < 0) |
| @@ -4426,6 +4731,8 @@ static int load_irks(struct sock *sk, struct hci_dev *hdev, void *cp_data, | |||
| 4426 | u16 len) | 4731 | u16 len) |
| 4427 | { | 4732 | { |
| 4428 | struct mgmt_cp_load_irks *cp = cp_data; | 4733 | struct mgmt_cp_load_irks *cp = cp_data; |
| 4734 | const u16 max_irk_count = ((U16_MAX - sizeof(*cp)) / | ||
| 4735 | sizeof(struct mgmt_irk_info)); | ||
| 4429 | u16 irk_count, expected_len; | 4736 | u16 irk_count, expected_len; |
| 4430 | int i, err; | 4737 | int i, err; |
| 4431 | 4738 | ||
| @@ -4436,6 +4743,11 @@ static int load_irks(struct sock *sk, struct hci_dev *hdev, void *cp_data, | |||
| 4436 | MGMT_STATUS_NOT_SUPPORTED); | 4743 | MGMT_STATUS_NOT_SUPPORTED); |
| 4437 | 4744 | ||
| 4438 | irk_count = __le16_to_cpu(cp->irk_count); | 4745 | irk_count = __le16_to_cpu(cp->irk_count); |
| 4746 | if (irk_count > max_irk_count) { | ||
| 4747 | BT_ERR("load_irks: too big irk_count value %u", irk_count); | ||
| 4748 | return cmd_status(sk, hdev->id, MGMT_OP_LOAD_IRKS, | ||
| 4749 | MGMT_STATUS_INVALID_PARAMS); | ||
| 4750 | } | ||
| 4439 | 4751 | ||
| 4440 | expected_len = sizeof(*cp) + irk_count * sizeof(struct mgmt_irk_info); | 4752 | expected_len = sizeof(*cp) + irk_count * sizeof(struct mgmt_irk_info); |
| 4441 | if (expected_len != len) { | 4753 | if (expected_len != len) { |
| @@ -4505,6 +4817,8 @@ static int load_long_term_keys(struct sock *sk, struct hci_dev *hdev, | |||
| 4505 | void *cp_data, u16 len) | 4817 | void *cp_data, u16 len) |
| 4506 | { | 4818 | { |
| 4507 | struct mgmt_cp_load_long_term_keys *cp = cp_data; | 4819 | struct mgmt_cp_load_long_term_keys *cp = cp_data; |
| 4820 | const u16 max_key_count = ((U16_MAX - sizeof(*cp)) / | ||
| 4821 | sizeof(struct mgmt_ltk_info)); | ||
| 4508 | u16 key_count, expected_len; | 4822 | u16 key_count, expected_len; |
| 4509 | int i, err; | 4823 | int i, err; |
| 4510 | 4824 | ||
| @@ -4515,6 +4829,11 @@ static int load_long_term_keys(struct sock *sk, struct hci_dev *hdev, | |||
| 4515 | MGMT_STATUS_NOT_SUPPORTED); | 4829 | MGMT_STATUS_NOT_SUPPORTED); |
| 4516 | 4830 | ||
| 4517 | key_count = __le16_to_cpu(cp->key_count); | 4831 | key_count = __le16_to_cpu(cp->key_count); |
| 4832 | if (key_count > max_key_count) { | ||
| 4833 | BT_ERR("load_ltks: too big key_count value %u", key_count); | ||
| 4834 | return cmd_status(sk, hdev->id, MGMT_OP_LOAD_LONG_TERM_KEYS, | ||
| 4835 | MGMT_STATUS_INVALID_PARAMS); | ||
| 4836 | } | ||
| 4518 | 4837 | ||
| 4519 | expected_len = sizeof(*cp) + key_count * | 4838 | expected_len = sizeof(*cp) + key_count * |
| 4520 | sizeof(struct mgmt_ltk_info); | 4839 | sizeof(struct mgmt_ltk_info); |
| @@ -4550,9 +4869,9 @@ static int load_long_term_keys(struct sock *sk, struct hci_dev *hdev, | |||
| 4550 | addr_type = ADDR_LE_DEV_RANDOM; | 4869 | addr_type = ADDR_LE_DEV_RANDOM; |
| 4551 | 4870 | ||
| 4552 | if (key->master) | 4871 | if (key->master) |
| 4553 | type = HCI_SMP_LTK; | 4872 | type = SMP_LTK; |
| 4554 | else | 4873 | else |
| 4555 | type = HCI_SMP_LTK_SLAVE; | 4874 | type = SMP_LTK_SLAVE; |
| 4556 | 4875 | ||
| 4557 | switch (key->type) { | 4876 | switch (key->type) { |
| 4558 | case MGMT_LTK_UNAUTHENTICATED: | 4877 | case MGMT_LTK_UNAUTHENTICATED: |
| @@ -4790,6 +5109,561 @@ unlock: | |||
| 4790 | return err; | 5109 | return err; |
| 4791 | } | 5110 | } |
| 4792 | 5111 | ||
| 5112 | static void get_clock_info_complete(struct hci_dev *hdev, u8 status) | ||
| 5113 | { | ||
| 5114 | struct mgmt_cp_get_clock_info *cp; | ||
| 5115 | struct mgmt_rp_get_clock_info rp; | ||
| 5116 | struct hci_cp_read_clock *hci_cp; | ||
| 5117 | struct pending_cmd *cmd; | ||
| 5118 | struct hci_conn *conn; | ||
| 5119 | |||
| 5120 | BT_DBG("%s status %u", hdev->name, status); | ||
| 5121 | |||
| 5122 | hci_dev_lock(hdev); | ||
| 5123 | |||
| 5124 | hci_cp = hci_sent_cmd_data(hdev, HCI_OP_READ_CLOCK); | ||
| 5125 | if (!hci_cp) | ||
| 5126 | goto unlock; | ||
| 5127 | |||
| 5128 | if (hci_cp->which) { | ||
| 5129 | u16 handle = __le16_to_cpu(hci_cp->handle); | ||
| 5130 | conn = hci_conn_hash_lookup_handle(hdev, handle); | ||
| 5131 | } else { | ||
| 5132 | conn = NULL; | ||
| 5133 | } | ||
| 5134 | |||
| 5135 | cmd = mgmt_pending_find_data(MGMT_OP_GET_CLOCK_INFO, hdev, conn); | ||
| 5136 | if (!cmd) | ||
| 5137 | goto unlock; | ||
| 5138 | |||
| 5139 | cp = cmd->param; | ||
| 5140 | |||
| 5141 | memset(&rp, 0, sizeof(rp)); | ||
| 5142 | memcpy(&rp.addr, &cp->addr, sizeof(rp.addr)); | ||
| 5143 | |||
| 5144 | if (status) | ||
| 5145 | goto send_rsp; | ||
| 5146 | |||
| 5147 | rp.local_clock = cpu_to_le32(hdev->clock); | ||
| 5148 | |||
| 5149 | if (conn) { | ||
| 5150 | rp.piconet_clock = cpu_to_le32(conn->clock); | ||
| 5151 | rp.accuracy = cpu_to_le16(conn->clock_accuracy); | ||
| 5152 | } | ||
| 5153 | |||
| 5154 | send_rsp: | ||
| 5155 | cmd_complete(cmd->sk, cmd->index, cmd->opcode, mgmt_status(status), | ||
| 5156 | &rp, sizeof(rp)); | ||
| 5157 | mgmt_pending_remove(cmd); | ||
| 5158 | if (conn) | ||
| 5159 | hci_conn_drop(conn); | ||
| 5160 | |||
| 5161 | unlock: | ||
| 5162 | hci_dev_unlock(hdev); | ||
| 5163 | } | ||
| 5164 | |||
| 5165 | static int get_clock_info(struct sock *sk, struct hci_dev *hdev, void *data, | ||
| 5166 | u16 len) | ||
| 5167 | { | ||
| 5168 | struct mgmt_cp_get_clock_info *cp = data; | ||
| 5169 | struct mgmt_rp_get_clock_info rp; | ||
| 5170 | struct hci_cp_read_clock hci_cp; | ||
| 5171 | struct pending_cmd *cmd; | ||
| 5172 | struct hci_request req; | ||
| 5173 | struct hci_conn *conn; | ||
| 5174 | int err; | ||
| 5175 | |||
| 5176 | BT_DBG("%s", hdev->name); | ||
| 5177 | |||
| 5178 | memset(&rp, 0, sizeof(rp)); | ||
| 5179 | bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr); | ||
| 5180 | rp.addr.type = cp->addr.type; | ||
| 5181 | |||
| 5182 | if (cp->addr.type != BDADDR_BREDR) | ||
| 5183 | return cmd_complete(sk, hdev->id, MGMT_OP_GET_CLOCK_INFO, | ||
| 5184 | MGMT_STATUS_INVALID_PARAMS, | ||
| 5185 | &rp, sizeof(rp)); | ||
| 5186 | |||
| 5187 | hci_dev_lock(hdev); | ||
| 5188 | |||
| 5189 | if (!hdev_is_powered(hdev)) { | ||
| 5190 | err = cmd_complete(sk, hdev->id, MGMT_OP_GET_CLOCK_INFO, | ||
| 5191 | MGMT_STATUS_NOT_POWERED, &rp, sizeof(rp)); | ||
| 5192 | goto unlock; | ||
| 5193 | } | ||
| 5194 | |||
| 5195 | if (bacmp(&cp->addr.bdaddr, BDADDR_ANY)) { | ||
| 5196 | conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, | ||
| 5197 | &cp->addr.bdaddr); | ||
| 5198 | if (!conn || conn->state != BT_CONNECTED) { | ||
| 5199 | err = cmd_complete(sk, hdev->id, | ||
| 5200 | MGMT_OP_GET_CLOCK_INFO, | ||
| 5201 | MGMT_STATUS_NOT_CONNECTED, | ||
| 5202 | &rp, sizeof(rp)); | ||
| 5203 | goto unlock; | ||
| 5204 | } | ||
| 5205 | } else { | ||
| 5206 | conn = NULL; | ||
| 5207 | } | ||
| 5208 | |||
| 5209 | cmd = mgmt_pending_add(sk, MGMT_OP_GET_CLOCK_INFO, hdev, data, len); | ||
| 5210 | if (!cmd) { | ||
| 5211 | err = -ENOMEM; | ||
| 5212 | goto unlock; | ||
| 5213 | } | ||
| 5214 | |||
| 5215 | hci_req_init(&req, hdev); | ||
| 5216 | |||
| 5217 | memset(&hci_cp, 0, sizeof(hci_cp)); | ||
| 5218 | hci_req_add(&req, HCI_OP_READ_CLOCK, sizeof(hci_cp), &hci_cp); | ||
| 5219 | |||
| 5220 | if (conn) { | ||
| 5221 | hci_conn_hold(conn); | ||
| 5222 | cmd->user_data = conn; | ||
| 5223 | |||
| 5224 | hci_cp.handle = cpu_to_le16(conn->handle); | ||
| 5225 | hci_cp.which = 0x01; /* Piconet clock */ | ||
| 5226 | hci_req_add(&req, HCI_OP_READ_CLOCK, sizeof(hci_cp), &hci_cp); | ||
| 5227 | } | ||
| 5228 | |||
| 5229 | err = hci_req_run(&req, get_clock_info_complete); | ||
| 5230 | if (err < 0) | ||
| 5231 | mgmt_pending_remove(cmd); | ||
| 5232 | |||
| 5233 | unlock: | ||
| 5234 | hci_dev_unlock(hdev); | ||
| 5235 | return err; | ||
| 5236 | } | ||
| 5237 | |||
| 5238 | /* Helper for Add/Remove Device commands */ | ||
| 5239 | static void update_page_scan(struct hci_dev *hdev, u8 scan) | ||
| 5240 | { | ||
| 5241 | if (!test_bit(HCI_BREDR_ENABLED, &hdev->dev_flags)) | ||
| 5242 | return; | ||
| 5243 | |||
| 5244 | if (!hdev_is_powered(hdev)) | ||
| 5245 | return; | ||
| 5246 | |||
| 5247 | /* If HCI_CONNECTABLE is set then Add/Remove Device should not | ||
| 5248 | * make any changes to page scanning. | ||
| 5249 | */ | ||
| 5250 | if (test_bit(HCI_CONNECTABLE, &hdev->dev_flags)) | ||
| 5251 | return; | ||
| 5252 | |||
| 5253 | if (test_bit(HCI_DISCOVERABLE, &hdev->dev_flags)) | ||
| 5254 | scan |= SCAN_INQUIRY; | ||
| 5255 | |||
| 5256 | hci_send_cmd(hdev, HCI_OP_WRITE_SCAN_ENABLE, 1, &scan); | ||
| 5257 | } | ||
| 5258 | |||
| 5259 | static void device_added(struct sock *sk, struct hci_dev *hdev, | ||
| 5260 | bdaddr_t *bdaddr, u8 type, u8 action) | ||
| 5261 | { | ||
| 5262 | struct mgmt_ev_device_added ev; | ||
| 5263 | |||
| 5264 | bacpy(&ev.addr.bdaddr, bdaddr); | ||
| 5265 | ev.addr.type = type; | ||
| 5266 | ev.action = action; | ||
| 5267 | |||
| 5268 | mgmt_event(MGMT_EV_DEVICE_ADDED, hdev, &ev, sizeof(ev), sk); | ||
| 5269 | } | ||
| 5270 | |||
| 5271 | static int add_device(struct sock *sk, struct hci_dev *hdev, | ||
| 5272 | void *data, u16 len) | ||
| 5273 | { | ||
| 5274 | struct mgmt_cp_add_device *cp = data; | ||
| 5275 | u8 auto_conn, addr_type; | ||
| 5276 | int err; | ||
| 5277 | |||
| 5278 | BT_DBG("%s", hdev->name); | ||
| 5279 | |||
| 5280 | if (!bdaddr_type_is_valid(cp->addr.type) || | ||
| 5281 | !bacmp(&cp->addr.bdaddr, BDADDR_ANY)) | ||
| 5282 | return cmd_complete(sk, hdev->id, MGMT_OP_ADD_DEVICE, | ||
| 5283 | MGMT_STATUS_INVALID_PARAMS, | ||
| 5284 | &cp->addr, sizeof(cp->addr)); | ||
| 5285 | |||
| 5286 | if (cp->action != 0x00 && cp->action != 0x01 && cp->action != 0x02) | ||
| 5287 | return cmd_complete(sk, hdev->id, MGMT_OP_ADD_DEVICE, | ||
| 5288 | MGMT_STATUS_INVALID_PARAMS, | ||
| 5289 | &cp->addr, sizeof(cp->addr)); | ||
| 5290 | |||
| 5291 | hci_dev_lock(hdev); | ||
| 5292 | |||
| 5293 | if (cp->addr.type == BDADDR_BREDR) { | ||
| 5294 | bool update_scan; | ||
| 5295 | |||
| 5296 | /* Only incoming connections action is supported for now */ | ||
| 5297 | if (cp->action != 0x01) { | ||
| 5298 | err = cmd_complete(sk, hdev->id, MGMT_OP_ADD_DEVICE, | ||
| 5299 | MGMT_STATUS_INVALID_PARAMS, | ||
| 5300 | &cp->addr, sizeof(cp->addr)); | ||
| 5301 | goto unlock; | ||
| 5302 | } | ||
| 5303 | |||
| 5304 | update_scan = list_empty(&hdev->whitelist); | ||
| 5305 | |||
| 5306 | err = hci_bdaddr_list_add(&hdev->whitelist, &cp->addr.bdaddr, | ||
| 5307 | cp->addr.type); | ||
| 5308 | if (err) | ||
| 5309 | goto unlock; | ||
| 5310 | |||
| 5311 | if (update_scan) | ||
| 5312 | update_page_scan(hdev, SCAN_PAGE); | ||
| 5313 | |||
| 5314 | goto added; | ||
| 5315 | } | ||
| 5316 | |||
| 5317 | if (cp->addr.type == BDADDR_LE_PUBLIC) | ||
| 5318 | addr_type = ADDR_LE_DEV_PUBLIC; | ||
| 5319 | else | ||
| 5320 | addr_type = ADDR_LE_DEV_RANDOM; | ||
| 5321 | |||
| 5322 | if (cp->action == 0x02) | ||
| 5323 | auto_conn = HCI_AUTO_CONN_ALWAYS; | ||
| 5324 | else if (cp->action == 0x01) | ||
| 5325 | auto_conn = HCI_AUTO_CONN_DIRECT; | ||
| 5326 | else | ||
| 5327 | auto_conn = HCI_AUTO_CONN_REPORT; | ||
| 5328 | |||
| 5329 | /* If the connection parameters don't exist for this device, | ||
| 5330 | * they will be created and configured with defaults. | ||
| 5331 | */ | ||
| 5332 | if (hci_conn_params_set(hdev, &cp->addr.bdaddr, addr_type, | ||
| 5333 | auto_conn) < 0) { | ||
| 5334 | err = cmd_complete(sk, hdev->id, MGMT_OP_ADD_DEVICE, | ||
| 5335 | MGMT_STATUS_FAILED, | ||
| 5336 | &cp->addr, sizeof(cp->addr)); | ||
| 5337 | goto unlock; | ||
| 5338 | } | ||
| 5339 | |||
| 5340 | added: | ||
| 5341 | device_added(sk, hdev, &cp->addr.bdaddr, cp->addr.type, cp->action); | ||
| 5342 | |||
| 5343 | err = cmd_complete(sk, hdev->id, MGMT_OP_ADD_DEVICE, | ||
| 5344 | MGMT_STATUS_SUCCESS, &cp->addr, sizeof(cp->addr)); | ||
| 5345 | |||
| 5346 | unlock: | ||
| 5347 | hci_dev_unlock(hdev); | ||
| 5348 | return err; | ||
| 5349 | } | ||
| 5350 | |||
| 5351 | static void device_removed(struct sock *sk, struct hci_dev *hdev, | ||
| 5352 | bdaddr_t *bdaddr, u8 type) | ||
| 5353 | { | ||
| 5354 | struct mgmt_ev_device_removed ev; | ||
| 5355 | |||
| 5356 | bacpy(&ev.addr.bdaddr, bdaddr); | ||
| 5357 | ev.addr.type = type; | ||
| 5358 | |||
| 5359 | mgmt_event(MGMT_EV_DEVICE_REMOVED, hdev, &ev, sizeof(ev), sk); | ||
| 5360 | } | ||
| 5361 | |||
| 5362 | static int remove_device(struct sock *sk, struct hci_dev *hdev, | ||
| 5363 | void *data, u16 len) | ||
| 5364 | { | ||
| 5365 | struct mgmt_cp_remove_device *cp = data; | ||
| 5366 | int err; | ||
| 5367 | |||
| 5368 | BT_DBG("%s", hdev->name); | ||
| 5369 | |||
| 5370 | hci_dev_lock(hdev); | ||
| 5371 | |||
| 5372 | if (bacmp(&cp->addr.bdaddr, BDADDR_ANY)) { | ||
| 5373 | struct hci_conn_params *params; | ||
| 5374 | u8 addr_type; | ||
| 5375 | |||
| 5376 | if (!bdaddr_type_is_valid(cp->addr.type)) { | ||
| 5377 | err = cmd_complete(sk, hdev->id, MGMT_OP_REMOVE_DEVICE, | ||
| 5378 | MGMT_STATUS_INVALID_PARAMS, | ||
| 5379 | &cp->addr, sizeof(cp->addr)); | ||
| 5380 | goto unlock; | ||
| 5381 | } | ||
| 5382 | |||
| 5383 | if (cp->addr.type == BDADDR_BREDR) { | ||
| 5384 | err = hci_bdaddr_list_del(&hdev->whitelist, | ||
| 5385 | &cp->addr.bdaddr, | ||
| 5386 | cp->addr.type); | ||
| 5387 | if (err) { | ||
| 5388 | err = cmd_complete(sk, hdev->id, | ||
| 5389 | MGMT_OP_REMOVE_DEVICE, | ||
| 5390 | MGMT_STATUS_INVALID_PARAMS, | ||
| 5391 | &cp->addr, sizeof(cp->addr)); | ||
| 5392 | goto unlock; | ||
| 5393 | } | ||
| 5394 | |||
| 5395 | if (list_empty(&hdev->whitelist)) | ||
| 5396 | update_page_scan(hdev, SCAN_DISABLED); | ||
| 5397 | |||
| 5398 | device_removed(sk, hdev, &cp->addr.bdaddr, | ||
| 5399 | cp->addr.type); | ||
| 5400 | goto complete; | ||
| 5401 | } | ||
| 5402 | |||
| 5403 | if (cp->addr.type == BDADDR_LE_PUBLIC) | ||
| 5404 | addr_type = ADDR_LE_DEV_PUBLIC; | ||
| 5405 | else | ||
| 5406 | addr_type = ADDR_LE_DEV_RANDOM; | ||
| 5407 | |||
| 5408 | params = hci_conn_params_lookup(hdev, &cp->addr.bdaddr, | ||
| 5409 | addr_type); | ||
| 5410 | if (!params) { | ||
| 5411 | err = cmd_complete(sk, hdev->id, MGMT_OP_REMOVE_DEVICE, | ||
| 5412 | MGMT_STATUS_INVALID_PARAMS, | ||
| 5413 | &cp->addr, sizeof(cp->addr)); | ||
| 5414 | goto unlock; | ||
| 5415 | } | ||
| 5416 | |||
| 5417 | if (params->auto_connect == HCI_AUTO_CONN_DISABLED) { | ||
| 5418 | err = cmd_complete(sk, hdev->id, MGMT_OP_REMOVE_DEVICE, | ||
| 5419 | MGMT_STATUS_INVALID_PARAMS, | ||
| 5420 | &cp->addr, sizeof(cp->addr)); | ||
| 5421 | goto unlock; | ||
| 5422 | } | ||
| 5423 | |||
| 5424 | list_del(¶ms->action); | ||
| 5425 | list_del(¶ms->list); | ||
| 5426 | kfree(params); | ||
| 5427 | hci_update_background_scan(hdev); | ||
| 5428 | |||
| 5429 | device_removed(sk, hdev, &cp->addr.bdaddr, cp->addr.type); | ||
| 5430 | } else { | ||
| 5431 | struct hci_conn_params *p, *tmp; | ||
| 5432 | struct bdaddr_list *b, *btmp; | ||
| 5433 | |||
| 5434 | if (cp->addr.type) { | ||
| 5435 | err = cmd_complete(sk, hdev->id, MGMT_OP_REMOVE_DEVICE, | ||
| 5436 | MGMT_STATUS_INVALID_PARAMS, | ||
| 5437 | &cp->addr, sizeof(cp->addr)); | ||
| 5438 | goto unlock; | ||
| 5439 | } | ||
| 5440 | |||
| 5441 | list_for_each_entry_safe(b, btmp, &hdev->whitelist, list) { | ||
| 5442 | device_removed(sk, hdev, &b->bdaddr, b->bdaddr_type); | ||
| 5443 | list_del(&b->list); | ||
| 5444 | kfree(b); | ||
| 5445 | } | ||
| 5446 | |||
| 5447 | update_page_scan(hdev, SCAN_DISABLED); | ||
| 5448 | |||
| 5449 | list_for_each_entry_safe(p, tmp, &hdev->le_conn_params, list) { | ||
| 5450 | if (p->auto_connect == HCI_AUTO_CONN_DISABLED) | ||
| 5451 | continue; | ||
| 5452 | device_removed(sk, hdev, &p->addr, p->addr_type); | ||
| 5453 | list_del(&p->action); | ||
| 5454 | list_del(&p->list); | ||
| 5455 | kfree(p); | ||
| 5456 | } | ||
| 5457 | |||
| 5458 | BT_DBG("All LE connection parameters were removed"); | ||
| 5459 | |||
| 5460 | hci_update_background_scan(hdev); | ||
| 5461 | } | ||
| 5462 | |||
| 5463 | complete: | ||
| 5464 | err = cmd_complete(sk, hdev->id, MGMT_OP_REMOVE_DEVICE, | ||
| 5465 | MGMT_STATUS_SUCCESS, &cp->addr, sizeof(cp->addr)); | ||
| 5466 | |||
| 5467 | unlock: | ||
| 5468 | hci_dev_unlock(hdev); | ||
| 5469 | return err; | ||
| 5470 | } | ||
| 5471 | |||
| 5472 | static int load_conn_param(struct sock *sk, struct hci_dev *hdev, void *data, | ||
| 5473 | u16 len) | ||
| 5474 | { | ||
| 5475 | struct mgmt_cp_load_conn_param *cp = data; | ||
| 5476 | const u16 max_param_count = ((U16_MAX - sizeof(*cp)) / | ||
| 5477 | sizeof(struct mgmt_conn_param)); | ||
| 5478 | u16 param_count, expected_len; | ||
| 5479 | int i; | ||
| 5480 | |||
| 5481 | if (!lmp_le_capable(hdev)) | ||
| 5482 | return cmd_status(sk, hdev->id, MGMT_OP_LOAD_CONN_PARAM, | ||
| 5483 | MGMT_STATUS_NOT_SUPPORTED); | ||
| 5484 | |||
| 5485 | param_count = __le16_to_cpu(cp->param_count); | ||
| 5486 | if (param_count > max_param_count) { | ||
| 5487 | BT_ERR("load_conn_param: too big param_count value %u", | ||
| 5488 | param_count); | ||
| 5489 | return cmd_status(sk, hdev->id, MGMT_OP_LOAD_CONN_PARAM, | ||
| 5490 | MGMT_STATUS_INVALID_PARAMS); | ||
| 5491 | } | ||
| 5492 | |||
| 5493 | expected_len = sizeof(*cp) + param_count * | ||
| 5494 | sizeof(struct mgmt_conn_param); | ||
| 5495 | if (expected_len != len) { | ||
| 5496 | BT_ERR("load_conn_param: expected %u bytes, got %u bytes", | ||
| 5497 | expected_len, len); | ||
| 5498 | return cmd_status(sk, hdev->id, MGMT_OP_LOAD_CONN_PARAM, | ||
| 5499 | MGMT_STATUS_INVALID_PARAMS); | ||
| 5500 | } | ||
| 5501 | |||
| 5502 | BT_DBG("%s param_count %u", hdev->name, param_count); | ||
| 5503 | |||
| 5504 | hci_dev_lock(hdev); | ||
| 5505 | |||
| 5506 | hci_conn_params_clear_disabled(hdev); | ||
| 5507 | |||
| 5508 | for (i = 0; i < param_count; i++) { | ||
| 5509 | struct mgmt_conn_param *param = &cp->params[i]; | ||
| 5510 | struct hci_conn_params *hci_param; | ||
| 5511 | u16 min, max, latency, timeout; | ||
| 5512 | u8 addr_type; | ||
| 5513 | |||
| 5514 | BT_DBG("Adding %pMR (type %u)", ¶m->addr.bdaddr, | ||
| 5515 | param->addr.type); | ||
| 5516 | |||
| 5517 | if (param->addr.type == BDADDR_LE_PUBLIC) { | ||
| 5518 | addr_type = ADDR_LE_DEV_PUBLIC; | ||
| 5519 | } else if (param->addr.type == BDADDR_LE_RANDOM) { | ||
| 5520 | addr_type = ADDR_LE_DEV_RANDOM; | ||
| 5521 | } else { | ||
| 5522 | BT_ERR("Ignoring invalid connection parameters"); | ||
| 5523 | continue; | ||
| 5524 | } | ||
| 5525 | |||
| 5526 | min = le16_to_cpu(param->min_interval); | ||
| 5527 | max = le16_to_cpu(param->max_interval); | ||
| 5528 | latency = le16_to_cpu(param->latency); | ||
| 5529 | timeout = le16_to_cpu(param->timeout); | ||
| 5530 | |||
| 5531 | BT_DBG("min 0x%04x max 0x%04x latency 0x%04x timeout 0x%04x", | ||
| 5532 | min, max, latency, timeout); | ||
| 5533 | |||
| 5534 | if (hci_check_conn_params(min, max, latency, timeout) < 0) { | ||
| 5535 | BT_ERR("Ignoring invalid connection parameters"); | ||
| 5536 | continue; | ||
| 5537 | } | ||
| 5538 | |||
| 5539 | hci_param = hci_conn_params_add(hdev, ¶m->addr.bdaddr, | ||
| 5540 | addr_type); | ||
| 5541 | if (!hci_param) { | ||
| 5542 | BT_ERR("Failed to add connection parameters"); | ||
| 5543 | continue; | ||
| 5544 | } | ||
| 5545 | |||
| 5546 | hci_param->conn_min_interval = min; | ||
| 5547 | hci_param->conn_max_interval = max; | ||
| 5548 | hci_param->conn_latency = latency; | ||
| 5549 | hci_param->supervision_timeout = timeout; | ||
| 5550 | } | ||
| 5551 | |||
| 5552 | hci_dev_unlock(hdev); | ||
| 5553 | |||
| 5554 | return cmd_complete(sk, hdev->id, MGMT_OP_LOAD_CONN_PARAM, 0, NULL, 0); | ||
| 5555 | } | ||
| 5556 | |||
| 5557 | static int set_external_config(struct sock *sk, struct hci_dev *hdev, | ||
| 5558 | void *data, u16 len) | ||
| 5559 | { | ||
| 5560 | struct mgmt_cp_set_external_config *cp = data; | ||
| 5561 | bool changed; | ||
| 5562 | int err; | ||
| 5563 | |||
| 5564 | BT_DBG("%s", hdev->name); | ||
| 5565 | |||
| 5566 | if (hdev_is_powered(hdev)) | ||
| 5567 | return cmd_status(sk, hdev->id, MGMT_OP_SET_EXTERNAL_CONFIG, | ||
| 5568 | MGMT_STATUS_REJECTED); | ||
| 5569 | |||
| 5570 | if (cp->config != 0x00 && cp->config != 0x01) | ||
| 5571 | return cmd_status(sk, hdev->id, MGMT_OP_SET_EXTERNAL_CONFIG, | ||
| 5572 | MGMT_STATUS_INVALID_PARAMS); | ||
| 5573 | |||
| 5574 | if (!test_bit(HCI_QUIRK_EXTERNAL_CONFIG, &hdev->quirks)) | ||
| 5575 | return cmd_status(sk, hdev->id, MGMT_OP_SET_EXTERNAL_CONFIG, | ||
| 5576 | MGMT_STATUS_NOT_SUPPORTED); | ||
| 5577 | |||
| 5578 | hci_dev_lock(hdev); | ||
| 5579 | |||
| 5580 | if (cp->config) | ||
| 5581 | changed = !test_and_set_bit(HCI_EXT_CONFIGURED, | ||
| 5582 | &hdev->dev_flags); | ||
| 5583 | else | ||
| 5584 | changed = test_and_clear_bit(HCI_EXT_CONFIGURED, | ||
| 5585 | &hdev->dev_flags); | ||
| 5586 | |||
| 5587 | err = send_options_rsp(sk, MGMT_OP_SET_EXTERNAL_CONFIG, hdev); | ||
| 5588 | if (err < 0) | ||
| 5589 | goto unlock; | ||
| 5590 | |||
| 5591 | if (!changed) | ||
| 5592 | goto unlock; | ||
| 5593 | |||
| 5594 | err = new_options(hdev, sk); | ||
| 5595 | |||
| 5596 | if (test_bit(HCI_UNCONFIGURED, &hdev->dev_flags) == is_configured(hdev)) { | ||
| 5597 | mgmt_index_removed(hdev); | ||
| 5598 | |||
| 5599 | if (test_and_change_bit(HCI_UNCONFIGURED, &hdev->dev_flags)) { | ||
| 5600 | set_bit(HCI_CONFIG, &hdev->dev_flags); | ||
| 5601 | set_bit(HCI_AUTO_OFF, &hdev->dev_flags); | ||
| 5602 | |||
| 5603 | queue_work(hdev->req_workqueue, &hdev->power_on); | ||
| 5604 | } else { | ||
| 5605 | set_bit(HCI_RAW, &hdev->flags); | ||
| 5606 | mgmt_index_added(hdev); | ||
| 5607 | } | ||
| 5608 | } | ||
| 5609 | |||
| 5610 | unlock: | ||
| 5611 | hci_dev_unlock(hdev); | ||
| 5612 | return err; | ||
| 5613 | } | ||
| 5614 | |||
| 5615 | static int set_public_address(struct sock *sk, struct hci_dev *hdev, | ||
| 5616 | void *data, u16 len) | ||
| 5617 | { | ||
| 5618 | struct mgmt_cp_set_public_address *cp = data; | ||
| 5619 | bool changed; | ||
| 5620 | int err; | ||
| 5621 | |||
| 5622 | BT_DBG("%s", hdev->name); | ||
| 5623 | |||
| 5624 | if (hdev_is_powered(hdev)) | ||
| 5625 | return cmd_status(sk, hdev->id, MGMT_OP_SET_PUBLIC_ADDRESS, | ||
| 5626 | MGMT_STATUS_REJECTED); | ||
| 5627 | |||
| 5628 | if (!bacmp(&cp->bdaddr, BDADDR_ANY)) | ||
| 5629 | return cmd_status(sk, hdev->id, MGMT_OP_SET_PUBLIC_ADDRESS, | ||
| 5630 | MGMT_STATUS_INVALID_PARAMS); | ||
| 5631 | |||
| 5632 | if (!hdev->set_bdaddr) | ||
| 5633 | return cmd_status(sk, hdev->id, MGMT_OP_SET_PUBLIC_ADDRESS, | ||
| 5634 | MGMT_STATUS_NOT_SUPPORTED); | ||
| 5635 | |||
| 5636 | hci_dev_lock(hdev); | ||
| 5637 | |||
| 5638 | changed = !!bacmp(&hdev->public_addr, &cp->bdaddr); | ||
| 5639 | bacpy(&hdev->public_addr, &cp->bdaddr); | ||
| 5640 | |||
| 5641 | err = send_options_rsp(sk, MGMT_OP_SET_PUBLIC_ADDRESS, hdev); | ||
| 5642 | if (err < 0) | ||
| 5643 | goto unlock; | ||
| 5644 | |||
| 5645 | if (!changed) | ||
| 5646 | goto unlock; | ||
| 5647 | |||
| 5648 | if (test_bit(HCI_UNCONFIGURED, &hdev->dev_flags)) | ||
| 5649 | err = new_options(hdev, sk); | ||
| 5650 | |||
| 5651 | if (is_configured(hdev)) { | ||
| 5652 | mgmt_index_removed(hdev); | ||
| 5653 | |||
| 5654 | clear_bit(HCI_UNCONFIGURED, &hdev->dev_flags); | ||
| 5655 | |||
| 5656 | set_bit(HCI_CONFIG, &hdev->dev_flags); | ||
| 5657 | set_bit(HCI_AUTO_OFF, &hdev->dev_flags); | ||
| 5658 | |||
| 5659 | queue_work(hdev->req_workqueue, &hdev->power_on); | ||
| 5660 | } | ||
| 5661 | |||
| 5662 | unlock: | ||
| 5663 | hci_dev_unlock(hdev); | ||
| 5664 | return err; | ||
| 5665 | } | ||
| 5666 | |||
| 4793 | static const struct mgmt_handler { | 5667 | static const struct mgmt_handler { |
| 4794 | int (*func) (struct sock *sk, struct hci_dev *hdev, void *data, | 5668 | int (*func) (struct sock *sk, struct hci_dev *hdev, void *data, |
| 4795 | u16 data_len); | 5669 | u16 data_len); |
| @@ -4805,7 +5679,7 @@ static const struct mgmt_handler { | |||
| 4805 | { set_discoverable, false, MGMT_SET_DISCOVERABLE_SIZE }, | 5679 | { set_discoverable, false, MGMT_SET_DISCOVERABLE_SIZE }, |
| 4806 | { set_connectable, false, MGMT_SETTING_SIZE }, | 5680 | { set_connectable, false, MGMT_SETTING_SIZE }, |
| 4807 | { set_fast_connectable, false, MGMT_SETTING_SIZE }, | 5681 | { set_fast_connectable, false, MGMT_SETTING_SIZE }, |
| 4808 | { set_pairable, false, MGMT_SETTING_SIZE }, | 5682 | { set_bondable, false, MGMT_SETTING_SIZE }, |
| 4809 | { set_link_security, false, MGMT_SETTING_SIZE }, | 5683 | { set_link_security, false, MGMT_SETTING_SIZE }, |
| 4810 | { set_ssp, false, MGMT_SETTING_SIZE }, | 5684 | { set_ssp, false, MGMT_SETTING_SIZE }, |
| 4811 | { set_hs, false, MGMT_SETTING_SIZE }, | 5685 | { set_hs, false, MGMT_SETTING_SIZE }, |
| @@ -4846,9 +5720,16 @@ static const struct mgmt_handler { | |||
| 4846 | { set_privacy, false, MGMT_SET_PRIVACY_SIZE }, | 5720 | { set_privacy, false, MGMT_SET_PRIVACY_SIZE }, |
| 4847 | { load_irks, true, MGMT_LOAD_IRKS_SIZE }, | 5721 | { load_irks, true, MGMT_LOAD_IRKS_SIZE }, |
| 4848 | { get_conn_info, false, MGMT_GET_CONN_INFO_SIZE }, | 5722 | { get_conn_info, false, MGMT_GET_CONN_INFO_SIZE }, |
| 5723 | { get_clock_info, false, MGMT_GET_CLOCK_INFO_SIZE }, | ||
| 5724 | { add_device, false, MGMT_ADD_DEVICE_SIZE }, | ||
| 5725 | { remove_device, false, MGMT_REMOVE_DEVICE_SIZE }, | ||
| 5726 | { load_conn_param, true, MGMT_LOAD_CONN_PARAM_SIZE }, | ||
| 5727 | { read_unconf_index_list, false, MGMT_READ_UNCONF_INDEX_LIST_SIZE }, | ||
| 5728 | { read_config_info, false, MGMT_READ_CONFIG_INFO_SIZE }, | ||
| 5729 | { set_external_config, false, MGMT_SET_EXTERNAL_CONFIG_SIZE }, | ||
| 5730 | { set_public_address, false, MGMT_SET_PUBLIC_ADDRESS_SIZE }, | ||
| 4849 | }; | 5731 | }; |
| 4850 | 5732 | ||
| 4851 | |||
| 4852 | int mgmt_control(struct sock *sk, struct msghdr *msg, size_t msglen) | 5733 | int mgmt_control(struct sock *sk, struct msghdr *msg, size_t msglen) |
| 4853 | { | 5734 | { |
| 4854 | void *buf; | 5735 | void *buf; |
| @@ -4892,11 +5773,21 @@ int mgmt_control(struct sock *sk, struct msghdr *msg, size_t msglen) | |||
| 4892 | } | 5773 | } |
| 4893 | 5774 | ||
| 4894 | if (test_bit(HCI_SETUP, &hdev->dev_flags) || | 5775 | if (test_bit(HCI_SETUP, &hdev->dev_flags) || |
| 5776 | test_bit(HCI_CONFIG, &hdev->dev_flags) || | ||
| 4895 | test_bit(HCI_USER_CHANNEL, &hdev->dev_flags)) { | 5777 | test_bit(HCI_USER_CHANNEL, &hdev->dev_flags)) { |
| 4896 | err = cmd_status(sk, index, opcode, | 5778 | err = cmd_status(sk, index, opcode, |
| 4897 | MGMT_STATUS_INVALID_INDEX); | 5779 | MGMT_STATUS_INVALID_INDEX); |
| 4898 | goto done; | 5780 | goto done; |
| 4899 | } | 5781 | } |
| 5782 | |||
| 5783 | if (test_bit(HCI_UNCONFIGURED, &hdev->dev_flags) && | ||
| 5784 | opcode != MGMT_OP_READ_CONFIG_INFO && | ||
| 5785 | opcode != MGMT_OP_SET_EXTERNAL_CONFIG && | ||
| 5786 | opcode != MGMT_OP_SET_PUBLIC_ADDRESS) { | ||
| 5787 | err = cmd_status(sk, index, opcode, | ||
| 5788 | MGMT_STATUS_INVALID_INDEX); | ||
| 5789 | goto done; | ||
| 5790 | } | ||
| 4900 | } | 5791 | } |
| 4901 | 5792 | ||
| 4902 | if (opcode >= ARRAY_SIZE(mgmt_handlers) || | 5793 | if (opcode >= ARRAY_SIZE(mgmt_handlers) || |
| @@ -4907,8 +5798,15 @@ int mgmt_control(struct sock *sk, struct msghdr *msg, size_t msglen) | |||
| 4907 | goto done; | 5798 | goto done; |
| 4908 | } | 5799 | } |
| 4909 | 5800 | ||
| 4910 | if ((hdev && opcode < MGMT_OP_READ_INFO) || | 5801 | if (hdev && (opcode <= MGMT_OP_READ_INDEX_LIST || |
| 4911 | (!hdev && opcode >= MGMT_OP_READ_INFO)) { | 5802 | opcode == MGMT_OP_READ_UNCONF_INDEX_LIST)) { |
| 5803 | err = cmd_status(sk, index, opcode, | ||
| 5804 | MGMT_STATUS_INVALID_INDEX); | ||
| 5805 | goto done; | ||
| 5806 | } | ||
| 5807 | |||
| 5808 | if (!hdev && (opcode > MGMT_OP_READ_INDEX_LIST && | ||
| 5809 | opcode != MGMT_OP_READ_UNCONF_INDEX_LIST)) { | ||
| 4912 | err = cmd_status(sk, index, opcode, | 5810 | err = cmd_status(sk, index, opcode, |
| 4913 | MGMT_STATUS_INVALID_INDEX); | 5811 | MGMT_STATUS_INVALID_INDEX); |
| 4914 | goto done; | 5812 | goto done; |
| @@ -4947,7 +5845,13 @@ void mgmt_index_added(struct hci_dev *hdev) | |||
| 4947 | if (hdev->dev_type != HCI_BREDR) | 5845 | if (hdev->dev_type != HCI_BREDR) |
| 4948 | return; | 5846 | return; |
| 4949 | 5847 | ||
| 4950 | mgmt_event(MGMT_EV_INDEX_ADDED, hdev, NULL, 0, NULL); | 5848 | if (test_bit(HCI_QUIRK_RAW_DEVICE, &hdev->quirks)) |
| 5849 | return; | ||
| 5850 | |||
| 5851 | if (test_bit(HCI_UNCONFIGURED, &hdev->dev_flags)) | ||
| 5852 | mgmt_event(MGMT_EV_UNCONF_INDEX_ADDED, hdev, NULL, 0, NULL); | ||
| 5853 | else | ||
| 5854 | mgmt_event(MGMT_EV_INDEX_ADDED, hdev, NULL, 0, NULL); | ||
| 4951 | } | 5855 | } |
| 4952 | 5856 | ||
| 4953 | void mgmt_index_removed(struct hci_dev *hdev) | 5857 | void mgmt_index_removed(struct hci_dev *hdev) |
| @@ -4957,20 +5861,42 @@ void mgmt_index_removed(struct hci_dev *hdev) | |||
| 4957 | if (hdev->dev_type != HCI_BREDR) | 5861 | if (hdev->dev_type != HCI_BREDR) |
| 4958 | return; | 5862 | return; |
| 4959 | 5863 | ||
| 5864 | if (test_bit(HCI_QUIRK_RAW_DEVICE, &hdev->quirks)) | ||
| 5865 | return; | ||
| 5866 | |||
| 4960 | mgmt_pending_foreach(0, hdev, cmd_status_rsp, &status); | 5867 | mgmt_pending_foreach(0, hdev, cmd_status_rsp, &status); |
| 4961 | 5868 | ||
| 4962 | mgmt_event(MGMT_EV_INDEX_REMOVED, hdev, NULL, 0, NULL); | 5869 | if (test_bit(HCI_UNCONFIGURED, &hdev->dev_flags)) |
| 5870 | mgmt_event(MGMT_EV_UNCONF_INDEX_REMOVED, hdev, NULL, 0, NULL); | ||
| 5871 | else | ||
| 5872 | mgmt_event(MGMT_EV_INDEX_REMOVED, hdev, NULL, 0, NULL); | ||
| 4963 | } | 5873 | } |
| 4964 | 5874 | ||
| 4965 | /* This function requires the caller holds hdev->lock */ | 5875 | /* This function requires the caller holds hdev->lock */ |
| 4966 | static void restart_le_auto_conns(struct hci_dev *hdev) | 5876 | static void restart_le_actions(struct hci_dev *hdev) |
| 4967 | { | 5877 | { |
| 4968 | struct hci_conn_params *p; | 5878 | struct hci_conn_params *p; |
| 4969 | 5879 | ||
| 4970 | list_for_each_entry(p, &hdev->le_conn_params, list) { | 5880 | list_for_each_entry(p, &hdev->le_conn_params, list) { |
| 4971 | if (p->auto_connect == HCI_AUTO_CONN_ALWAYS) | 5881 | /* Needed for AUTO_OFF case where might not "really" |
| 4972 | hci_pend_le_conn_add(hdev, &p->addr, p->addr_type); | 5882 | * have been powered off. |
| 5883 | */ | ||
| 5884 | list_del_init(&p->action); | ||
| 5885 | |||
| 5886 | switch (p->auto_connect) { | ||
| 5887 | case HCI_AUTO_CONN_DIRECT: | ||
| 5888 | case HCI_AUTO_CONN_ALWAYS: | ||
| 5889 | list_add(&p->action, &hdev->pend_le_conns); | ||
| 5890 | break; | ||
| 5891 | case HCI_AUTO_CONN_REPORT: | ||
| 5892 | list_add(&p->action, &hdev->pend_le_reports); | ||
| 5893 | break; | ||
| 5894 | default: | ||
| 5895 | break; | ||
| 5896 | } | ||
| 4973 | } | 5897 | } |
| 5898 | |||
| 5899 | hci_update_background_scan(hdev); | ||
| 4974 | } | 5900 | } |
| 4975 | 5901 | ||
| 4976 | static void powered_complete(struct hci_dev *hdev, u8 status) | 5902 | static void powered_complete(struct hci_dev *hdev, u8 status) |
| @@ -4981,7 +5907,7 @@ static void powered_complete(struct hci_dev *hdev, u8 status) | |||
| 4981 | 5907 | ||
| 4982 | hci_dev_lock(hdev); | 5908 | hci_dev_lock(hdev); |
| 4983 | 5909 | ||
| 4984 | restart_le_auto_conns(hdev); | 5910 | restart_le_actions(hdev); |
| 4985 | 5911 | ||
| 4986 | mgmt_pending_foreach(MGMT_OP_SET_POWERED, hdev, settings_rsp, &match); | 5912 | mgmt_pending_foreach(MGMT_OP_SET_POWERED, hdev, settings_rsp, &match); |
| 4987 | 5913 | ||
| @@ -5011,8 +5937,8 @@ static int powered_update_hci(struct hci_dev *hdev) | |||
| 5011 | lmp_bredr_capable(hdev)) { | 5937 | lmp_bredr_capable(hdev)) { |
| 5012 | struct hci_cp_write_le_host_supported cp; | 5938 | struct hci_cp_write_le_host_supported cp; |
| 5013 | 5939 | ||
| 5014 | cp.le = 1; | 5940 | cp.le = 0x01; |
| 5015 | cp.simul = lmp_le_br_capable(hdev); | 5941 | cp.simul = 0x00; |
| 5016 | 5942 | ||
| 5017 | /* Check first if we already have the right | 5943 | /* Check first if we already have the right |
| 5018 | * host state (host features set) | 5944 | * host state (host features set) |
| @@ -5138,92 +6064,6 @@ void mgmt_discoverable_timeout(struct hci_dev *hdev) | |||
| 5138 | hci_dev_unlock(hdev); | 6064 | hci_dev_unlock(hdev); |
| 5139 | } | 6065 | } |
| 5140 | 6066 | ||
| 5141 | void mgmt_discoverable(struct hci_dev *hdev, u8 discoverable) | ||
| 5142 | { | ||
| 5143 | bool changed; | ||
| 5144 | |||
| 5145 | /* Nothing needed here if there's a pending command since that | ||
| 5146 | * commands request completion callback takes care of everything | ||
| 5147 | * necessary. | ||
| 5148 | */ | ||
| 5149 | if (mgmt_pending_find(MGMT_OP_SET_DISCOVERABLE, hdev)) | ||
| 5150 | return; | ||
| 5151 | |||
| 5152 | /* Powering off may clear the scan mode - don't let that interfere */ | ||
| 5153 | if (!discoverable && mgmt_pending_find(MGMT_OP_SET_POWERED, hdev)) | ||
| 5154 | return; | ||
| 5155 | |||
| 5156 | if (discoverable) { | ||
| 5157 | changed = !test_and_set_bit(HCI_DISCOVERABLE, &hdev->dev_flags); | ||
| 5158 | } else { | ||
| 5159 | clear_bit(HCI_LIMITED_DISCOVERABLE, &hdev->dev_flags); | ||
| 5160 | changed = test_and_clear_bit(HCI_DISCOVERABLE, &hdev->dev_flags); | ||
| 5161 | } | ||
| 5162 | |||
| 5163 | if (changed) { | ||
| 5164 | struct hci_request req; | ||
| 5165 | |||
| 5166 | /* In case this change in discoverable was triggered by | ||
| 5167 | * a disabling of connectable there could be a need to | ||
| 5168 | * update the advertising flags. | ||
| 5169 | */ | ||
| 5170 | hci_req_init(&req, hdev); | ||
| 5171 | update_adv_data(&req); | ||
| 5172 | hci_req_run(&req, NULL); | ||
| 5173 | |||
| 5174 | new_settings(hdev, NULL); | ||
| 5175 | } | ||
| 5176 | } | ||
| 5177 | |||
| 5178 | void mgmt_connectable(struct hci_dev *hdev, u8 connectable) | ||
| 5179 | { | ||
| 5180 | bool changed; | ||
| 5181 | |||
| 5182 | /* Nothing needed here if there's a pending command since that | ||
| 5183 | * commands request completion callback takes care of everything | ||
| 5184 | * necessary. | ||
| 5185 | */ | ||
| 5186 | if (mgmt_pending_find(MGMT_OP_SET_CONNECTABLE, hdev)) | ||
| 5187 | return; | ||
| 5188 | |||
| 5189 | /* Powering off may clear the scan mode - don't let that interfere */ | ||
| 5190 | if (!connectable && mgmt_pending_find(MGMT_OP_SET_POWERED, hdev)) | ||
| 5191 | return; | ||
| 5192 | |||
| 5193 | if (connectable) | ||
| 5194 | changed = !test_and_set_bit(HCI_CONNECTABLE, &hdev->dev_flags); | ||
| 5195 | else | ||
| 5196 | changed = test_and_clear_bit(HCI_CONNECTABLE, &hdev->dev_flags); | ||
| 5197 | |||
| 5198 | if (changed) | ||
| 5199 | new_settings(hdev, NULL); | ||
| 5200 | } | ||
| 5201 | |||
| 5202 | void mgmt_advertising(struct hci_dev *hdev, u8 advertising) | ||
| 5203 | { | ||
| 5204 | /* Powering off may stop advertising - don't let that interfere */ | ||
| 5205 | if (!advertising && mgmt_pending_find(MGMT_OP_SET_POWERED, hdev)) | ||
| 5206 | return; | ||
| 5207 | |||
| 5208 | if (advertising) | ||
| 5209 | set_bit(HCI_ADVERTISING, &hdev->dev_flags); | ||
| 5210 | else | ||
| 5211 | clear_bit(HCI_ADVERTISING, &hdev->dev_flags); | ||
| 5212 | } | ||
| 5213 | |||
| 5214 | void mgmt_write_scan_failed(struct hci_dev *hdev, u8 scan, u8 status) | ||
| 5215 | { | ||
| 5216 | u8 mgmt_err = mgmt_status(status); | ||
| 5217 | |||
| 5218 | if (scan & SCAN_PAGE) | ||
| 5219 | mgmt_pending_foreach(MGMT_OP_SET_CONNECTABLE, hdev, | ||
| 5220 | cmd_status_rsp, &mgmt_err); | ||
| 5221 | |||
| 5222 | if (scan & SCAN_INQUIRY) | ||
| 5223 | mgmt_pending_foreach(MGMT_OP_SET_DISCOVERABLE, hdev, | ||
| 5224 | cmd_status_rsp, &mgmt_err); | ||
| 5225 | } | ||
| 5226 | |||
| 5227 | void mgmt_new_link_key(struct hci_dev *hdev, struct link_key *key, | 6067 | void mgmt_new_link_key(struct hci_dev *hdev, struct link_key *key, |
| 5228 | bool persistent) | 6068 | bool persistent) |
| 5229 | { | 6069 | { |
| @@ -5279,7 +6119,7 @@ void mgmt_new_ltk(struct hci_dev *hdev, struct smp_ltk *key, bool persistent) | |||
| 5279 | ev.key.ediv = key->ediv; | 6119 | ev.key.ediv = key->ediv; |
| 5280 | ev.key.rand = key->rand; | 6120 | ev.key.rand = key->rand; |
| 5281 | 6121 | ||
| 5282 | if (key->type == HCI_SMP_LTK) | 6122 | if (key->type == SMP_LTK) |
| 5283 | ev.key.master = 1; | 6123 | ev.key.master = 1; |
| 5284 | 6124 | ||
| 5285 | memcpy(ev.key.val, key->val, sizeof(key->val)); | 6125 | memcpy(ev.key.val, key->val, sizeof(key->val)); |
| @@ -5347,6 +6187,27 @@ void mgmt_new_csrk(struct hci_dev *hdev, struct smp_csrk *csrk, | |||
| 5347 | mgmt_event(MGMT_EV_NEW_CSRK, hdev, &ev, sizeof(ev), NULL); | 6187 | mgmt_event(MGMT_EV_NEW_CSRK, hdev, &ev, sizeof(ev), NULL); |
| 5348 | } | 6188 | } |
| 5349 | 6189 | ||
| 6190 | void mgmt_new_conn_param(struct hci_dev *hdev, bdaddr_t *bdaddr, | ||
| 6191 | u8 bdaddr_type, u8 store_hint, u16 min_interval, | ||
| 6192 | u16 max_interval, u16 latency, u16 timeout) | ||
| 6193 | { | ||
| 6194 | struct mgmt_ev_new_conn_param ev; | ||
| 6195 | |||
| 6196 | if (!hci_is_identity_address(bdaddr, bdaddr_type)) | ||
| 6197 | return; | ||
| 6198 | |||
| 6199 | memset(&ev, 0, sizeof(ev)); | ||
| 6200 | bacpy(&ev.addr.bdaddr, bdaddr); | ||
| 6201 | ev.addr.type = link_to_bdaddr(LE_LINK, bdaddr_type); | ||
| 6202 | ev.store_hint = store_hint; | ||
| 6203 | ev.min_interval = cpu_to_le16(min_interval); | ||
| 6204 | ev.max_interval = cpu_to_le16(max_interval); | ||
| 6205 | ev.latency = cpu_to_le16(latency); | ||
| 6206 | ev.timeout = cpu_to_le16(timeout); | ||
| 6207 | |||
| 6208 | mgmt_event(MGMT_EV_NEW_CONN_PARAM, hdev, &ev, sizeof(ev), NULL); | ||
| 6209 | } | ||
| 6210 | |||
| 5350 | static inline u16 eir_append_data(u8 *eir, u16 eir_len, u8 type, u8 *data, | 6211 | static inline u16 eir_append_data(u8 *eir, u16 eir_len, u8 type, u8 *data, |
| 5351 | u8 data_len) | 6212 | u8 data_len) |
| 5352 | { | 6213 | { |
| @@ -5765,10 +6626,14 @@ void mgmt_ssp_enable_complete(struct hci_dev *hdev, u8 enable, u8 status) | |||
| 5765 | 6626 | ||
| 5766 | hci_req_init(&req, hdev); | 6627 | hci_req_init(&req, hdev); |
| 5767 | 6628 | ||
| 5768 | if (test_bit(HCI_SSP_ENABLED, &hdev->dev_flags)) | 6629 | if (test_bit(HCI_SSP_ENABLED, &hdev->dev_flags)) { |
| 6630 | if (test_bit(HCI_USE_DEBUG_KEYS, &hdev->dev_flags)) | ||
| 6631 | hci_req_add(&req, HCI_OP_WRITE_SSP_DEBUG_MODE, | ||
| 6632 | sizeof(enable), &enable); | ||
| 5769 | update_eir(&req); | 6633 | update_eir(&req); |
| 5770 | else | 6634 | } else { |
| 5771 | clear_eir(&req); | 6635 | clear_eir(&req); |
| 6636 | } | ||
| 5772 | 6637 | ||
| 5773 | hci_req_run(&req, NULL); | 6638 | hci_req_run(&req, NULL); |
| 5774 | } | 6639 | } |
| @@ -5912,17 +6777,23 @@ void mgmt_read_local_oob_data_complete(struct hci_dev *hdev, u8 *hash192, | |||
| 5912 | } | 6777 | } |
| 5913 | 6778 | ||
| 5914 | void mgmt_device_found(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type, | 6779 | void mgmt_device_found(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type, |
| 5915 | u8 addr_type, u8 *dev_class, s8 rssi, u8 cfm_name, | 6780 | u8 addr_type, u8 *dev_class, s8 rssi, u32 flags, |
| 5916 | u8 ssp, u8 *eir, u16 eir_len, u8 *scan_rsp, | 6781 | u8 *eir, u16 eir_len, u8 *scan_rsp, u8 scan_rsp_len) |
| 5917 | u8 scan_rsp_len) | ||
| 5918 | { | 6782 | { |
| 5919 | char buf[512]; | 6783 | char buf[512]; |
| 5920 | struct mgmt_ev_device_found *ev = (void *) buf; | 6784 | struct mgmt_ev_device_found *ev = (void *) buf; |
| 5921 | struct smp_irk *irk; | ||
| 5922 | size_t ev_size; | 6785 | size_t ev_size; |
| 5923 | 6786 | ||
| 5924 | if (!hci_discovery_active(hdev)) | 6787 | /* Don't send events for a non-kernel initiated discovery. With |
| 5925 | return; | 6788 | * LE one exception is if we have pend_le_reports > 0 in which |
| 6789 | * case we're doing passive scanning and want these events. | ||
| 6790 | */ | ||
| 6791 | if (!hci_discovery_active(hdev)) { | ||
| 6792 | if (link_type == ACL_LINK) | ||
| 6793 | return; | ||
| 6794 | if (link_type == LE_LINK && list_empty(&hdev->pend_le_reports)) | ||
| 6795 | return; | ||
| 6796 | } | ||
| 5926 | 6797 | ||
| 5927 | /* Make sure that the buffer is big enough. The 5 extra bytes | 6798 | /* Make sure that the buffer is big enough. The 5 extra bytes |
| 5928 | * are for the potential CoD field. | 6799 | * are for the potential CoD field. |
| @@ -5932,20 +6803,10 @@ void mgmt_device_found(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type, | |||
| 5932 | 6803 | ||
| 5933 | memset(buf, 0, sizeof(buf)); | 6804 | memset(buf, 0, sizeof(buf)); |
| 5934 | 6805 | ||
| 5935 | irk = hci_get_irk(hdev, bdaddr, addr_type); | 6806 | bacpy(&ev->addr.bdaddr, bdaddr); |
| 5936 | if (irk) { | 6807 | ev->addr.type = link_to_bdaddr(link_type, addr_type); |
| 5937 | bacpy(&ev->addr.bdaddr, &irk->bdaddr); | ||
| 5938 | ev->addr.type = link_to_bdaddr(link_type, irk->addr_type); | ||
| 5939 | } else { | ||
| 5940 | bacpy(&ev->addr.bdaddr, bdaddr); | ||
| 5941 | ev->addr.type = link_to_bdaddr(link_type, addr_type); | ||
| 5942 | } | ||
| 5943 | |||
| 5944 | ev->rssi = rssi; | 6808 | ev->rssi = rssi; |
| 5945 | if (cfm_name) | 6809 | ev->flags = cpu_to_le32(flags); |
| 5946 | ev->flags |= cpu_to_le32(MGMT_DEV_FOUND_CONFIRM_NAME); | ||
| 5947 | if (!ssp) | ||
| 5948 | ev->flags |= cpu_to_le32(MGMT_DEV_FOUND_LEGACY_PAIRING); | ||
| 5949 | 6810 | ||
| 5950 | if (eir_len > 0) | 6811 | if (eir_len > 0) |
| 5951 | memcpy(ev->eir, eir, eir_len); | 6812 | memcpy(ev->eir, eir, eir_len); |
| @@ -6013,63 +6874,19 @@ void mgmt_discovering(struct hci_dev *hdev, u8 discovering) | |||
| 6013 | mgmt_event(MGMT_EV_DISCOVERING, hdev, &ev, sizeof(ev), NULL); | 6874 | mgmt_event(MGMT_EV_DISCOVERING, hdev, &ev, sizeof(ev), NULL); |
| 6014 | } | 6875 | } |
| 6015 | 6876 | ||
| 6016 | int mgmt_device_blocked(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 type) | ||
| 6017 | { | ||
| 6018 | struct pending_cmd *cmd; | ||
| 6019 | struct mgmt_ev_device_blocked ev; | ||
| 6020 | |||
| 6021 | cmd = mgmt_pending_find(MGMT_OP_BLOCK_DEVICE, hdev); | ||
| 6022 | |||
| 6023 | bacpy(&ev.addr.bdaddr, bdaddr); | ||
| 6024 | ev.addr.type = type; | ||
| 6025 | |||
| 6026 | return mgmt_event(MGMT_EV_DEVICE_BLOCKED, hdev, &ev, sizeof(ev), | ||
| 6027 | cmd ? cmd->sk : NULL); | ||
| 6028 | } | ||
| 6029 | |||
| 6030 | int mgmt_device_unblocked(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 type) | ||
| 6031 | { | ||
| 6032 | struct pending_cmd *cmd; | ||
| 6033 | struct mgmt_ev_device_unblocked ev; | ||
| 6034 | |||
| 6035 | cmd = mgmt_pending_find(MGMT_OP_UNBLOCK_DEVICE, hdev); | ||
| 6036 | |||
| 6037 | bacpy(&ev.addr.bdaddr, bdaddr); | ||
| 6038 | ev.addr.type = type; | ||
| 6039 | |||
| 6040 | return mgmt_event(MGMT_EV_DEVICE_UNBLOCKED, hdev, &ev, sizeof(ev), | ||
| 6041 | cmd ? cmd->sk : NULL); | ||
| 6042 | } | ||
| 6043 | |||
| 6044 | static void adv_enable_complete(struct hci_dev *hdev, u8 status) | 6877 | static void adv_enable_complete(struct hci_dev *hdev, u8 status) |
| 6045 | { | 6878 | { |
| 6046 | BT_DBG("%s status %u", hdev->name, status); | 6879 | BT_DBG("%s status %u", hdev->name, status); |
| 6047 | |||
| 6048 | /* Clear the advertising mgmt setting if we failed to re-enable it */ | ||
| 6049 | if (status) { | ||
| 6050 | clear_bit(HCI_ADVERTISING, &hdev->dev_flags); | ||
| 6051 | new_settings(hdev, NULL); | ||
| 6052 | } | ||
| 6053 | } | 6880 | } |
| 6054 | 6881 | ||
| 6055 | void mgmt_reenable_advertising(struct hci_dev *hdev) | 6882 | void mgmt_reenable_advertising(struct hci_dev *hdev) |
| 6056 | { | 6883 | { |
| 6057 | struct hci_request req; | 6884 | struct hci_request req; |
| 6058 | 6885 | ||
| 6059 | if (hci_conn_num(hdev, LE_LINK) > 0) | ||
| 6060 | return; | ||
| 6061 | |||
| 6062 | if (!test_bit(HCI_ADVERTISING, &hdev->dev_flags)) | 6886 | if (!test_bit(HCI_ADVERTISING, &hdev->dev_flags)) |
| 6063 | return; | 6887 | return; |
| 6064 | 6888 | ||
| 6065 | hci_req_init(&req, hdev); | 6889 | hci_req_init(&req, hdev); |
| 6066 | enable_advertising(&req); | 6890 | enable_advertising(&req); |
| 6067 | 6891 | hci_req_run(&req, adv_enable_complete); | |
| 6068 | /* If this fails we have no option but to let user space know | ||
| 6069 | * that we've disabled advertising. | ||
| 6070 | */ | ||
| 6071 | if (hci_req_run(&req, adv_enable_complete) < 0) { | ||
| 6072 | clear_bit(HCI_ADVERTISING, &hdev->dev_flags); | ||
| 6073 | new_settings(hdev, NULL); | ||
| 6074 | } | ||
| 6075 | } | 6892 | } |
diff --git a/net/bluetooth/rfcomm/core.c b/net/bluetooth/rfcomm/core.c index 754b6fe4f742..af73bc3acb40 100644 --- a/net/bluetooth/rfcomm/core.c +++ b/net/bluetooth/rfcomm/core.c | |||
| @@ -227,7 +227,8 @@ static int rfcomm_check_security(struct rfcomm_dlc *d) | |||
| 227 | break; | 227 | break; |
| 228 | } | 228 | } |
| 229 | 229 | ||
| 230 | return hci_conn_security(conn->hcon, d->sec_level, auth_type); | 230 | return hci_conn_security(conn->hcon, d->sec_level, auth_type, |
| 231 | d->out); | ||
| 231 | } | 232 | } |
| 232 | 233 | ||
| 233 | static void rfcomm_session_timeout(unsigned long arg) | 234 | static void rfcomm_session_timeout(unsigned long arg) |
| @@ -1909,10 +1910,13 @@ static struct rfcomm_session *rfcomm_process_rx(struct rfcomm_session *s) | |||
| 1909 | /* Get data directly from socket receive queue without copying it. */ | 1910 | /* Get data directly from socket receive queue without copying it. */ |
| 1910 | while ((skb = skb_dequeue(&sk->sk_receive_queue))) { | 1911 | while ((skb = skb_dequeue(&sk->sk_receive_queue))) { |
| 1911 | skb_orphan(skb); | 1912 | skb_orphan(skb); |
| 1912 | if (!skb_linearize(skb)) | 1913 | if (!skb_linearize(skb)) { |
| 1913 | s = rfcomm_recv_frame(s, skb); | 1914 | s = rfcomm_recv_frame(s, skb); |
| 1914 | else | 1915 | if (!s) |
| 1916 | break; | ||
| 1917 | } else { | ||
| 1915 | kfree_skb(skb); | 1918 | kfree_skb(skb); |
| 1919 | } | ||
| 1916 | } | 1920 | } |
| 1917 | 1921 | ||
| 1918 | if (s && (sk->sk_state == BT_CLOSED)) | 1922 | if (s && (sk->sk_state == BT_CLOSED)) |
diff --git a/net/bluetooth/rfcomm/sock.c b/net/bluetooth/rfcomm/sock.c index c603a5eb4720..8bbbb5ec468c 100644 --- a/net/bluetooth/rfcomm/sock.c +++ b/net/bluetooth/rfcomm/sock.c | |||
| @@ -918,7 +918,8 @@ static int rfcomm_sock_shutdown(struct socket *sock, int how) | |||
| 918 | sk->sk_shutdown = SHUTDOWN_MASK; | 918 | sk->sk_shutdown = SHUTDOWN_MASK; |
| 919 | __rfcomm_sock_close(sk); | 919 | __rfcomm_sock_close(sk); |
| 920 | 920 | ||
| 921 | if (sock_flag(sk, SOCK_LINGER) && sk->sk_lingertime) | 921 | if (sock_flag(sk, SOCK_LINGER) && sk->sk_lingertime && |
| 922 | !(current->flags & PF_EXITING)) | ||
| 922 | err = bt_sock_wait_state(sk, BT_CLOSED, sk->sk_lingertime); | 923 | err = bt_sock_wait_state(sk, BT_CLOSED, sk->sk_lingertime); |
| 923 | } | 924 | } |
| 924 | release_sock(sk); | 925 | release_sock(sk); |
diff --git a/net/bluetooth/sco.c b/net/bluetooth/sco.c index c06dbd3938e8..7ee9e4ab00f8 100644 --- a/net/bluetooth/sco.c +++ b/net/bluetooth/sco.c | |||
| @@ -40,13 +40,38 @@ static struct bt_sock_list sco_sk_list = { | |||
| 40 | .lock = __RW_LOCK_UNLOCKED(sco_sk_list.lock) | 40 | .lock = __RW_LOCK_UNLOCKED(sco_sk_list.lock) |
| 41 | }; | 41 | }; |
| 42 | 42 | ||
| 43 | static void __sco_chan_add(struct sco_conn *conn, struct sock *sk, struct sock *parent); | 43 | /* ---- SCO connections ---- */ |
| 44 | static void sco_chan_del(struct sock *sk, int err); | 44 | struct sco_conn { |
| 45 | struct hci_conn *hcon; | ||
| 46 | |||
| 47 | spinlock_t lock; | ||
| 48 | struct sock *sk; | ||
| 49 | |||
| 50 | unsigned int mtu; | ||
| 51 | }; | ||
| 52 | |||
| 53 | #define sco_conn_lock(c) spin_lock(&c->lock); | ||
| 54 | #define sco_conn_unlock(c) spin_unlock(&c->lock); | ||
| 45 | 55 | ||
| 46 | static void sco_sock_close(struct sock *sk); | 56 | static void sco_sock_close(struct sock *sk); |
| 47 | static void sco_sock_kill(struct sock *sk); | 57 | static void sco_sock_kill(struct sock *sk); |
| 48 | 58 | ||
| 59 | /* ----- SCO socket info ----- */ | ||
| 60 | #define sco_pi(sk) ((struct sco_pinfo *) sk) | ||
| 61 | |||
| 62 | struct sco_pinfo { | ||
| 63 | struct bt_sock bt; | ||
| 64 | bdaddr_t src; | ||
| 65 | bdaddr_t dst; | ||
| 66 | __u32 flags; | ||
| 67 | __u16 setting; | ||
| 68 | struct sco_conn *conn; | ||
| 69 | }; | ||
| 70 | |||
| 49 | /* ---- SCO timers ---- */ | 71 | /* ---- SCO timers ---- */ |
| 72 | #define SCO_CONN_TIMEOUT (HZ * 40) | ||
| 73 | #define SCO_DISCONN_TIMEOUT (HZ * 2) | ||
| 74 | |||
| 50 | static void sco_sock_timeout(unsigned long arg) | 75 | static void sco_sock_timeout(unsigned long arg) |
| 51 | { | 76 | { |
| 52 | struct sock *sk = (struct sock *) arg; | 77 | struct sock *sk = (struct sock *) arg; |
| @@ -102,13 +127,31 @@ static struct sco_conn *sco_conn_add(struct hci_conn *hcon) | |||
| 102 | return conn; | 127 | return conn; |
| 103 | } | 128 | } |
| 104 | 129 | ||
| 105 | static struct sock *sco_chan_get(struct sco_conn *conn) | 130 | /* Delete channel. |
| 131 | * Must be called on the locked socket. */ | ||
| 132 | static void sco_chan_del(struct sock *sk, int err) | ||
| 106 | { | 133 | { |
| 107 | struct sock *sk = NULL; | 134 | struct sco_conn *conn; |
| 108 | sco_conn_lock(conn); | 135 | |
| 109 | sk = conn->sk; | 136 | conn = sco_pi(sk)->conn; |
| 110 | sco_conn_unlock(conn); | 137 | |
| 111 | return sk; | 138 | BT_DBG("sk %p, conn %p, err %d", sk, conn, err); |
| 139 | |||
| 140 | if (conn) { | ||
| 141 | sco_conn_lock(conn); | ||
| 142 | conn->sk = NULL; | ||
| 143 | sco_pi(sk)->conn = NULL; | ||
| 144 | sco_conn_unlock(conn); | ||
| 145 | |||
| 146 | if (conn->hcon) | ||
| 147 | hci_conn_drop(conn->hcon); | ||
| 148 | } | ||
| 149 | |||
| 150 | sk->sk_state = BT_CLOSED; | ||
| 151 | sk->sk_err = err; | ||
| 152 | sk->sk_state_change(sk); | ||
| 153 | |||
| 154 | sock_set_flag(sk, SOCK_ZAPPED); | ||
| 112 | } | 155 | } |
| 113 | 156 | ||
| 114 | static int sco_conn_del(struct hci_conn *hcon, int err) | 157 | static int sco_conn_del(struct hci_conn *hcon, int err) |
| @@ -122,7 +165,10 @@ static int sco_conn_del(struct hci_conn *hcon, int err) | |||
| 122 | BT_DBG("hcon %p conn %p, err %d", hcon, conn, err); | 165 | BT_DBG("hcon %p conn %p, err %d", hcon, conn, err); |
| 123 | 166 | ||
| 124 | /* Kill socket */ | 167 | /* Kill socket */ |
| 125 | sk = sco_chan_get(conn); | 168 | sco_conn_lock(conn); |
| 169 | sk = conn->sk; | ||
| 170 | sco_conn_unlock(conn); | ||
| 171 | |||
| 126 | if (sk) { | 172 | if (sk) { |
| 127 | bh_lock_sock(sk); | 173 | bh_lock_sock(sk); |
| 128 | sco_sock_clear_timer(sk); | 174 | sco_sock_clear_timer(sk); |
| @@ -136,6 +182,17 @@ static int sco_conn_del(struct hci_conn *hcon, int err) | |||
| 136 | return 0; | 182 | return 0; |
| 137 | } | 183 | } |
| 138 | 184 | ||
| 185 | static void __sco_chan_add(struct sco_conn *conn, struct sock *sk, struct sock *parent) | ||
| 186 | { | ||
| 187 | BT_DBG("conn %p", conn); | ||
| 188 | |||
| 189 | sco_pi(sk)->conn = conn; | ||
| 190 | conn->sk = sk; | ||
| 191 | |||
| 192 | if (parent) | ||
| 193 | bt_accept_enqueue(parent, sk); | ||
| 194 | } | ||
| 195 | |||
| 139 | static int sco_chan_add(struct sco_conn *conn, struct sock *sk, | 196 | static int sco_chan_add(struct sco_conn *conn, struct sock *sk, |
| 140 | struct sock *parent) | 197 | struct sock *parent) |
| 141 | { | 198 | { |
| @@ -240,7 +297,11 @@ static int sco_send_frame(struct sock *sk, struct msghdr *msg, int len) | |||
| 240 | 297 | ||
| 241 | static void sco_recv_frame(struct sco_conn *conn, struct sk_buff *skb) | 298 | static void sco_recv_frame(struct sco_conn *conn, struct sk_buff *skb) |
| 242 | { | 299 | { |
| 243 | struct sock *sk = sco_chan_get(conn); | 300 | struct sock *sk; |
| 301 | |||
| 302 | sco_conn_lock(conn); | ||
| 303 | sk = conn->sk; | ||
| 304 | sco_conn_unlock(conn); | ||
| 244 | 305 | ||
| 245 | if (!sk) | 306 | if (!sk) |
| 246 | goto drop; | 307 | goto drop; |
| @@ -909,7 +970,8 @@ static int sco_sock_shutdown(struct socket *sock, int how) | |||
| 909 | sco_sock_clear_timer(sk); | 970 | sco_sock_clear_timer(sk); |
| 910 | __sco_sock_close(sk); | 971 | __sco_sock_close(sk); |
| 911 | 972 | ||
| 912 | if (sock_flag(sk, SOCK_LINGER) && sk->sk_lingertime) | 973 | if (sock_flag(sk, SOCK_LINGER) && sk->sk_lingertime && |
| 974 | !(current->flags & PF_EXITING)) | ||
| 913 | err = bt_sock_wait_state(sk, BT_CLOSED, | 975 | err = bt_sock_wait_state(sk, BT_CLOSED, |
| 914 | sk->sk_lingertime); | 976 | sk->sk_lingertime); |
| 915 | } | 977 | } |
| @@ -929,7 +991,8 @@ static int sco_sock_release(struct socket *sock) | |||
| 929 | 991 | ||
| 930 | sco_sock_close(sk); | 992 | sco_sock_close(sk); |
| 931 | 993 | ||
| 932 | if (sock_flag(sk, SOCK_LINGER) && sk->sk_lingertime) { | 994 | if (sock_flag(sk, SOCK_LINGER) && sk->sk_lingertime && |
| 995 | !(current->flags & PF_EXITING)) { | ||
| 933 | lock_sock(sk); | 996 | lock_sock(sk); |
| 934 | err = bt_sock_wait_state(sk, BT_CLOSED, sk->sk_lingertime); | 997 | err = bt_sock_wait_state(sk, BT_CLOSED, sk->sk_lingertime); |
| 935 | release_sock(sk); | 998 | release_sock(sk); |
| @@ -940,44 +1003,6 @@ static int sco_sock_release(struct socket *sock) | |||
| 940 | return err; | 1003 | return err; |
| 941 | } | 1004 | } |
| 942 | 1005 | ||
| 943 | static void __sco_chan_add(struct sco_conn *conn, struct sock *sk, struct sock *parent) | ||
| 944 | { | ||
| 945 | BT_DBG("conn %p", conn); | ||
| 946 | |||
| 947 | sco_pi(sk)->conn = conn; | ||
| 948 | conn->sk = sk; | ||
| 949 | |||
| 950 | if (parent) | ||
| 951 | bt_accept_enqueue(parent, sk); | ||
| 952 | } | ||
| 953 | |||
| 954 | /* Delete channel. | ||
| 955 | * Must be called on the locked socket. */ | ||
| 956 | static void sco_chan_del(struct sock *sk, int err) | ||
| 957 | { | ||
| 958 | struct sco_conn *conn; | ||
| 959 | |||
| 960 | conn = sco_pi(sk)->conn; | ||
| 961 | |||
| 962 | BT_DBG("sk %p, conn %p, err %d", sk, conn, err); | ||
| 963 | |||
| 964 | if (conn) { | ||
| 965 | sco_conn_lock(conn); | ||
| 966 | conn->sk = NULL; | ||
| 967 | sco_pi(sk)->conn = NULL; | ||
| 968 | sco_conn_unlock(conn); | ||
| 969 | |||
| 970 | if (conn->hcon) | ||
| 971 | hci_conn_drop(conn->hcon); | ||
| 972 | } | ||
| 973 | |||
| 974 | sk->sk_state = BT_CLOSED; | ||
| 975 | sk->sk_err = err; | ||
| 976 | sk->sk_state_change(sk); | ||
| 977 | |||
| 978 | sock_set_flag(sk, SOCK_ZAPPED); | ||
| 979 | } | ||
| 980 | |||
| 981 | static void sco_conn_ready(struct sco_conn *conn) | 1006 | static void sco_conn_ready(struct sco_conn *conn) |
| 982 | { | 1007 | { |
| 983 | struct sock *parent; | 1008 | struct sock *parent; |
diff --git a/net/bluetooth/smp.c b/net/bluetooth/smp.c index e33a982161c1..fd3294300803 100644 --- a/net/bluetooth/smp.c +++ b/net/bluetooth/smp.c | |||
| @@ -35,11 +35,13 @@ | |||
| 35 | 35 | ||
| 36 | #define AUTH_REQ_MASK 0x07 | 36 | #define AUTH_REQ_MASK 0x07 |
| 37 | 37 | ||
| 38 | #define SMP_FLAG_TK_VALID 1 | 38 | enum { |
| 39 | #define SMP_FLAG_CFM_PENDING 2 | 39 | SMP_FLAG_TK_VALID, |
| 40 | #define SMP_FLAG_MITM_AUTH 3 | 40 | SMP_FLAG_CFM_PENDING, |
| 41 | #define SMP_FLAG_COMPLETE 4 | 41 | SMP_FLAG_MITM_AUTH, |
| 42 | #define SMP_FLAG_INITIATOR 5 | 42 | SMP_FLAG_COMPLETE, |
| 43 | SMP_FLAG_INITIATOR, | ||
| 44 | }; | ||
| 43 | 45 | ||
| 44 | struct smp_chan { | 46 | struct smp_chan { |
| 45 | struct l2cap_conn *conn; | 47 | struct l2cap_conn *conn; |
| @@ -60,20 +62,16 @@ struct smp_chan { | |||
| 60 | struct smp_ltk *slave_ltk; | 62 | struct smp_ltk *slave_ltk; |
| 61 | struct smp_irk *remote_irk; | 63 | struct smp_irk *remote_irk; |
| 62 | unsigned long flags; | 64 | unsigned long flags; |
| 65 | |||
| 66 | struct crypto_blkcipher *tfm_aes; | ||
| 63 | }; | 67 | }; |
| 64 | 68 | ||
| 65 | static inline void swap128(const u8 src[16], u8 dst[16]) | 69 | static inline void swap_buf(const u8 *src, u8 *dst, size_t len) |
| 66 | { | 70 | { |
| 67 | int i; | 71 | size_t i; |
| 68 | for (i = 0; i < 16; i++) | ||
| 69 | dst[15 - i] = src[i]; | ||
| 70 | } | ||
| 71 | 72 | ||
| 72 | static inline void swap56(const u8 src[7], u8 dst[7]) | 73 | for (i = 0; i < len; i++) |
| 73 | { | 74 | dst[len - 1 - i] = src[i]; |
| 74 | int i; | ||
| 75 | for (i = 0; i < 7; i++) | ||
| 76 | dst[6 - i] = src[i]; | ||
| 77 | } | 75 | } |
| 78 | 76 | ||
| 79 | static int smp_e(struct crypto_blkcipher *tfm, const u8 *k, u8 *r) | 77 | static int smp_e(struct crypto_blkcipher *tfm, const u8 *k, u8 *r) |
| @@ -92,7 +90,7 @@ static int smp_e(struct crypto_blkcipher *tfm, const u8 *k, u8 *r) | |||
| 92 | desc.flags = 0; | 90 | desc.flags = 0; |
| 93 | 91 | ||
| 94 | /* The most significant octet of key corresponds to k[0] */ | 92 | /* The most significant octet of key corresponds to k[0] */ |
| 95 | swap128(k, tmp); | 93 | swap_buf(k, tmp, 16); |
| 96 | 94 | ||
| 97 | err = crypto_blkcipher_setkey(tfm, tmp, 16); | 95 | err = crypto_blkcipher_setkey(tfm, tmp, 16); |
| 98 | if (err) { | 96 | if (err) { |
| @@ -101,7 +99,7 @@ static int smp_e(struct crypto_blkcipher *tfm, const u8 *k, u8 *r) | |||
| 101 | } | 99 | } |
| 102 | 100 | ||
| 103 | /* Most significant octet of plaintextData corresponds to data[0] */ | 101 | /* Most significant octet of plaintextData corresponds to data[0] */ |
| 104 | swap128(r, data); | 102 | swap_buf(r, data, 16); |
| 105 | 103 | ||
| 106 | sg_init_one(&sg, data, 16); | 104 | sg_init_one(&sg, data, 16); |
| 107 | 105 | ||
| @@ -110,7 +108,7 @@ static int smp_e(struct crypto_blkcipher *tfm, const u8 *k, u8 *r) | |||
| 110 | BT_ERR("Encrypt data error %d", err); | 108 | BT_ERR("Encrypt data error %d", err); |
| 111 | 109 | ||
| 112 | /* Most significant octet of encryptedData corresponds to data[0] */ | 110 | /* Most significant octet of encryptedData corresponds to data[0] */ |
| 113 | swap128(data, r); | 111 | swap_buf(data, r, 16); |
| 114 | 112 | ||
| 115 | return err; | 113 | return err; |
| 116 | } | 114 | } |
| @@ -174,13 +172,16 @@ int smp_generate_rpa(struct crypto_blkcipher *tfm, u8 irk[16], bdaddr_t *rpa) | |||
| 174 | return 0; | 172 | return 0; |
| 175 | } | 173 | } |
| 176 | 174 | ||
| 177 | static int smp_c1(struct crypto_blkcipher *tfm, u8 k[16], u8 r[16], | 175 | static int smp_c1(struct smp_chan *smp, u8 k[16], u8 r[16], u8 preq[7], |
| 178 | u8 preq[7], u8 pres[7], u8 _iat, bdaddr_t *ia, | 176 | u8 pres[7], u8 _iat, bdaddr_t *ia, u8 _rat, bdaddr_t *ra, |
| 179 | u8 _rat, bdaddr_t *ra, u8 res[16]) | 177 | u8 res[16]) |
| 180 | { | 178 | { |
| 179 | struct hci_dev *hdev = smp->conn->hcon->hdev; | ||
| 181 | u8 p1[16], p2[16]; | 180 | u8 p1[16], p2[16]; |
| 182 | int err; | 181 | int err; |
| 183 | 182 | ||
| 183 | BT_DBG("%s", hdev->name); | ||
| 184 | |||
| 184 | memset(p1, 0, 16); | 185 | memset(p1, 0, 16); |
| 185 | 186 | ||
| 186 | /* p1 = pres || preq || _rat || _iat */ | 187 | /* p1 = pres || preq || _rat || _iat */ |
| @@ -198,7 +199,7 @@ static int smp_c1(struct crypto_blkcipher *tfm, u8 k[16], u8 r[16], | |||
| 198 | u128_xor((u128 *) res, (u128 *) r, (u128 *) p1); | 199 | u128_xor((u128 *) res, (u128 *) r, (u128 *) p1); |
| 199 | 200 | ||
| 200 | /* res = e(k, res) */ | 201 | /* res = e(k, res) */ |
| 201 | err = smp_e(tfm, k, res); | 202 | err = smp_e(smp->tfm_aes, k, res); |
| 202 | if (err) { | 203 | if (err) { |
| 203 | BT_ERR("Encrypt data error"); | 204 | BT_ERR("Encrypt data error"); |
| 204 | return err; | 205 | return err; |
| @@ -208,23 +209,26 @@ static int smp_c1(struct crypto_blkcipher *tfm, u8 k[16], u8 r[16], | |||
| 208 | u128_xor((u128 *) res, (u128 *) res, (u128 *) p2); | 209 | u128_xor((u128 *) res, (u128 *) res, (u128 *) p2); |
| 209 | 210 | ||
| 210 | /* res = e(k, res) */ | 211 | /* res = e(k, res) */ |
| 211 | err = smp_e(tfm, k, res); | 212 | err = smp_e(smp->tfm_aes, k, res); |
| 212 | if (err) | 213 | if (err) |
| 213 | BT_ERR("Encrypt data error"); | 214 | BT_ERR("Encrypt data error"); |
| 214 | 215 | ||
| 215 | return err; | 216 | return err; |
| 216 | } | 217 | } |
| 217 | 218 | ||
| 218 | static int smp_s1(struct crypto_blkcipher *tfm, u8 k[16], u8 r1[16], | 219 | static int smp_s1(struct smp_chan *smp, u8 k[16], u8 r1[16], u8 r2[16], |
| 219 | u8 r2[16], u8 _r[16]) | 220 | u8 _r[16]) |
| 220 | { | 221 | { |
| 222 | struct hci_dev *hdev = smp->conn->hcon->hdev; | ||
| 221 | int err; | 223 | int err; |
| 222 | 224 | ||
| 225 | BT_DBG("%s", hdev->name); | ||
| 226 | |||
| 223 | /* Just least significant octets from r1 and r2 are considered */ | 227 | /* Just least significant octets from r1 and r2 are considered */ |
| 224 | memcpy(_r, r2, 8); | 228 | memcpy(_r, r2, 8); |
| 225 | memcpy(_r + 8, r1, 8); | 229 | memcpy(_r + 8, r1, 8); |
| 226 | 230 | ||
| 227 | err = smp_e(tfm, k, _r); | 231 | err = smp_e(smp->tfm_aes, k, _r); |
| 228 | if (err) | 232 | if (err) |
| 229 | BT_ERR("Encrypt data error"); | 233 | BT_ERR("Encrypt data error"); |
| 230 | 234 | ||
| @@ -303,7 +307,7 @@ static void build_pairing_cmd(struct l2cap_conn *conn, | |||
| 303 | struct hci_dev *hdev = hcon->hdev; | 307 | struct hci_dev *hdev = hcon->hdev; |
| 304 | u8 local_dist = 0, remote_dist = 0; | 308 | u8 local_dist = 0, remote_dist = 0; |
| 305 | 309 | ||
| 306 | if (test_bit(HCI_PAIRABLE, &conn->hcon->hdev->dev_flags)) { | 310 | if (test_bit(HCI_BONDABLE, &conn->hcon->hdev->dev_flags)) { |
| 307 | local_dist = SMP_DIST_ENC_KEY | SMP_DIST_SIGN; | 311 | local_dist = SMP_DIST_ENC_KEY | SMP_DIST_SIGN; |
| 308 | remote_dist = SMP_DIST_ENC_KEY | SMP_DIST_SIGN; | 312 | remote_dist = SMP_DIST_ENC_KEY | SMP_DIST_SIGN; |
| 309 | authreq |= SMP_AUTH_BONDING; | 313 | authreq |= SMP_AUTH_BONDING; |
| @@ -387,10 +391,12 @@ static const u8 gen_method[5][5] = { | |||
| 387 | 391 | ||
| 388 | static u8 get_auth_method(struct smp_chan *smp, u8 local_io, u8 remote_io) | 392 | static u8 get_auth_method(struct smp_chan *smp, u8 local_io, u8 remote_io) |
| 389 | { | 393 | { |
| 390 | /* If either side has unknown io_caps, use JUST WORKS */ | 394 | /* If either side has unknown io_caps, use JUST_CFM (which gets |
| 395 | * converted later to JUST_WORKS if we're initiators. | ||
| 396 | */ | ||
| 391 | if (local_io > SMP_IO_KEYBOARD_DISPLAY || | 397 | if (local_io > SMP_IO_KEYBOARD_DISPLAY || |
| 392 | remote_io > SMP_IO_KEYBOARD_DISPLAY) | 398 | remote_io > SMP_IO_KEYBOARD_DISPLAY) |
| 393 | return JUST_WORKS; | 399 | return JUST_CFM; |
| 394 | 400 | ||
| 395 | return gen_method[remote_io][local_io]; | 401 | return gen_method[remote_io][local_io]; |
| 396 | } | 402 | } |
| @@ -410,21 +416,25 @@ static int tk_request(struct l2cap_conn *conn, u8 remote_oob, u8 auth, | |||
| 410 | 416 | ||
| 411 | BT_DBG("tk_request: auth:%d lcl:%d rem:%d", auth, local_io, remote_io); | 417 | BT_DBG("tk_request: auth:%d lcl:%d rem:%d", auth, local_io, remote_io); |
| 412 | 418 | ||
| 413 | /* If neither side wants MITM, use JUST WORKS */ | 419 | /* If neither side wants MITM, either "just" confirm an incoming |
| 414 | /* Otherwise, look up method from the table */ | 420 | * request or use just-works for outgoing ones. The JUST_CFM |
| 421 | * will be converted to JUST_WORKS if necessary later in this | ||
| 422 | * function. If either side has MITM look up the method from the | ||
| 423 | * table. | ||
| 424 | */ | ||
| 415 | if (!(auth & SMP_AUTH_MITM)) | 425 | if (!(auth & SMP_AUTH_MITM)) |
| 416 | method = JUST_WORKS; | 426 | method = JUST_CFM; |
| 417 | else | 427 | else |
| 418 | method = get_auth_method(smp, local_io, remote_io); | 428 | method = get_auth_method(smp, local_io, remote_io); |
| 419 | 429 | ||
| 420 | /* If not bonding, don't ask user to confirm a Zero TK */ | ||
| 421 | if (!(auth & SMP_AUTH_BONDING) && method == JUST_CFM) | ||
| 422 | method = JUST_WORKS; | ||
| 423 | |||
| 424 | /* Don't confirm locally initiated pairing attempts */ | 430 | /* Don't confirm locally initiated pairing attempts */ |
| 425 | if (method == JUST_CFM && test_bit(SMP_FLAG_INITIATOR, &smp->flags)) | 431 | if (method == JUST_CFM && test_bit(SMP_FLAG_INITIATOR, &smp->flags)) |
| 426 | method = JUST_WORKS; | 432 | method = JUST_WORKS; |
| 427 | 433 | ||
| 434 | /* Don't bother user space with no IO capabilities */ | ||
| 435 | if (method == JUST_CFM && hcon->io_capability == HCI_IO_NO_INPUT_OUTPUT) | ||
| 436 | method = JUST_WORKS; | ||
| 437 | |||
| 428 | /* If Just Works, Continue with Zero TK */ | 438 | /* If Just Works, Continue with Zero TK */ |
| 429 | if (method == JUST_WORKS) { | 439 | if (method == JUST_WORKS) { |
| 430 | set_bit(SMP_FLAG_TK_VALID, &smp->flags); | 440 | set_bit(SMP_FLAG_TK_VALID, &smp->flags); |
| @@ -439,7 +449,7 @@ static int tk_request(struct l2cap_conn *conn, u8 remote_oob, u8 auth, | |||
| 439 | * Confirms and the slave Enters the passkey. | 449 | * Confirms and the slave Enters the passkey. |
| 440 | */ | 450 | */ |
| 441 | if (method == OVERLAP) { | 451 | if (method == OVERLAP) { |
| 442 | if (hcon->link_mode & HCI_LM_MASTER) | 452 | if (hcon->role == HCI_ROLE_MASTER) |
| 443 | method = CFM_PASSKEY; | 453 | method = CFM_PASSKEY; |
| 444 | else | 454 | else |
| 445 | method = REQ_PASSKEY; | 455 | method = REQ_PASSKEY; |
| @@ -477,23 +487,15 @@ static int tk_request(struct l2cap_conn *conn, u8 remote_oob, u8 auth, | |||
| 477 | static u8 smp_confirm(struct smp_chan *smp) | 487 | static u8 smp_confirm(struct smp_chan *smp) |
| 478 | { | 488 | { |
| 479 | struct l2cap_conn *conn = smp->conn; | 489 | struct l2cap_conn *conn = smp->conn; |
| 480 | struct hci_dev *hdev = conn->hcon->hdev; | ||
| 481 | struct crypto_blkcipher *tfm = hdev->tfm_aes; | ||
| 482 | struct smp_cmd_pairing_confirm cp; | 490 | struct smp_cmd_pairing_confirm cp; |
| 483 | int ret; | 491 | int ret; |
| 484 | 492 | ||
| 485 | BT_DBG("conn %p", conn); | 493 | BT_DBG("conn %p", conn); |
| 486 | 494 | ||
| 487 | /* Prevent mutual access to hdev->tfm_aes */ | 495 | ret = smp_c1(smp, smp->tk, smp->prnd, smp->preq, smp->prsp, |
| 488 | hci_dev_lock(hdev); | ||
| 489 | |||
| 490 | ret = smp_c1(tfm, smp->tk, smp->prnd, smp->preq, smp->prsp, | ||
| 491 | conn->hcon->init_addr_type, &conn->hcon->init_addr, | 496 | conn->hcon->init_addr_type, &conn->hcon->init_addr, |
| 492 | conn->hcon->resp_addr_type, &conn->hcon->resp_addr, | 497 | conn->hcon->resp_addr_type, &conn->hcon->resp_addr, |
| 493 | cp.confirm_val); | 498 | cp.confirm_val); |
| 494 | |||
| 495 | hci_dev_unlock(hdev); | ||
| 496 | |||
| 497 | if (ret) | 499 | if (ret) |
| 498 | return SMP_UNSPECIFIED; | 500 | return SMP_UNSPECIFIED; |
| 499 | 501 | ||
| @@ -508,25 +510,17 @@ static u8 smp_random(struct smp_chan *smp) | |||
| 508 | { | 510 | { |
| 509 | struct l2cap_conn *conn = smp->conn; | 511 | struct l2cap_conn *conn = smp->conn; |
| 510 | struct hci_conn *hcon = conn->hcon; | 512 | struct hci_conn *hcon = conn->hcon; |
| 511 | struct hci_dev *hdev = hcon->hdev; | ||
| 512 | struct crypto_blkcipher *tfm = hdev->tfm_aes; | ||
| 513 | u8 confirm[16]; | 513 | u8 confirm[16]; |
| 514 | int ret; | 514 | int ret; |
| 515 | 515 | ||
| 516 | if (IS_ERR_OR_NULL(tfm)) | 516 | if (IS_ERR_OR_NULL(smp->tfm_aes)) |
| 517 | return SMP_UNSPECIFIED; | 517 | return SMP_UNSPECIFIED; |
| 518 | 518 | ||
| 519 | BT_DBG("conn %p %s", conn, conn->hcon->out ? "master" : "slave"); | 519 | BT_DBG("conn %p %s", conn, conn->hcon->out ? "master" : "slave"); |
| 520 | 520 | ||
| 521 | /* Prevent mutual access to hdev->tfm_aes */ | 521 | ret = smp_c1(smp, smp->tk, smp->rrnd, smp->preq, smp->prsp, |
| 522 | hci_dev_lock(hdev); | ||
| 523 | |||
| 524 | ret = smp_c1(tfm, smp->tk, smp->rrnd, smp->preq, smp->prsp, | ||
| 525 | hcon->init_addr_type, &hcon->init_addr, | 522 | hcon->init_addr_type, &hcon->init_addr, |
| 526 | hcon->resp_addr_type, &hcon->resp_addr, confirm); | 523 | hcon->resp_addr_type, &hcon->resp_addr, confirm); |
| 527 | |||
| 528 | hci_dev_unlock(hdev); | ||
| 529 | |||
| 530 | if (ret) | 524 | if (ret) |
| 531 | return SMP_UNSPECIFIED; | 525 | return SMP_UNSPECIFIED; |
| 532 | 526 | ||
| @@ -540,7 +534,7 @@ static u8 smp_random(struct smp_chan *smp) | |||
| 540 | __le64 rand = 0; | 534 | __le64 rand = 0; |
| 541 | __le16 ediv = 0; | 535 | __le16 ediv = 0; |
| 542 | 536 | ||
| 543 | smp_s1(tfm, smp->tk, smp->rrnd, smp->prnd, stk); | 537 | smp_s1(smp, smp->tk, smp->rrnd, smp->prnd, stk); |
| 544 | 538 | ||
| 545 | memset(stk + smp->enc_key_size, 0, | 539 | memset(stk + smp->enc_key_size, 0, |
| 546 | SMP_MAX_ENC_KEY_SIZE - smp->enc_key_size); | 540 | SMP_MAX_ENC_KEY_SIZE - smp->enc_key_size); |
| @@ -550,6 +544,7 @@ static u8 smp_random(struct smp_chan *smp) | |||
| 550 | 544 | ||
| 551 | hci_le_start_enc(hcon, ediv, rand, stk); | 545 | hci_le_start_enc(hcon, ediv, rand, stk); |
| 552 | hcon->enc_key_size = smp->enc_key_size; | 546 | hcon->enc_key_size = smp->enc_key_size; |
| 547 | set_bit(HCI_CONN_STK_ENCRYPT, &hcon->flags); | ||
| 553 | } else { | 548 | } else { |
| 554 | u8 stk[16], auth; | 549 | u8 stk[16], auth; |
| 555 | __le64 rand = 0; | 550 | __le64 rand = 0; |
| @@ -558,7 +553,7 @@ static u8 smp_random(struct smp_chan *smp) | |||
| 558 | smp_send_cmd(conn, SMP_CMD_PAIRING_RANDOM, sizeof(smp->prnd), | 553 | smp_send_cmd(conn, SMP_CMD_PAIRING_RANDOM, sizeof(smp->prnd), |
| 559 | smp->prnd); | 554 | smp->prnd); |
| 560 | 555 | ||
| 561 | smp_s1(tfm, smp->tk, smp->prnd, smp->rrnd, stk); | 556 | smp_s1(smp, smp->tk, smp->prnd, smp->rrnd, stk); |
| 562 | 557 | ||
| 563 | memset(stk + smp->enc_key_size, 0, | 558 | memset(stk + smp->enc_key_size, 0, |
| 564 | SMP_MAX_ENC_KEY_SIZE - smp->enc_key_size); | 559 | SMP_MAX_ENC_KEY_SIZE - smp->enc_key_size); |
| @@ -568,9 +563,12 @@ static u8 smp_random(struct smp_chan *smp) | |||
| 568 | else | 563 | else |
| 569 | auth = 0; | 564 | auth = 0; |
| 570 | 565 | ||
| 566 | /* Even though there's no _SLAVE suffix this is the | ||
| 567 | * slave STK we're adding for later lookup (the master | ||
| 568 | * STK never needs to be stored). | ||
| 569 | */ | ||
| 571 | hci_add_ltk(hcon->hdev, &hcon->dst, hcon->dst_type, | 570 | hci_add_ltk(hcon->hdev, &hcon->dst, hcon->dst_type, |
| 572 | HCI_SMP_STK_SLAVE, auth, stk, smp->enc_key_size, | 571 | SMP_STK, auth, stk, smp->enc_key_size, ediv, rand); |
| 573 | ediv, rand); | ||
| 574 | } | 572 | } |
| 575 | 573 | ||
| 576 | return 0; | 574 | return 0; |
| @@ -581,12 +579,21 @@ static struct smp_chan *smp_chan_create(struct l2cap_conn *conn) | |||
| 581 | struct smp_chan *smp; | 579 | struct smp_chan *smp; |
| 582 | 580 | ||
| 583 | smp = kzalloc(sizeof(*smp), GFP_ATOMIC); | 581 | smp = kzalloc(sizeof(*smp), GFP_ATOMIC); |
| 584 | if (!smp) | 582 | if (!smp) { |
| 583 | clear_bit(HCI_CONN_LE_SMP_PEND, &conn->hcon->flags); | ||
| 585 | return NULL; | 584 | return NULL; |
| 585 | } | ||
| 586 | |||
| 587 | smp->tfm_aes = crypto_alloc_blkcipher("ecb(aes)", 0, CRYPTO_ALG_ASYNC); | ||
| 588 | if (IS_ERR(smp->tfm_aes)) { | ||
| 589 | BT_ERR("Unable to create ECB crypto context"); | ||
| 590 | kfree(smp); | ||
| 591 | clear_bit(HCI_CONN_LE_SMP_PEND, &conn->hcon->flags); | ||
| 592 | return NULL; | ||
| 593 | } | ||
| 586 | 594 | ||
| 587 | smp->conn = conn; | 595 | smp->conn = conn; |
| 588 | conn->smp_chan = smp; | 596 | conn->smp_chan = smp; |
| 589 | conn->hcon->smp_conn = conn; | ||
| 590 | 597 | ||
| 591 | hci_conn_hold(conn->hcon); | 598 | hci_conn_hold(conn->hcon); |
| 592 | 599 | ||
| @@ -606,6 +613,8 @@ void smp_chan_destroy(struct l2cap_conn *conn) | |||
| 606 | kfree(smp->csrk); | 613 | kfree(smp->csrk); |
| 607 | kfree(smp->slave_csrk); | 614 | kfree(smp->slave_csrk); |
| 608 | 615 | ||
| 616 | crypto_free_blkcipher(smp->tfm_aes); | ||
| 617 | |||
| 609 | /* If pairing failed clean up any keys we might have */ | 618 | /* If pairing failed clean up any keys we might have */ |
| 610 | if (!complete) { | 619 | if (!complete) { |
| 611 | if (smp->ltk) { | 620 | if (smp->ltk) { |
| @@ -626,19 +635,18 @@ void smp_chan_destroy(struct l2cap_conn *conn) | |||
| 626 | 635 | ||
| 627 | kfree(smp); | 636 | kfree(smp); |
| 628 | conn->smp_chan = NULL; | 637 | conn->smp_chan = NULL; |
| 629 | conn->hcon->smp_conn = NULL; | ||
| 630 | hci_conn_drop(conn->hcon); | 638 | hci_conn_drop(conn->hcon); |
| 631 | } | 639 | } |
| 632 | 640 | ||
| 633 | int smp_user_confirm_reply(struct hci_conn *hcon, u16 mgmt_op, __le32 passkey) | 641 | int smp_user_confirm_reply(struct hci_conn *hcon, u16 mgmt_op, __le32 passkey) |
| 634 | { | 642 | { |
| 635 | struct l2cap_conn *conn = hcon->smp_conn; | 643 | struct l2cap_conn *conn = hcon->l2cap_data; |
| 636 | struct smp_chan *smp; | 644 | struct smp_chan *smp; |
| 637 | u32 value; | 645 | u32 value; |
| 638 | 646 | ||
| 639 | BT_DBG(""); | 647 | BT_DBG(""); |
| 640 | 648 | ||
| 641 | if (!conn) | 649 | if (!conn || !test_bit(HCI_CONN_LE_SMP_PEND, &hcon->flags)) |
| 642 | return -ENOTCONN; | 650 | return -ENOTCONN; |
| 643 | 651 | ||
| 644 | smp = conn->smp_chan; | 652 | smp = conn->smp_chan; |
| @@ -675,6 +683,7 @@ int smp_user_confirm_reply(struct hci_conn *hcon, u16 mgmt_op, __le32 passkey) | |||
| 675 | static u8 smp_cmd_pairing_req(struct l2cap_conn *conn, struct sk_buff *skb) | 683 | static u8 smp_cmd_pairing_req(struct l2cap_conn *conn, struct sk_buff *skb) |
| 676 | { | 684 | { |
| 677 | struct smp_cmd_pairing rsp, *req = (void *) skb->data; | 685 | struct smp_cmd_pairing rsp, *req = (void *) skb->data; |
| 686 | struct hci_dev *hdev = conn->hcon->hdev; | ||
| 678 | struct smp_chan *smp; | 687 | struct smp_chan *smp; |
| 679 | u8 key_size, auth, sec_level; | 688 | u8 key_size, auth, sec_level; |
| 680 | int ret; | 689 | int ret; |
| @@ -684,7 +693,7 @@ static u8 smp_cmd_pairing_req(struct l2cap_conn *conn, struct sk_buff *skb) | |||
| 684 | if (skb->len < sizeof(*req)) | 693 | if (skb->len < sizeof(*req)) |
| 685 | return SMP_INVALID_PARAMS; | 694 | return SMP_INVALID_PARAMS; |
| 686 | 695 | ||
| 687 | if (conn->hcon->link_mode & HCI_LM_MASTER) | 696 | if (conn->hcon->role != HCI_ROLE_SLAVE) |
| 688 | return SMP_CMD_NOTSUPP; | 697 | return SMP_CMD_NOTSUPP; |
| 689 | 698 | ||
| 690 | if (!test_and_set_bit(HCI_CONN_LE_SMP_PEND, &conn->hcon->flags)) | 699 | if (!test_and_set_bit(HCI_CONN_LE_SMP_PEND, &conn->hcon->flags)) |
| @@ -695,6 +704,10 @@ static u8 smp_cmd_pairing_req(struct l2cap_conn *conn, struct sk_buff *skb) | |||
| 695 | if (!smp) | 704 | if (!smp) |
| 696 | return SMP_UNSPECIFIED; | 705 | return SMP_UNSPECIFIED; |
| 697 | 706 | ||
| 707 | if (!test_bit(HCI_BONDABLE, &hdev->dev_flags) && | ||
| 708 | (req->auth_req & SMP_AUTH_BONDING)) | ||
| 709 | return SMP_PAIRING_NOTSUPP; | ||
| 710 | |||
| 698 | smp->preq[0] = SMP_CMD_PAIRING_REQ; | 711 | smp->preq[0] = SMP_CMD_PAIRING_REQ; |
| 699 | memcpy(&smp->preq[1], req, sizeof(*req)); | 712 | memcpy(&smp->preq[1], req, sizeof(*req)); |
| 700 | skb_pull(skb, sizeof(*req)); | 713 | skb_pull(skb, sizeof(*req)); |
| @@ -734,8 +747,6 @@ static u8 smp_cmd_pairing_req(struct l2cap_conn *conn, struct sk_buff *skb) | |||
| 734 | if (ret) | 747 | if (ret) |
| 735 | return SMP_UNSPECIFIED; | 748 | return SMP_UNSPECIFIED; |
| 736 | 749 | ||
| 737 | clear_bit(SMP_FLAG_INITIATOR, &smp->flags); | ||
| 738 | |||
| 739 | return 0; | 750 | return 0; |
| 740 | } | 751 | } |
| 741 | 752 | ||
| @@ -751,7 +762,7 @@ static u8 smp_cmd_pairing_rsp(struct l2cap_conn *conn, struct sk_buff *skb) | |||
| 751 | if (skb->len < sizeof(*rsp)) | 762 | if (skb->len < sizeof(*rsp)) |
| 752 | return SMP_INVALID_PARAMS; | 763 | return SMP_INVALID_PARAMS; |
| 753 | 764 | ||
| 754 | if (!(conn->hcon->link_mode & HCI_LM_MASTER)) | 765 | if (conn->hcon->role != HCI_ROLE_MASTER) |
| 755 | return SMP_CMD_NOTSUPP; | 766 | return SMP_CMD_NOTSUPP; |
| 756 | 767 | ||
| 757 | skb_pull(skb, sizeof(*rsp)); | 768 | skb_pull(skb, sizeof(*rsp)); |
| @@ -839,26 +850,51 @@ static u8 smp_cmd_pairing_random(struct l2cap_conn *conn, struct sk_buff *skb) | |||
| 839 | return smp_random(smp); | 850 | return smp_random(smp); |
| 840 | } | 851 | } |
| 841 | 852 | ||
| 842 | static u8 smp_ltk_encrypt(struct l2cap_conn *conn, u8 sec_level) | 853 | static bool smp_ltk_encrypt(struct l2cap_conn *conn, u8 sec_level) |
| 843 | { | 854 | { |
| 844 | struct smp_ltk *key; | 855 | struct smp_ltk *key; |
| 845 | struct hci_conn *hcon = conn->hcon; | 856 | struct hci_conn *hcon = conn->hcon; |
| 846 | 857 | ||
| 847 | key = hci_find_ltk_by_addr(hcon->hdev, &hcon->dst, hcon->dst_type, | 858 | key = hci_find_ltk_by_addr(hcon->hdev, &hcon->dst, hcon->dst_type, |
| 848 | hcon->out); | 859 | hcon->role); |
| 849 | if (!key) | 860 | if (!key) |
| 850 | return 0; | 861 | return false; |
| 851 | 862 | ||
| 852 | if (sec_level > BT_SECURITY_MEDIUM && !key->authenticated) | 863 | if (sec_level > BT_SECURITY_MEDIUM && !key->authenticated) |
| 853 | return 0; | 864 | return false; |
| 854 | 865 | ||
| 855 | if (test_and_set_bit(HCI_CONN_ENCRYPT_PEND, &hcon->flags)) | 866 | if (test_and_set_bit(HCI_CONN_ENCRYPT_PEND, &hcon->flags)) |
| 856 | return 1; | 867 | return true; |
| 857 | 868 | ||
| 858 | hci_le_start_enc(hcon, key->ediv, key->rand, key->val); | 869 | hci_le_start_enc(hcon, key->ediv, key->rand, key->val); |
| 859 | hcon->enc_key_size = key->enc_size; | 870 | hcon->enc_key_size = key->enc_size; |
| 860 | 871 | ||
| 861 | return 1; | 872 | /* We never store STKs for master role, so clear this flag */ |
| 873 | clear_bit(HCI_CONN_STK_ENCRYPT, &hcon->flags); | ||
| 874 | |||
| 875 | return true; | ||
| 876 | } | ||
| 877 | |||
| 878 | bool smp_sufficient_security(struct hci_conn *hcon, u8 sec_level) | ||
| 879 | { | ||
| 880 | if (sec_level == BT_SECURITY_LOW) | ||
| 881 | return true; | ||
| 882 | |||
| 883 | /* If we're encrypted with an STK always claim insufficient | ||
| 884 | * security. This way we allow the connection to be re-encrypted | ||
| 885 | * with an LTK, even if the LTK provides the same level of | ||
| 886 | * security. Only exception is if we don't have an LTK (e.g. | ||
| 887 | * because of key distribution bits). | ||
| 888 | */ | ||
| 889 | if (test_bit(HCI_CONN_STK_ENCRYPT, &hcon->flags) && | ||
| 890 | hci_find_ltk_by_addr(hcon->hdev, &hcon->dst, hcon->dst_type, | ||
| 891 | hcon->role)) | ||
| 892 | return false; | ||
| 893 | |||
| 894 | if (hcon->sec_level >= sec_level) | ||
| 895 | return true; | ||
| 896 | |||
| 897 | return false; | ||
| 862 | } | 898 | } |
| 863 | 899 | ||
| 864 | static u8 smp_cmd_security_req(struct l2cap_conn *conn, struct sk_buff *skb) | 900 | static u8 smp_cmd_security_req(struct l2cap_conn *conn, struct sk_buff *skb) |
| @@ -874,10 +910,13 @@ static u8 smp_cmd_security_req(struct l2cap_conn *conn, struct sk_buff *skb) | |||
| 874 | if (skb->len < sizeof(*rp)) | 910 | if (skb->len < sizeof(*rp)) |
| 875 | return SMP_INVALID_PARAMS; | 911 | return SMP_INVALID_PARAMS; |
| 876 | 912 | ||
| 877 | if (!(conn->hcon->link_mode & HCI_LM_MASTER)) | 913 | if (hcon->role != HCI_ROLE_MASTER) |
| 878 | return SMP_CMD_NOTSUPP; | 914 | return SMP_CMD_NOTSUPP; |
| 879 | 915 | ||
| 880 | sec_level = authreq_to_seclevel(rp->auth_req); | 916 | sec_level = authreq_to_seclevel(rp->auth_req); |
| 917 | if (smp_sufficient_security(hcon, sec_level)) | ||
| 918 | return 0; | ||
| 919 | |||
| 881 | if (sec_level > hcon->pending_sec_level) | 920 | if (sec_level > hcon->pending_sec_level) |
| 882 | hcon->pending_sec_level = sec_level; | 921 | hcon->pending_sec_level = sec_level; |
| 883 | 922 | ||
| @@ -888,6 +927,12 @@ static u8 smp_cmd_security_req(struct l2cap_conn *conn, struct sk_buff *skb) | |||
| 888 | return 0; | 927 | return 0; |
| 889 | 928 | ||
| 890 | smp = smp_chan_create(conn); | 929 | smp = smp_chan_create(conn); |
| 930 | if (!smp) | ||
| 931 | return SMP_UNSPECIFIED; | ||
| 932 | |||
| 933 | if (!test_bit(HCI_BONDABLE, &hcon->hdev->dev_flags) && | ||
| 934 | (rp->auth_req & SMP_AUTH_BONDING)) | ||
| 935 | return SMP_PAIRING_NOTSUPP; | ||
| 891 | 936 | ||
| 892 | skb_pull(skb, sizeof(*rp)); | 937 | skb_pull(skb, sizeof(*rp)); |
| 893 | 938 | ||
| @@ -899,22 +944,9 @@ static u8 smp_cmd_security_req(struct l2cap_conn *conn, struct sk_buff *skb) | |||
| 899 | 944 | ||
| 900 | smp_send_cmd(conn, SMP_CMD_PAIRING_REQ, sizeof(cp), &cp); | 945 | smp_send_cmd(conn, SMP_CMD_PAIRING_REQ, sizeof(cp), &cp); |
| 901 | 946 | ||
| 902 | clear_bit(SMP_FLAG_INITIATOR, &smp->flags); | ||
| 903 | |||
| 904 | return 0; | 947 | return 0; |
| 905 | } | 948 | } |
| 906 | 949 | ||
| 907 | bool smp_sufficient_security(struct hci_conn *hcon, u8 sec_level) | ||
| 908 | { | ||
| 909 | if (sec_level == BT_SECURITY_LOW) | ||
| 910 | return true; | ||
| 911 | |||
| 912 | if (hcon->sec_level >= sec_level) | ||
| 913 | return true; | ||
| 914 | |||
| 915 | return false; | ||
| 916 | } | ||
| 917 | |||
| 918 | int smp_conn_security(struct hci_conn *hcon, __u8 sec_level) | 950 | int smp_conn_security(struct hci_conn *hcon, __u8 sec_level) |
| 919 | { | 951 | { |
| 920 | struct l2cap_conn *conn = hcon->l2cap_data; | 952 | struct l2cap_conn *conn = hcon->l2cap_data; |
| @@ -936,7 +968,7 @@ int smp_conn_security(struct hci_conn *hcon, __u8 sec_level) | |||
| 936 | if (sec_level > hcon->pending_sec_level) | 968 | if (sec_level > hcon->pending_sec_level) |
| 937 | hcon->pending_sec_level = sec_level; | 969 | hcon->pending_sec_level = sec_level; |
| 938 | 970 | ||
| 939 | if (hcon->link_mode & HCI_LM_MASTER) | 971 | if (hcon->role == HCI_ROLE_MASTER) |
| 940 | if (smp_ltk_encrypt(conn, hcon->pending_sec_level)) | 972 | if (smp_ltk_encrypt(conn, hcon->pending_sec_level)) |
| 941 | return 0; | 973 | return 0; |
| 942 | 974 | ||
| @@ -956,7 +988,7 @@ int smp_conn_security(struct hci_conn *hcon, __u8 sec_level) | |||
| 956 | hcon->pending_sec_level > BT_SECURITY_MEDIUM) | 988 | hcon->pending_sec_level > BT_SECURITY_MEDIUM) |
| 957 | authreq |= SMP_AUTH_MITM; | 989 | authreq |= SMP_AUTH_MITM; |
| 958 | 990 | ||
| 959 | if (hcon->link_mode & HCI_LM_MASTER) { | 991 | if (hcon->role == HCI_ROLE_MASTER) { |
| 960 | struct smp_cmd_pairing cp; | 992 | struct smp_cmd_pairing cp; |
| 961 | 993 | ||
| 962 | build_pairing_cmd(conn, &cp, NULL, authreq); | 994 | build_pairing_cmd(conn, &cp, NULL, authreq); |
| @@ -1021,7 +1053,7 @@ static int smp_cmd_master_ident(struct l2cap_conn *conn, struct sk_buff *skb) | |||
| 1021 | 1053 | ||
| 1022 | hci_dev_lock(hdev); | 1054 | hci_dev_lock(hdev); |
| 1023 | authenticated = (hcon->sec_level == BT_SECURITY_HIGH); | 1055 | authenticated = (hcon->sec_level == BT_SECURITY_HIGH); |
| 1024 | ltk = hci_add_ltk(hdev, &hcon->dst, hcon->dst_type, HCI_SMP_LTK, | 1056 | ltk = hci_add_ltk(hdev, &hcon->dst, hcon->dst_type, SMP_LTK, |
| 1025 | authenticated, smp->tk, smp->enc_key_size, | 1057 | authenticated, smp->tk, smp->enc_key_size, |
| 1026 | rp->ediv, rp->rand); | 1058 | rp->ediv, rp->rand); |
| 1027 | smp->ltk = ltk; | 1059 | smp->ltk = ltk; |
| @@ -1075,6 +1107,8 @@ static int smp_cmd_ident_addr_info(struct l2cap_conn *conn, | |||
| 1075 | 1107 | ||
| 1076 | skb_pull(skb, sizeof(*info)); | 1108 | skb_pull(skb, sizeof(*info)); |
| 1077 | 1109 | ||
| 1110 | hci_dev_lock(hcon->hdev); | ||
| 1111 | |||
| 1078 | /* Strictly speaking the Core Specification (4.1) allows sending | 1112 | /* Strictly speaking the Core Specification (4.1) allows sending |
| 1079 | * an empty address which would force us to rely on just the IRK | 1113 | * an empty address which would force us to rely on just the IRK |
| 1080 | * as "identity information". However, since such | 1114 | * as "identity information". However, since such |
| @@ -1084,8 +1118,7 @@ static int smp_cmd_ident_addr_info(struct l2cap_conn *conn, | |||
| 1084 | */ | 1118 | */ |
| 1085 | if (!bacmp(&info->bdaddr, BDADDR_ANY)) { | 1119 | if (!bacmp(&info->bdaddr, BDADDR_ANY)) { |
| 1086 | BT_ERR("Ignoring IRK with no identity address"); | 1120 | BT_ERR("Ignoring IRK with no identity address"); |
| 1087 | smp_distribute_keys(conn); | 1121 | goto distribute; |
| 1088 | return 0; | ||
| 1089 | } | 1122 | } |
| 1090 | 1123 | ||
| 1091 | bacpy(&smp->id_addr, &info->bdaddr); | 1124 | bacpy(&smp->id_addr, &info->bdaddr); |
| @@ -1099,8 +1132,11 @@ static int smp_cmd_ident_addr_info(struct l2cap_conn *conn, | |||
| 1099 | smp->remote_irk = hci_add_irk(conn->hcon->hdev, &smp->id_addr, | 1132 | smp->remote_irk = hci_add_irk(conn->hcon->hdev, &smp->id_addr, |
| 1100 | smp->id_addr_type, smp->irk, &rpa); | 1133 | smp->id_addr_type, smp->irk, &rpa); |
| 1101 | 1134 | ||
| 1135 | distribute: | ||
| 1102 | smp_distribute_keys(conn); | 1136 | smp_distribute_keys(conn); |
| 1103 | 1137 | ||
| 1138 | hci_dev_unlock(hcon->hdev); | ||
| 1139 | |||
| 1104 | return 0; | 1140 | return 0; |
| 1105 | } | 1141 | } |
| 1106 | 1142 | ||
| @@ -1156,7 +1192,7 @@ int smp_sig_channel(struct l2cap_conn *conn, struct sk_buff *skb) | |||
| 1156 | } | 1192 | } |
| 1157 | 1193 | ||
| 1158 | if (!test_bit(HCI_LE_ENABLED, &hcon->hdev->dev_flags)) { | 1194 | if (!test_bit(HCI_LE_ENABLED, &hcon->hdev->dev_flags)) { |
| 1159 | err = -ENOTSUPP; | 1195 | err = -EOPNOTSUPP; |
| 1160 | reason = SMP_PAIRING_NOTSUPP; | 1196 | reason = SMP_PAIRING_NOTSUPP; |
| 1161 | goto done; | 1197 | goto done; |
| 1162 | } | 1198 | } |
| @@ -1174,7 +1210,7 @@ int smp_sig_channel(struct l2cap_conn *conn, struct sk_buff *skb) | |||
| 1174 | !conn->smp_chan) { | 1210 | !conn->smp_chan) { |
| 1175 | BT_ERR("Unexpected SMP command 0x%02x. Disconnecting.", code); | 1211 | BT_ERR("Unexpected SMP command 0x%02x. Disconnecting.", code); |
| 1176 | kfree_skb(skb); | 1212 | kfree_skb(skb); |
| 1177 | return -ENOTSUPP; | 1213 | return -EOPNOTSUPP; |
| 1178 | } | 1214 | } |
| 1179 | 1215 | ||
| 1180 | switch (code) { | 1216 | switch (code) { |
| @@ -1258,6 +1294,22 @@ static void smp_notify_keys(struct l2cap_conn *conn) | |||
| 1258 | bacpy(&hcon->dst, &smp->remote_irk->bdaddr); | 1294 | bacpy(&hcon->dst, &smp->remote_irk->bdaddr); |
| 1259 | hcon->dst_type = smp->remote_irk->addr_type; | 1295 | hcon->dst_type = smp->remote_irk->addr_type; |
| 1260 | l2cap_conn_update_id_addr(hcon); | 1296 | l2cap_conn_update_id_addr(hcon); |
| 1297 | |||
| 1298 | /* When receiving an indentity resolving key for | ||
| 1299 | * a remote device that does not use a resolvable | ||
| 1300 | * private address, just remove the key so that | ||
| 1301 | * it is possible to use the controller white | ||
| 1302 | * list for scanning. | ||
| 1303 | * | ||
| 1304 | * Userspace will have been told to not store | ||
| 1305 | * this key at this point. So it is safe to | ||
| 1306 | * just remove it. | ||
| 1307 | */ | ||
| 1308 | if (!bacmp(&smp->remote_irk->rpa, BDADDR_ANY)) { | ||
| 1309 | list_del(&smp->remote_irk->list); | ||
| 1310 | kfree(smp->remote_irk); | ||
| 1311 | smp->remote_irk = NULL; | ||
| 1312 | } | ||
| 1261 | } | 1313 | } |
| 1262 | 1314 | ||
| 1263 | /* The LTKs and CSRKs should be persistent only if both sides | 1315 | /* The LTKs and CSRKs should be persistent only if both sides |
| @@ -1337,7 +1389,7 @@ int smp_distribute_keys(struct l2cap_conn *conn) | |||
| 1337 | 1389 | ||
| 1338 | authenticated = hcon->sec_level == BT_SECURITY_HIGH; | 1390 | authenticated = hcon->sec_level == BT_SECURITY_HIGH; |
| 1339 | ltk = hci_add_ltk(hdev, &hcon->dst, hcon->dst_type, | 1391 | ltk = hci_add_ltk(hdev, &hcon->dst, hcon->dst_type, |
| 1340 | HCI_SMP_LTK_SLAVE, authenticated, enc.ltk, | 1392 | SMP_LTK_SLAVE, authenticated, enc.ltk, |
| 1341 | smp->enc_key_size, ediv, rand); | 1393 | smp->enc_key_size, ediv, rand); |
| 1342 | smp->slave_ltk = ltk; | 1394 | smp->slave_ltk = ltk; |
| 1343 | 1395 | ||
diff --git a/net/bluetooth/smp.h b/net/bluetooth/smp.h index 5a8dc36460a1..796f4f45f92f 100644 --- a/net/bluetooth/smp.h +++ b/net/bluetooth/smp.h | |||
| @@ -116,6 +116,13 @@ struct smp_cmd_security_req { | |||
| 116 | #define SMP_MIN_ENC_KEY_SIZE 7 | 116 | #define SMP_MIN_ENC_KEY_SIZE 7 |
| 117 | #define SMP_MAX_ENC_KEY_SIZE 16 | 117 | #define SMP_MAX_ENC_KEY_SIZE 16 |
| 118 | 118 | ||
| 119 | /* LTK types used in internal storage (struct smp_ltk) */ | ||
| 120 | enum { | ||
| 121 | SMP_STK, | ||
| 122 | SMP_LTK, | ||
| 123 | SMP_LTK_SLAVE, | ||
| 124 | }; | ||
| 125 | |||
| 119 | /* SMP Commands */ | 126 | /* SMP Commands */ |
| 120 | bool smp_sufficient_security(struct hci_conn *hcon, u8 sec_level); | 127 | bool smp_sufficient_security(struct hci_conn *hcon, u8 sec_level); |
| 121 | int smp_conn_security(struct hci_conn *hcon, __u8 sec_level); | 128 | int smp_conn_security(struct hci_conn *hcon, __u8 sec_level); |
diff --git a/net/bridge/br_fdb.c b/net/bridge/br_fdb.c index b524c36c1273..6f6c95cfe8f2 100644 --- a/net/bridge/br_fdb.c +++ b/net/bridge/br_fdb.c | |||
| @@ -93,7 +93,7 @@ static void fdb_rcu_free(struct rcu_head *head) | |||
| 93 | static void fdb_add_hw(struct net_bridge *br, const unsigned char *addr) | 93 | static void fdb_add_hw(struct net_bridge *br, const unsigned char *addr) |
| 94 | { | 94 | { |
| 95 | int err; | 95 | int err; |
| 96 | struct net_bridge_port *p, *tmp; | 96 | struct net_bridge_port *p; |
| 97 | 97 | ||
| 98 | ASSERT_RTNL(); | 98 | ASSERT_RTNL(); |
| 99 | 99 | ||
| @@ -107,11 +107,9 @@ static void fdb_add_hw(struct net_bridge *br, const unsigned char *addr) | |||
| 107 | 107 | ||
| 108 | return; | 108 | return; |
| 109 | undo: | 109 | undo: |
| 110 | list_for_each_entry(tmp, &br->port_list, list) { | 110 | list_for_each_entry_continue_reverse(p, &br->port_list, list) { |
| 111 | if (tmp == p) | 111 | if (!br_promisc_port(p)) |
| 112 | break; | 112 | dev_uc_del(p->dev, addr); |
| 113 | if (!br_promisc_port(tmp)) | ||
| 114 | dev_uc_del(tmp->dev, addr); | ||
| 115 | } | 113 | } |
| 116 | } | 114 | } |
| 117 | 115 | ||
| @@ -631,7 +629,7 @@ static int fdb_fill_info(struct sk_buff *skb, const struct net_bridge *br, | |||
| 631 | if (nla_put(skb, NDA_CACHEINFO, sizeof(ci), &ci)) | 629 | if (nla_put(skb, NDA_CACHEINFO, sizeof(ci), &ci)) |
| 632 | goto nla_put_failure; | 630 | goto nla_put_failure; |
| 633 | 631 | ||
| 634 | if (nla_put(skb, NDA_VLAN, sizeof(u16), &fdb->vlan_id)) | 632 | if (fdb->vlan_id && nla_put(skb, NDA_VLAN, sizeof(u16), &fdb->vlan_id)) |
| 635 | goto nla_put_failure; | 633 | goto nla_put_failure; |
| 636 | 634 | ||
| 637 | return nlmsg_end(skb, nlh); | 635 | return nlmsg_end(skb, nlh); |
| @@ -678,6 +676,7 @@ errout: | |||
| 678 | int br_fdb_dump(struct sk_buff *skb, | 676 | int br_fdb_dump(struct sk_buff *skb, |
| 679 | struct netlink_callback *cb, | 677 | struct netlink_callback *cb, |
| 680 | struct net_device *dev, | 678 | struct net_device *dev, |
| 679 | struct net_device *filter_dev, | ||
| 681 | int idx) | 680 | int idx) |
| 682 | { | 681 | { |
| 683 | struct net_bridge *br = netdev_priv(dev); | 682 | struct net_bridge *br = netdev_priv(dev); |
| @@ -693,6 +692,19 @@ int br_fdb_dump(struct sk_buff *skb, | |||
| 693 | if (idx < cb->args[0]) | 692 | if (idx < cb->args[0]) |
| 694 | goto skip; | 693 | goto skip; |
| 695 | 694 | ||
| 695 | if (filter_dev && | ||
| 696 | (!f->dst || f->dst->dev != filter_dev)) { | ||
| 697 | if (filter_dev != dev) | ||
| 698 | goto skip; | ||
| 699 | /* !f->dst is a speacial case for bridge | ||
| 700 | * It means the MAC belongs to the bridge | ||
| 701 | * Therefore need a little more filtering | ||
| 702 | * we only want to dump the !f->dst case | ||
| 703 | */ | ||
| 704 | if (f->dst) | ||
| 705 | goto skip; | ||
| 706 | } | ||
| 707 | |||
| 696 | if (fdb_fill_info(skb, br, f, | 708 | if (fdb_fill_info(skb, br, f, |
| 697 | NETLINK_CB(cb->skb).portid, | 709 | NETLINK_CB(cb->skb).portid, |
| 698 | cb->nlh->nlmsg_seq, | 710 | cb->nlh->nlmsg_seq, |
diff --git a/net/bridge/br_if.c b/net/bridge/br_if.c index 3eca3fdf8fe1..078d336a1f37 100644 --- a/net/bridge/br_if.c +++ b/net/bridge/br_if.c | |||
| @@ -344,7 +344,7 @@ int br_add_bridge(struct net *net, const char *name) | |||
| 344 | struct net_device *dev; | 344 | struct net_device *dev; |
| 345 | int res; | 345 | int res; |
| 346 | 346 | ||
| 347 | dev = alloc_netdev(sizeof(struct net_bridge), name, | 347 | dev = alloc_netdev(sizeof(struct net_bridge), name, NET_NAME_UNKNOWN, |
| 348 | br_dev_setup); | 348 | br_dev_setup); |
| 349 | 349 | ||
| 350 | if (!dev) | 350 | if (!dev) |
diff --git a/net/bridge/br_multicast.c b/net/bridge/br_multicast.c index abfa0b65a111..7751c92c8c57 100644 --- a/net/bridge/br_multicast.c +++ b/net/bridge/br_multicast.c | |||
| @@ -1174,7 +1174,7 @@ static void br_multicast_add_router(struct net_bridge *br, | |||
| 1174 | } | 1174 | } |
| 1175 | 1175 | ||
| 1176 | if (slot) | 1176 | if (slot) |
| 1177 | hlist_add_after_rcu(slot, &port->rlist); | 1177 | hlist_add_behind_rcu(&port->rlist, slot); |
| 1178 | else | 1178 | else |
| 1179 | hlist_add_head_rcu(&port->rlist, &br->router_list); | 1179 | hlist_add_head_rcu(&port->rlist, &br->router_list); |
| 1180 | } | 1180 | } |
| @@ -2216,6 +2216,43 @@ unlock: | |||
| 2216 | EXPORT_SYMBOL_GPL(br_multicast_list_adjacent); | 2216 | EXPORT_SYMBOL_GPL(br_multicast_list_adjacent); |
| 2217 | 2217 | ||
| 2218 | /** | 2218 | /** |
| 2219 | * br_multicast_has_querier_anywhere - Checks for a querier on a bridge | ||
| 2220 | * @dev: The bridge port providing the bridge on which to check for a querier | ||
| 2221 | * @proto: The protocol family to check for: IGMP -> ETH_P_IP, MLD -> ETH_P_IPV6 | ||
| 2222 | * | ||
| 2223 | * Checks whether the given interface has a bridge on top and if so returns | ||
| 2224 | * true if a valid querier exists anywhere on the bridged link layer. | ||
| 2225 | * Otherwise returns false. | ||
| 2226 | */ | ||
| 2227 | bool br_multicast_has_querier_anywhere(struct net_device *dev, int proto) | ||
| 2228 | { | ||
| 2229 | struct net_bridge *br; | ||
| 2230 | struct net_bridge_port *port; | ||
| 2231 | struct ethhdr eth; | ||
| 2232 | bool ret = false; | ||
| 2233 | |||
| 2234 | rcu_read_lock(); | ||
| 2235 | if (!br_port_exists(dev)) | ||
| 2236 | goto unlock; | ||
| 2237 | |||
| 2238 | port = br_port_get_rcu(dev); | ||
| 2239 | if (!port || !port->br) | ||
| 2240 | goto unlock; | ||
| 2241 | |||
| 2242 | br = port->br; | ||
| 2243 | |||
| 2244 | memset(ð, 0, sizeof(eth)); | ||
| 2245 | eth.h_proto = htons(proto); | ||
| 2246 | |||
| 2247 | ret = br_multicast_querier_exists(br, ð); | ||
| 2248 | |||
| 2249 | unlock: | ||
| 2250 | rcu_read_unlock(); | ||
| 2251 | return ret; | ||
| 2252 | } | ||
| 2253 | EXPORT_SYMBOL_GPL(br_multicast_has_querier_anywhere); | ||
| 2254 | |||
| 2255 | /** | ||
| 2219 | * br_multicast_has_querier_adjacent - Checks for a querier behind a bridge port | 2256 | * br_multicast_has_querier_adjacent - Checks for a querier behind a bridge port |
| 2220 | * @dev: The bridge port adjacent to which to check for a querier | 2257 | * @dev: The bridge port adjacent to which to check for a querier |
| 2221 | * @proto: The protocol family to check for: IGMP -> ETH_P_IP, MLD -> ETH_P_IPV6 | 2258 | * @proto: The protocol family to check for: IGMP -> ETH_P_IP, MLD -> ETH_P_IPV6 |
diff --git a/net/bridge/br_netlink.c b/net/bridge/br_netlink.c index 26edb518b839..cb5fcf62f663 100644 --- a/net/bridge/br_netlink.c +++ b/net/bridge/br_netlink.c | |||
| @@ -208,7 +208,6 @@ int br_getlink(struct sk_buff *skb, u32 pid, u32 seq, | |||
| 208 | int err = 0; | 208 | int err = 0; |
| 209 | struct net_bridge_port *port = br_port_get_rtnl(dev); | 209 | struct net_bridge_port *port = br_port_get_rtnl(dev); |
| 210 | 210 | ||
| 211 | /* not a bridge port and */ | ||
| 212 | if (!port && !(filter_mask & RTEXT_FILTER_BRVLAN)) | 211 | if (!port && !(filter_mask & RTEXT_FILTER_BRVLAN)) |
| 213 | goto out; | 212 | goto out; |
| 214 | 213 | ||
diff --git a/net/bridge/br_private.h b/net/bridge/br_private.h index 23caf5b0309e..62a7fa2e3569 100644 --- a/net/bridge/br_private.h +++ b/net/bridge/br_private.h | |||
| @@ -399,7 +399,7 @@ int br_fdb_delete(struct ndmsg *ndm, struct nlattr *tb[], | |||
| 399 | int br_fdb_add(struct ndmsg *nlh, struct nlattr *tb[], struct net_device *dev, | 399 | int br_fdb_add(struct ndmsg *nlh, struct nlattr *tb[], struct net_device *dev, |
| 400 | const unsigned char *addr, u16 nlh_flags); | 400 | const unsigned char *addr, u16 nlh_flags); |
| 401 | int br_fdb_dump(struct sk_buff *skb, struct netlink_callback *cb, | 401 | int br_fdb_dump(struct sk_buff *skb, struct netlink_callback *cb, |
| 402 | struct net_device *dev, int idx); | 402 | struct net_device *dev, struct net_device *fdev, int idx); |
| 403 | int br_fdb_sync_static(struct net_bridge *br, struct net_bridge_port *p); | 403 | int br_fdb_sync_static(struct net_bridge *br, struct net_bridge_port *p); |
| 404 | void br_fdb_unsync_static(struct net_bridge *br, struct net_bridge_port *p); | 404 | void br_fdb_unsync_static(struct net_bridge *br, struct net_bridge_port *p); |
| 405 | 405 | ||
diff --git a/net/bridge/br_vlan.c b/net/bridge/br_vlan.c index 2b2774fe0703..e1bcd653899b 100644 --- a/net/bridge/br_vlan.c +++ b/net/bridge/br_vlan.c | |||
| @@ -55,10 +55,8 @@ static int __vlan_add(struct net_port_vlans *v, u16 vid, u16 flags) | |||
| 55 | 55 | ||
| 56 | if (p) { | 56 | if (p) { |
| 57 | /* Add VLAN to the device filter if it is supported. | 57 | /* Add VLAN to the device filter if it is supported. |
| 58 | * Stricly speaking, this is not necessary now, since | 58 | * This ensures tagged traffic enters the bridge when |
| 59 | * devices are made promiscuous by the bridge, but if | 59 | * promiscuous mode is disabled by br_manage_promisc(). |
| 60 | * that ever changes this code will allow tagged | ||
| 61 | * traffic to enter the bridge. | ||
| 62 | */ | 60 | */ |
| 63 | err = vlan_vid_add(dev, br->vlan_proto, vid); | 61 | err = vlan_vid_add(dev, br->vlan_proto, vid); |
| 64 | if (err) | 62 | if (err) |
| @@ -183,7 +181,7 @@ bool br_allowed_ingress(struct net_bridge *br, struct net_port_vlans *v, | |||
| 183 | */ | 181 | */ |
| 184 | if (unlikely(!vlan_tx_tag_present(skb) && | 182 | if (unlikely(!vlan_tx_tag_present(skb) && |
| 185 | skb->protocol == proto)) { | 183 | skb->protocol == proto)) { |
| 186 | skb = vlan_untag(skb); | 184 | skb = skb_vlan_untag(skb); |
| 187 | if (unlikely(!skb)) | 185 | if (unlikely(!skb)) |
| 188 | return false; | 186 | return false; |
| 189 | } | 187 | } |
diff --git a/net/bridge/netfilter/Kconfig b/net/bridge/netfilter/Kconfig index 629dc77874a9..9cebf47ac840 100644 --- a/net/bridge/netfilter/Kconfig +++ b/net/bridge/netfilter/Kconfig | |||
| @@ -14,6 +14,15 @@ config NFT_BRIDGE_META | |||
| 14 | help | 14 | help |
| 15 | Add support for bridge dedicated meta key. | 15 | Add support for bridge dedicated meta key. |
| 16 | 16 | ||
| 17 | config NFT_BRIDGE_REJECT | ||
| 18 | tristate "Netfilter nf_tables bridge reject support" | ||
| 19 | depends on NFT_REJECT && NFT_REJECT_IPV4 && NFT_REJECT_IPV6 | ||
| 20 | help | ||
| 21 | Add support to reject packets. | ||
| 22 | |||
| 23 | config NF_LOG_BRIDGE | ||
| 24 | tristate "Bridge packet logging" | ||
| 25 | |||
| 17 | endif # NF_TABLES_BRIDGE | 26 | endif # NF_TABLES_BRIDGE |
| 18 | 27 | ||
| 19 | menuconfig BRIDGE_NF_EBTABLES | 28 | menuconfig BRIDGE_NF_EBTABLES |
| @@ -202,22 +211,6 @@ config BRIDGE_EBT_LOG | |||
| 202 | 211 | ||
| 203 | To compile it as a module, choose M here. If unsure, say N. | 212 | To compile it as a module, choose M here. If unsure, say N. |
| 204 | 213 | ||
| 205 | config BRIDGE_EBT_ULOG | ||
| 206 | tristate "ebt: ulog support (OBSOLETE)" | ||
| 207 | help | ||
| 208 | This option enables the old bridge-specific "ebt_ulog" implementation | ||
| 209 | which has been obsoleted by the new "nfnetlink_log" code (see | ||
| 210 | CONFIG_NETFILTER_NETLINK_LOG). | ||
| 211 | |||
| 212 | This option adds the ulog watcher, that you can use in any rule | ||
| 213 | in any ebtables table. The packet is passed to a userspace | ||
| 214 | logging daemon using netlink multicast sockets. This differs | ||
| 215 | from the log watcher in the sense that the complete packet is | ||
| 216 | sent to userspace instead of a descriptive text and that | ||
| 217 | netlink multicast sockets are used instead of the syslog. | ||
| 218 | |||
| 219 | To compile it as a module, choose M here. If unsure, say N. | ||
| 220 | |||
| 221 | config BRIDGE_EBT_NFLOG | 214 | config BRIDGE_EBT_NFLOG |
| 222 | tristate "ebt: nflog support" | 215 | tristate "ebt: nflog support" |
| 223 | help | 216 | help |
diff --git a/net/bridge/netfilter/Makefile b/net/bridge/netfilter/Makefile index 6f2f3943d66f..be4d0cea78ce 100644 --- a/net/bridge/netfilter/Makefile +++ b/net/bridge/netfilter/Makefile | |||
| @@ -4,6 +4,10 @@ | |||
| 4 | 4 | ||
| 5 | obj-$(CONFIG_NF_TABLES_BRIDGE) += nf_tables_bridge.o | 5 | obj-$(CONFIG_NF_TABLES_BRIDGE) += nf_tables_bridge.o |
| 6 | obj-$(CONFIG_NFT_BRIDGE_META) += nft_meta_bridge.o | 6 | obj-$(CONFIG_NFT_BRIDGE_META) += nft_meta_bridge.o |
| 7 | obj-$(CONFIG_NFT_BRIDGE_REJECT) += nft_reject_bridge.o | ||
| 8 | |||
| 9 | # packet logging | ||
| 10 | obj-$(CONFIG_NF_LOG_BRIDGE) += nf_log_bridge.o | ||
| 7 | 11 | ||
| 8 | obj-$(CONFIG_BRIDGE_NF_EBTABLES) += ebtables.o | 12 | obj-$(CONFIG_BRIDGE_NF_EBTABLES) += ebtables.o |
| 9 | 13 | ||
| @@ -33,5 +37,4 @@ obj-$(CONFIG_BRIDGE_EBT_SNAT) += ebt_snat.o | |||
| 33 | 37 | ||
| 34 | # watchers | 38 | # watchers |
| 35 | obj-$(CONFIG_BRIDGE_EBT_LOG) += ebt_log.o | 39 | obj-$(CONFIG_BRIDGE_EBT_LOG) += ebt_log.o |
| 36 | obj-$(CONFIG_BRIDGE_EBT_ULOG) += ebt_ulog.o | ||
| 37 | obj-$(CONFIG_BRIDGE_EBT_NFLOG) += ebt_nflog.o | 40 | obj-$(CONFIG_BRIDGE_EBT_NFLOG) += ebt_nflog.o |
diff --git a/net/bridge/netfilter/ebt_log.c b/net/bridge/netfilter/ebt_log.c index 5322a36867a3..17f2e4bc2a29 100644 --- a/net/bridge/netfilter/ebt_log.c +++ b/net/bridge/netfilter/ebt_log.c | |||
| @@ -186,6 +186,10 @@ ebt_log_tg(struct sk_buff *skb, const struct xt_action_param *par) | |||
| 186 | li.u.log.level = info->loglevel; | 186 | li.u.log.level = info->loglevel; |
| 187 | li.u.log.logflags = info->bitmask; | 187 | li.u.log.logflags = info->bitmask; |
| 188 | 188 | ||
| 189 | /* Remember that we have to use ebt_log_packet() not to break backward | ||
| 190 | * compatibility. We cannot use the default bridge packet logger via | ||
| 191 | * nf_log_packet() with NFT_LOG_TYPE_LOG here. --Pablo | ||
| 192 | */ | ||
| 189 | if (info->bitmask & EBT_LOG_NFLOG) | 193 | if (info->bitmask & EBT_LOG_NFLOG) |
| 190 | nf_log_packet(net, NFPROTO_BRIDGE, par->hooknum, skb, | 194 | nf_log_packet(net, NFPROTO_BRIDGE, par->hooknum, skb, |
| 191 | par->in, par->out, &li, "%s", info->prefix); | 195 | par->in, par->out, &li, "%s", info->prefix); |
| @@ -205,54 +209,13 @@ static struct xt_target ebt_log_tg_reg __read_mostly = { | |||
| 205 | .me = THIS_MODULE, | 209 | .me = THIS_MODULE, |
| 206 | }; | 210 | }; |
| 207 | 211 | ||
| 208 | static struct nf_logger ebt_log_logger __read_mostly = { | ||
| 209 | .name = "ebt_log", | ||
| 210 | .logfn = &ebt_log_packet, | ||
| 211 | .me = THIS_MODULE, | ||
| 212 | }; | ||
| 213 | |||
| 214 | static int __net_init ebt_log_net_init(struct net *net) | ||
| 215 | { | ||
| 216 | nf_log_set(net, NFPROTO_BRIDGE, &ebt_log_logger); | ||
| 217 | return 0; | ||
| 218 | } | ||
| 219 | |||
| 220 | static void __net_exit ebt_log_net_fini(struct net *net) | ||
| 221 | { | ||
| 222 | nf_log_unset(net, &ebt_log_logger); | ||
| 223 | } | ||
| 224 | |||
| 225 | static struct pernet_operations ebt_log_net_ops = { | ||
| 226 | .init = ebt_log_net_init, | ||
| 227 | .exit = ebt_log_net_fini, | ||
| 228 | }; | ||
| 229 | |||
| 230 | static int __init ebt_log_init(void) | 212 | static int __init ebt_log_init(void) |
| 231 | { | 213 | { |
| 232 | int ret; | 214 | return xt_register_target(&ebt_log_tg_reg); |
| 233 | |||
| 234 | ret = register_pernet_subsys(&ebt_log_net_ops); | ||
| 235 | if (ret < 0) | ||
| 236 | goto err_pernet; | ||
| 237 | |||
| 238 | ret = xt_register_target(&ebt_log_tg_reg); | ||
| 239 | if (ret < 0) | ||
| 240 | goto err_target; | ||
| 241 | |||
| 242 | nf_log_register(NFPROTO_BRIDGE, &ebt_log_logger); | ||
| 243 | |||
| 244 | return ret; | ||
| 245 | |||
| 246 | err_target: | ||
| 247 | unregister_pernet_subsys(&ebt_log_net_ops); | ||
| 248 | err_pernet: | ||
| 249 | return ret; | ||
| 250 | } | 215 | } |
| 251 | 216 | ||
| 252 | static void __exit ebt_log_fini(void) | 217 | static void __exit ebt_log_fini(void) |
| 253 | { | 218 | { |
| 254 | unregister_pernet_subsys(&ebt_log_net_ops); | ||
| 255 | nf_log_unregister(&ebt_log_logger); | ||
| 256 | xt_unregister_target(&ebt_log_tg_reg); | 219 | xt_unregister_target(&ebt_log_tg_reg); |
| 257 | } | 220 | } |
| 258 | 221 | ||
diff --git a/net/bridge/netfilter/ebt_ulog.c b/net/bridge/netfilter/ebt_ulog.c deleted file mode 100644 index 7c470c371e14..000000000000 --- a/net/bridge/netfilter/ebt_ulog.c +++ /dev/null | |||
| @@ -1,393 +0,0 @@ | |||
| 1 | /* | ||
| 2 | * netfilter module for userspace bridged Ethernet frames logging daemons | ||
| 3 | * | ||
| 4 | * Authors: | ||
| 5 | * Bart De Schuymer <bdschuym@pandora.be> | ||
| 6 | * Harald Welte <laforge@netfilter.org> | ||
| 7 | * | ||
| 8 | * November, 2004 | ||
| 9 | * | ||
| 10 | * Based on ipt_ULOG.c, which is | ||
| 11 | * (C) 2000-2002 by Harald Welte <laforge@netfilter.org> | ||
| 12 | * | ||
| 13 | * This module accepts two parameters: | ||
| 14 | * | ||
| 15 | * nlbufsiz: | ||
| 16 | * The parameter specifies how big the buffer for each netlink multicast | ||
| 17 | * group is. e.g. If you say nlbufsiz=8192, up to eight kb of packets will | ||
| 18 | * get accumulated in the kernel until they are sent to userspace. It is | ||
| 19 | * NOT possible to allocate more than 128kB, and it is strongly discouraged, | ||
| 20 | * because atomically allocating 128kB inside the network rx softirq is not | ||
| 21 | * reliable. Please also keep in mind that this buffer size is allocated for | ||
| 22 | * each nlgroup you are using, so the total kernel memory usage increases | ||
| 23 | * by that factor. | ||
| 24 | * | ||
| 25 | * flushtimeout: | ||
| 26 | * Specify, after how many hundredths of a second the queue should be | ||
| 27 | * flushed even if it is not full yet. | ||
| 28 | * | ||
| 29 | */ | ||
| 30 | #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt | ||
| 31 | #include <linux/module.h> | ||
| 32 | #include <linux/slab.h> | ||
| 33 | #include <linux/spinlock.h> | ||
| 34 | #include <linux/socket.h> | ||
| 35 | #include <linux/skbuff.h> | ||
| 36 | #include <linux/kernel.h> | ||
| 37 | #include <linux/timer.h> | ||
| 38 | #include <net/netlink.h> | ||
| 39 | #include <linux/netdevice.h> | ||
| 40 | #include <linux/netfilter/x_tables.h> | ||
| 41 | #include <linux/netfilter_bridge/ebtables.h> | ||
| 42 | #include <linux/netfilter_bridge/ebt_ulog.h> | ||
| 43 | #include <net/netfilter/nf_log.h> | ||
| 44 | #include <net/netns/generic.h> | ||
| 45 | #include <net/sock.h> | ||
| 46 | #include "../br_private.h" | ||
| 47 | |||
| 48 | static unsigned int nlbufsiz = NLMSG_GOODSIZE; | ||
| 49 | module_param(nlbufsiz, uint, 0600); | ||
| 50 | MODULE_PARM_DESC(nlbufsiz, "netlink buffer size (number of bytes) " | ||
| 51 | "(defaults to 4096)"); | ||
| 52 | |||
| 53 | static unsigned int flushtimeout = 10; | ||
| 54 | module_param(flushtimeout, uint, 0600); | ||
| 55 | MODULE_PARM_DESC(flushtimeout, "buffer flush timeout (hundredths ofa second) " | ||
| 56 | "(defaults to 10)"); | ||
| 57 | |||
| 58 | typedef struct { | ||
| 59 | unsigned int qlen; /* number of nlmsgs' in the skb */ | ||
| 60 | struct nlmsghdr *lastnlh; /* netlink header of last msg in skb */ | ||
| 61 | struct sk_buff *skb; /* the pre-allocated skb */ | ||
| 62 | struct timer_list timer; /* the timer function */ | ||
| 63 | spinlock_t lock; /* the per-queue lock */ | ||
| 64 | } ebt_ulog_buff_t; | ||
| 65 | |||
| 66 | static int ebt_ulog_net_id __read_mostly; | ||
| 67 | struct ebt_ulog_net { | ||
| 68 | unsigned int nlgroup[EBT_ULOG_MAXNLGROUPS]; | ||
| 69 | ebt_ulog_buff_t ulog_buffers[EBT_ULOG_MAXNLGROUPS]; | ||
| 70 | struct sock *ebtulognl; | ||
| 71 | }; | ||
| 72 | |||
| 73 | static struct ebt_ulog_net *ebt_ulog_pernet(struct net *net) | ||
| 74 | { | ||
| 75 | return net_generic(net, ebt_ulog_net_id); | ||
| 76 | } | ||
| 77 | |||
| 78 | /* send one ulog_buff_t to userspace */ | ||
| 79 | static void ulog_send(struct ebt_ulog_net *ebt, unsigned int nlgroup) | ||
| 80 | { | ||
| 81 | ebt_ulog_buff_t *ub = &ebt->ulog_buffers[nlgroup]; | ||
| 82 | |||
| 83 | del_timer(&ub->timer); | ||
| 84 | |||
| 85 | if (!ub->skb) | ||
| 86 | return; | ||
| 87 | |||
| 88 | /* last nlmsg needs NLMSG_DONE */ | ||
| 89 | if (ub->qlen > 1) | ||
| 90 | ub->lastnlh->nlmsg_type = NLMSG_DONE; | ||
| 91 | |||
| 92 | NETLINK_CB(ub->skb).dst_group = nlgroup + 1; | ||
| 93 | netlink_broadcast(ebt->ebtulognl, ub->skb, 0, nlgroup + 1, GFP_ATOMIC); | ||
| 94 | |||
| 95 | ub->qlen = 0; | ||
| 96 | ub->skb = NULL; | ||
| 97 | } | ||
| 98 | |||
| 99 | /* timer function to flush queue in flushtimeout time */ | ||
| 100 | static void ulog_timer(unsigned long data) | ||
| 101 | { | ||
| 102 | struct ebt_ulog_net *ebt = container_of((void *)data, | ||
| 103 | struct ebt_ulog_net, | ||
| 104 | nlgroup[*(unsigned int *)data]); | ||
| 105 | |||
| 106 | ebt_ulog_buff_t *ub = &ebt->ulog_buffers[*(unsigned int *)data]; | ||
| 107 | spin_lock_bh(&ub->lock); | ||
| 108 | if (ub->skb) | ||
| 109 | ulog_send(ebt, *(unsigned int *)data); | ||
| 110 | spin_unlock_bh(&ub->lock); | ||
| 111 | } | ||
| 112 | |||
| 113 | static struct sk_buff *ulog_alloc_skb(unsigned int size) | ||
| 114 | { | ||
| 115 | struct sk_buff *skb; | ||
| 116 | unsigned int n; | ||
| 117 | |||
| 118 | n = max(size, nlbufsiz); | ||
| 119 | skb = alloc_skb(n, GFP_ATOMIC | __GFP_NOWARN); | ||
| 120 | if (!skb) { | ||
| 121 | if (n > size) { | ||
| 122 | /* try to allocate only as much as we need for | ||
| 123 | * current packet */ | ||
| 124 | skb = alloc_skb(size, GFP_ATOMIC); | ||
| 125 | if (!skb) | ||
| 126 | pr_debug("cannot even allocate buffer of size %ub\n", | ||
| 127 | size); | ||
| 128 | } | ||
| 129 | } | ||
| 130 | |||
| 131 | return skb; | ||
| 132 | } | ||
| 133 | |||
| 134 | static void ebt_ulog_packet(struct net *net, unsigned int hooknr, | ||
| 135 | const struct sk_buff *skb, | ||
| 136 | const struct net_device *in, | ||
| 137 | const struct net_device *out, | ||
| 138 | const struct ebt_ulog_info *uloginfo, | ||
| 139 | const char *prefix) | ||
| 140 | { | ||
| 141 | ebt_ulog_packet_msg_t *pm; | ||
| 142 | size_t size, copy_len; | ||
| 143 | struct nlmsghdr *nlh; | ||
| 144 | struct ebt_ulog_net *ebt = ebt_ulog_pernet(net); | ||
| 145 | unsigned int group = uloginfo->nlgroup; | ||
| 146 | ebt_ulog_buff_t *ub = &ebt->ulog_buffers[group]; | ||
| 147 | spinlock_t *lock = &ub->lock; | ||
| 148 | ktime_t kt; | ||
| 149 | |||
| 150 | if ((uloginfo->cprange == 0) || | ||
| 151 | (uloginfo->cprange > skb->len + ETH_HLEN)) | ||
| 152 | copy_len = skb->len + ETH_HLEN; | ||
| 153 | else | ||
| 154 | copy_len = uloginfo->cprange; | ||
| 155 | |||
| 156 | size = nlmsg_total_size(sizeof(*pm) + copy_len); | ||
| 157 | if (size > nlbufsiz) { | ||
| 158 | pr_debug("Size %Zd needed, but nlbufsiz=%d\n", size, nlbufsiz); | ||
| 159 | return; | ||
| 160 | } | ||
| 161 | |||
| 162 | spin_lock_bh(lock); | ||
| 163 | |||
| 164 | if (!ub->skb) { | ||
| 165 | if (!(ub->skb = ulog_alloc_skb(size))) | ||
| 166 | goto unlock; | ||
| 167 | } else if (size > skb_tailroom(ub->skb)) { | ||
| 168 | ulog_send(ebt, group); | ||
| 169 | |||
| 170 | if (!(ub->skb = ulog_alloc_skb(size))) | ||
| 171 | goto unlock; | ||
| 172 | } | ||
| 173 | |||
| 174 | nlh = nlmsg_put(ub->skb, 0, ub->qlen, 0, | ||
| 175 | size - NLMSG_ALIGN(sizeof(*nlh)), 0); | ||
| 176 | if (!nlh) { | ||
| 177 | kfree_skb(ub->skb); | ||
| 178 | ub->skb = NULL; | ||
| 179 | goto unlock; | ||
| 180 | } | ||
| 181 | ub->qlen++; | ||
| 182 | |||
| 183 | pm = nlmsg_data(nlh); | ||
| 184 | memset(pm, 0, sizeof(*pm)); | ||
| 185 | |||
| 186 | /* Fill in the ulog data */ | ||
| 187 | pm->version = EBT_ULOG_VERSION; | ||
| 188 | kt = ktime_get_real(); | ||
| 189 | pm->stamp = ktime_to_timeval(kt); | ||
| 190 | if (ub->qlen == 1) | ||
| 191 | ub->skb->tstamp = kt; | ||
| 192 | pm->data_len = copy_len; | ||
| 193 | pm->mark = skb->mark; | ||
| 194 | pm->hook = hooknr; | ||
| 195 | if (uloginfo->prefix != NULL) | ||
| 196 | strcpy(pm->prefix, uloginfo->prefix); | ||
| 197 | |||
| 198 | if (in) { | ||
| 199 | strcpy(pm->physindev, in->name); | ||
| 200 | /* If in isn't a bridge, then physindev==indev */ | ||
| 201 | if (br_port_exists(in)) | ||
| 202 | /* rcu_read_lock()ed by nf_hook_slow */ | ||
| 203 | strcpy(pm->indev, br_port_get_rcu(in)->br->dev->name); | ||
| 204 | else | ||
| 205 | strcpy(pm->indev, in->name); | ||
| 206 | } | ||
| 207 | |||
| 208 | if (out) { | ||
| 209 | /* If out exists, then out is a bridge port */ | ||
| 210 | strcpy(pm->physoutdev, out->name); | ||
| 211 | /* rcu_read_lock()ed by nf_hook_slow */ | ||
| 212 | strcpy(pm->outdev, br_port_get_rcu(out)->br->dev->name); | ||
| 213 | } | ||
| 214 | |||
| 215 | if (skb_copy_bits(skb, -ETH_HLEN, pm->data, copy_len) < 0) | ||
| 216 | BUG(); | ||
| 217 | |||
| 218 | if (ub->qlen > 1) | ||
| 219 | ub->lastnlh->nlmsg_flags |= NLM_F_MULTI; | ||
| 220 | |||
| 221 | ub->lastnlh = nlh; | ||
| 222 | |||
| 223 | if (ub->qlen >= uloginfo->qthreshold) | ||
| 224 | ulog_send(ebt, group); | ||
| 225 | else if (!timer_pending(&ub->timer)) { | ||
| 226 | ub->timer.expires = jiffies + flushtimeout * HZ / 100; | ||
| 227 | add_timer(&ub->timer); | ||
| 228 | } | ||
| 229 | |||
| 230 | unlock: | ||
| 231 | spin_unlock_bh(lock); | ||
| 232 | } | ||
| 233 | |||
| 234 | /* this function is registered with the netfilter core */ | ||
| 235 | static void ebt_log_packet(struct net *net, u_int8_t pf, unsigned int hooknum, | ||
| 236 | const struct sk_buff *skb, const struct net_device *in, | ||
| 237 | const struct net_device *out, const struct nf_loginfo *li, | ||
| 238 | const char *prefix) | ||
| 239 | { | ||
| 240 | struct ebt_ulog_info loginfo; | ||
| 241 | |||
| 242 | if (!li || li->type != NF_LOG_TYPE_ULOG) { | ||
| 243 | loginfo.nlgroup = EBT_ULOG_DEFAULT_NLGROUP; | ||
| 244 | loginfo.cprange = 0; | ||
| 245 | loginfo.qthreshold = EBT_ULOG_DEFAULT_QTHRESHOLD; | ||
| 246 | loginfo.prefix[0] = '\0'; | ||
| 247 | } else { | ||
| 248 | loginfo.nlgroup = li->u.ulog.group; | ||
| 249 | loginfo.cprange = li->u.ulog.copy_len; | ||
| 250 | loginfo.qthreshold = li->u.ulog.qthreshold; | ||
| 251 | strlcpy(loginfo.prefix, prefix, sizeof(loginfo.prefix)); | ||
| 252 | } | ||
| 253 | |||
| 254 | ebt_ulog_packet(net, hooknum, skb, in, out, &loginfo, prefix); | ||
| 255 | } | ||
| 256 | |||
| 257 | static unsigned int | ||
| 258 | ebt_ulog_tg(struct sk_buff *skb, const struct xt_action_param *par) | ||
| 259 | { | ||
| 260 | struct net *net = dev_net(par->in ? par->in : par->out); | ||
| 261 | |||
| 262 | ebt_ulog_packet(net, par->hooknum, skb, par->in, par->out, | ||
| 263 | par->targinfo, NULL); | ||
| 264 | return EBT_CONTINUE; | ||
| 265 | } | ||
| 266 | |||
| 267 | static int ebt_ulog_tg_check(const struct xt_tgchk_param *par) | ||
| 268 | { | ||
| 269 | struct ebt_ulog_info *uloginfo = par->targinfo; | ||
| 270 | |||
| 271 | if (!par->net->xt.ebt_ulog_warn_deprecated) { | ||
| 272 | pr_info("ebt_ulog is deprecated and it will be removed soon, " | ||
| 273 | "use ebt_nflog instead\n"); | ||
| 274 | par->net->xt.ebt_ulog_warn_deprecated = true; | ||
| 275 | } | ||
| 276 | |||
| 277 | if (uloginfo->nlgroup > 31) | ||
| 278 | return -EINVAL; | ||
| 279 | |||
| 280 | uloginfo->prefix[EBT_ULOG_PREFIX_LEN - 1] = '\0'; | ||
| 281 | |||
| 282 | if (uloginfo->qthreshold > EBT_ULOG_MAX_QLEN) | ||
| 283 | uloginfo->qthreshold = EBT_ULOG_MAX_QLEN; | ||
| 284 | |||
| 285 | return 0; | ||
| 286 | } | ||
| 287 | |||
| 288 | static struct xt_target ebt_ulog_tg_reg __read_mostly = { | ||
| 289 | .name = "ulog", | ||
| 290 | .revision = 0, | ||
| 291 | .family = NFPROTO_BRIDGE, | ||
| 292 | .target = ebt_ulog_tg, | ||
| 293 | .checkentry = ebt_ulog_tg_check, | ||
| 294 | .targetsize = sizeof(struct ebt_ulog_info), | ||
| 295 | .me = THIS_MODULE, | ||
| 296 | }; | ||
| 297 | |||
| 298 | static struct nf_logger ebt_ulog_logger __read_mostly = { | ||
| 299 | .name = "ebt_ulog", | ||
| 300 | .logfn = &ebt_log_packet, | ||
| 301 | .me = THIS_MODULE, | ||
| 302 | }; | ||
| 303 | |||
| 304 | static int __net_init ebt_ulog_net_init(struct net *net) | ||
| 305 | { | ||
| 306 | int i; | ||
| 307 | struct ebt_ulog_net *ebt = ebt_ulog_pernet(net); | ||
| 308 | |||
| 309 | struct netlink_kernel_cfg cfg = { | ||
| 310 | .groups = EBT_ULOG_MAXNLGROUPS, | ||
| 311 | }; | ||
| 312 | |||
| 313 | /* initialize ulog_buffers */ | ||
| 314 | for (i = 0; i < EBT_ULOG_MAXNLGROUPS; i++) { | ||
| 315 | ebt->nlgroup[i] = i; | ||
| 316 | setup_timer(&ebt->ulog_buffers[i].timer, ulog_timer, | ||
| 317 | (unsigned long)&ebt->nlgroup[i]); | ||
| 318 | spin_lock_init(&ebt->ulog_buffers[i].lock); | ||
| 319 | } | ||
| 320 | |||
| 321 | ebt->ebtulognl = netlink_kernel_create(net, NETLINK_NFLOG, &cfg); | ||
| 322 | if (!ebt->ebtulognl) | ||
| 323 | return -ENOMEM; | ||
| 324 | |||
| 325 | nf_log_set(net, NFPROTO_BRIDGE, &ebt_ulog_logger); | ||
| 326 | return 0; | ||
| 327 | } | ||
| 328 | |||
| 329 | static void __net_exit ebt_ulog_net_fini(struct net *net) | ||
| 330 | { | ||
| 331 | int i; | ||
| 332 | struct ebt_ulog_net *ebt = ebt_ulog_pernet(net); | ||
| 333 | |||
| 334 | nf_log_unset(net, &ebt_ulog_logger); | ||
| 335 | for (i = 0; i < EBT_ULOG_MAXNLGROUPS; i++) { | ||
| 336 | ebt_ulog_buff_t *ub = &ebt->ulog_buffers[i]; | ||
| 337 | del_timer(&ub->timer); | ||
| 338 | |||
| 339 | if (ub->skb) { | ||
| 340 | kfree_skb(ub->skb); | ||
| 341 | ub->skb = NULL; | ||
| 342 | } | ||
| 343 | } | ||
| 344 | netlink_kernel_release(ebt->ebtulognl); | ||
| 345 | } | ||
| 346 | |||
| 347 | static struct pernet_operations ebt_ulog_net_ops = { | ||
| 348 | .init = ebt_ulog_net_init, | ||
| 349 | .exit = ebt_ulog_net_fini, | ||
| 350 | .id = &ebt_ulog_net_id, | ||
| 351 | .size = sizeof(struct ebt_ulog_net), | ||
| 352 | }; | ||
| 353 | |||
| 354 | static int __init ebt_ulog_init(void) | ||
| 355 | { | ||
| 356 | int ret; | ||
| 357 | |||
| 358 | if (nlbufsiz >= 128*1024) { | ||
| 359 | pr_warn("Netlink buffer has to be <= 128kB," | ||
| 360 | "please try a smaller nlbufsiz parameter.\n"); | ||
| 361 | return -EINVAL; | ||
| 362 | } | ||
| 363 | |||
| 364 | ret = register_pernet_subsys(&ebt_ulog_net_ops); | ||
| 365 | if (ret) | ||
| 366 | goto out_pernet; | ||
| 367 | |||
| 368 | ret = xt_register_target(&ebt_ulog_tg_reg); | ||
| 369 | if (ret) | ||
| 370 | goto out_target; | ||
| 371 | |||
| 372 | nf_log_register(NFPROTO_BRIDGE, &ebt_ulog_logger); | ||
| 373 | |||
| 374 | return 0; | ||
| 375 | |||
| 376 | out_target: | ||
| 377 | unregister_pernet_subsys(&ebt_ulog_net_ops); | ||
| 378 | out_pernet: | ||
| 379 | return ret; | ||
| 380 | } | ||
| 381 | |||
| 382 | static void __exit ebt_ulog_fini(void) | ||
| 383 | { | ||
| 384 | nf_log_unregister(&ebt_ulog_logger); | ||
| 385 | xt_unregister_target(&ebt_ulog_tg_reg); | ||
| 386 | unregister_pernet_subsys(&ebt_ulog_net_ops); | ||
| 387 | } | ||
| 388 | |||
| 389 | module_init(ebt_ulog_init); | ||
| 390 | module_exit(ebt_ulog_fini); | ||
| 391 | MODULE_LICENSE("GPL"); | ||
| 392 | MODULE_AUTHOR("Bart De Schuymer <bdschuym@pandora.be>"); | ||
| 393 | MODULE_DESCRIPTION("Ebtables: Packet logging to netlink using ULOG"); | ||
diff --git a/net/bridge/netfilter/ebtables.c b/net/bridge/netfilter/ebtables.c index 1059ed3bc255..6d69631b9f4d 100644 --- a/net/bridge/netfilter/ebtables.c +++ b/net/bridge/netfilter/ebtables.c | |||
| @@ -327,10 +327,7 @@ find_inlist_lock_noload(struct list_head *head, const char *name, int *error, | |||
| 327 | char name[EBT_FUNCTION_MAXNAMELEN]; | 327 | char name[EBT_FUNCTION_MAXNAMELEN]; |
| 328 | } *e; | 328 | } *e; |
| 329 | 329 | ||
| 330 | *error = mutex_lock_interruptible(mutex); | 330 | mutex_lock(mutex); |
| 331 | if (*error != 0) | ||
| 332 | return NULL; | ||
| 333 | |||
| 334 | list_for_each_entry(e, head, list) { | 331 | list_for_each_entry(e, head, list) { |
| 335 | if (strcmp(e->name, name) == 0) | 332 | if (strcmp(e->name, name) == 0) |
| 336 | return e; | 333 | return e; |
| @@ -1203,10 +1200,7 @@ ebt_register_table(struct net *net, const struct ebt_table *input_table) | |||
| 1203 | 1200 | ||
| 1204 | table->private = newinfo; | 1201 | table->private = newinfo; |
| 1205 | rwlock_init(&table->lock); | 1202 | rwlock_init(&table->lock); |
| 1206 | ret = mutex_lock_interruptible(&ebt_mutex); | 1203 | mutex_lock(&ebt_mutex); |
| 1207 | if (ret != 0) | ||
| 1208 | goto free_chainstack; | ||
| 1209 | |||
| 1210 | list_for_each_entry(t, &net->xt.tables[NFPROTO_BRIDGE], list) { | 1204 | list_for_each_entry(t, &net->xt.tables[NFPROTO_BRIDGE], list) { |
| 1211 | if (strcmp(t->name, table->name) == 0) { | 1205 | if (strcmp(t->name, table->name) == 0) { |
| 1212 | ret = -EEXIST; | 1206 | ret = -EEXIST; |
diff --git a/net/bridge/netfilter/nf_log_bridge.c b/net/bridge/netfilter/nf_log_bridge.c new file mode 100644 index 000000000000..5d9953a90929 --- /dev/null +++ b/net/bridge/netfilter/nf_log_bridge.c | |||
| @@ -0,0 +1,96 @@ | |||
| 1 | /* | ||
| 2 | * (C) 2014 by Pablo Neira Ayuso <pablo@netfilter.org> | ||
| 3 | * | ||
| 4 | * This program is free software; you can redistribute it and/or modify | ||
| 5 | * it under the terms of the GNU General Public License version 2 as | ||
| 6 | * published by the Free Software Foundation. | ||
| 7 | */ | ||
| 8 | |||
| 9 | #include <linux/module.h> | ||
| 10 | #include <linux/spinlock.h> | ||
| 11 | #include <linux/skbuff.h> | ||
| 12 | #include <linux/if_bridge.h> | ||
| 13 | #include <linux/ip.h> | ||
| 14 | #include <net/route.h> | ||
| 15 | |||
| 16 | #include <linux/netfilter.h> | ||
| 17 | #include <net/netfilter/nf_log.h> | ||
| 18 | |||
| 19 | static void nf_log_bridge_packet(struct net *net, u_int8_t pf, | ||
| 20 | unsigned int hooknum, | ||
| 21 | const struct sk_buff *skb, | ||
| 22 | const struct net_device *in, | ||
| 23 | const struct net_device *out, | ||
| 24 | const struct nf_loginfo *loginfo, | ||
| 25 | const char *prefix) | ||
| 26 | { | ||
| 27 | switch (eth_hdr(skb)->h_proto) { | ||
| 28 | case htons(ETH_P_IP): | ||
| 29 | nf_log_packet(net, NFPROTO_IPV4, hooknum, skb, in, out, | ||
| 30 | loginfo, "%s", prefix); | ||
| 31 | break; | ||
| 32 | case htons(ETH_P_IPV6): | ||
| 33 | nf_log_packet(net, NFPROTO_IPV6, hooknum, skb, in, out, | ||
| 34 | loginfo, "%s", prefix); | ||
| 35 | break; | ||
| 36 | case htons(ETH_P_ARP): | ||
| 37 | case htons(ETH_P_RARP): | ||
| 38 | nf_log_packet(net, NFPROTO_ARP, hooknum, skb, in, out, | ||
| 39 | loginfo, "%s", prefix); | ||
| 40 | break; | ||
| 41 | } | ||
| 42 | } | ||
| 43 | |||
| 44 | static struct nf_logger nf_bridge_logger __read_mostly = { | ||
| 45 | .name = "nf_log_bridge", | ||
| 46 | .type = NF_LOG_TYPE_LOG, | ||
| 47 | .logfn = nf_log_bridge_packet, | ||
| 48 | .me = THIS_MODULE, | ||
| 49 | }; | ||
| 50 | |||
| 51 | static int __net_init nf_log_bridge_net_init(struct net *net) | ||
| 52 | { | ||
| 53 | nf_log_set(net, NFPROTO_BRIDGE, &nf_bridge_logger); | ||
| 54 | return 0; | ||
| 55 | } | ||
| 56 | |||
| 57 | static void __net_exit nf_log_bridge_net_exit(struct net *net) | ||
| 58 | { | ||
| 59 | nf_log_unset(net, &nf_bridge_logger); | ||
| 60 | } | ||
| 61 | |||
| 62 | static struct pernet_operations nf_log_bridge_net_ops = { | ||
| 63 | .init = nf_log_bridge_net_init, | ||
| 64 | .exit = nf_log_bridge_net_exit, | ||
| 65 | }; | ||
| 66 | |||
| 67 | static int __init nf_log_bridge_init(void) | ||
| 68 | { | ||
| 69 | int ret; | ||
| 70 | |||
| 71 | /* Request to load the real packet loggers. */ | ||
| 72 | nf_logger_request_module(NFPROTO_IPV4, NF_LOG_TYPE_LOG); | ||
| 73 | nf_logger_request_module(NFPROTO_IPV6, NF_LOG_TYPE_LOG); | ||
| 74 | nf_logger_request_module(NFPROTO_ARP, NF_LOG_TYPE_LOG); | ||
| 75 | |||
| 76 | ret = register_pernet_subsys(&nf_log_bridge_net_ops); | ||
| 77 | if (ret < 0) | ||
| 78 | return ret; | ||
| 79 | |||
| 80 | nf_log_register(NFPROTO_BRIDGE, &nf_bridge_logger); | ||
| 81 | return 0; | ||
| 82 | } | ||
| 83 | |||
| 84 | static void __exit nf_log_bridge_exit(void) | ||
| 85 | { | ||
| 86 | unregister_pernet_subsys(&nf_log_bridge_net_ops); | ||
| 87 | nf_log_unregister(&nf_bridge_logger); | ||
| 88 | } | ||
| 89 | |||
| 90 | module_init(nf_log_bridge_init); | ||
| 91 | module_exit(nf_log_bridge_exit); | ||
| 92 | |||
| 93 | MODULE_AUTHOR("Pablo Neira Ayuso <pablo@netfilter.org>"); | ||
| 94 | MODULE_DESCRIPTION("Netfilter bridge packet logging"); | ||
| 95 | MODULE_LICENSE("GPL"); | ||
| 96 | MODULE_ALIAS_NF_LOGGER(AF_BRIDGE, 0); | ||
diff --git a/net/bridge/netfilter/nft_reject_bridge.c b/net/bridge/netfilter/nft_reject_bridge.c new file mode 100644 index 000000000000..ee3ffe93e14e --- /dev/null +++ b/net/bridge/netfilter/nft_reject_bridge.c | |||
| @@ -0,0 +1,67 @@ | |||
| 1 | /* | ||
| 2 | * Copyright (c) 2014 Pablo Neira Ayuso <pablo@netfilter.org> | ||
| 3 | * | ||
| 4 | * This program is free software; you can redistribute it and/or modify | ||
| 5 | * it under the terms of the GNU General Public License version 2 as | ||
| 6 | * published by the Free Software Foundation. | ||
| 7 | */ | ||
| 8 | |||
| 9 | #include <linux/kernel.h> | ||
| 10 | #include <linux/init.h> | ||
| 11 | #include <linux/module.h> | ||
| 12 | #include <linux/netlink.h> | ||
| 13 | #include <linux/netfilter.h> | ||
| 14 | #include <linux/netfilter/nf_tables.h> | ||
| 15 | #include <net/netfilter/nf_tables.h> | ||
| 16 | #include <net/netfilter/nft_reject.h> | ||
| 17 | |||
| 18 | static void nft_reject_bridge_eval(const struct nft_expr *expr, | ||
| 19 | struct nft_data data[NFT_REG_MAX + 1], | ||
| 20 | const struct nft_pktinfo *pkt) | ||
| 21 | { | ||
| 22 | switch (eth_hdr(pkt->skb)->h_proto) { | ||
| 23 | case htons(ETH_P_IP): | ||
| 24 | return nft_reject_ipv4_eval(expr, data, pkt); | ||
| 25 | case htons(ETH_P_IPV6): | ||
| 26 | return nft_reject_ipv6_eval(expr, data, pkt); | ||
| 27 | default: | ||
| 28 | /* No explicit way to reject this protocol, drop it. */ | ||
| 29 | data[NFT_REG_VERDICT].verdict = NF_DROP; | ||
| 30 | break; | ||
| 31 | } | ||
| 32 | } | ||
| 33 | |||
| 34 | static struct nft_expr_type nft_reject_bridge_type; | ||
| 35 | static const struct nft_expr_ops nft_reject_bridge_ops = { | ||
| 36 | .type = &nft_reject_bridge_type, | ||
| 37 | .size = NFT_EXPR_SIZE(sizeof(struct nft_reject)), | ||
| 38 | .eval = nft_reject_bridge_eval, | ||
| 39 | .init = nft_reject_init, | ||
| 40 | .dump = nft_reject_dump, | ||
| 41 | }; | ||
| 42 | |||
| 43 | static struct nft_expr_type nft_reject_bridge_type __read_mostly = { | ||
| 44 | .family = NFPROTO_BRIDGE, | ||
| 45 | .name = "reject", | ||
| 46 | .ops = &nft_reject_bridge_ops, | ||
| 47 | .policy = nft_reject_policy, | ||
| 48 | .maxattr = NFTA_REJECT_MAX, | ||
| 49 | .owner = THIS_MODULE, | ||
| 50 | }; | ||
| 51 | |||
| 52 | static int __init nft_reject_bridge_module_init(void) | ||
| 53 | { | ||
| 54 | return nft_register_expr(&nft_reject_bridge_type); | ||
| 55 | } | ||
| 56 | |||
| 57 | static void __exit nft_reject_bridge_module_exit(void) | ||
| 58 | { | ||
| 59 | nft_unregister_expr(&nft_reject_bridge_type); | ||
| 60 | } | ||
| 61 | |||
| 62 | module_init(nft_reject_bridge_module_init); | ||
| 63 | module_exit(nft_reject_bridge_module_exit); | ||
| 64 | |||
| 65 | MODULE_LICENSE("GPL"); | ||
| 66 | MODULE_AUTHOR("Pablo Neira Ayuso <pablo@netfilter.org>"); | ||
| 67 | MODULE_ALIAS_NFT_AF_EXPR(AF_BRIDGE, "reject"); | ||
diff --git a/net/caif/caif_socket.c b/net/caif/caif_socket.c index e8437094d15f..43f750e88e19 100644 --- a/net/caif/caif_socket.c +++ b/net/caif/caif_socket.c | |||
| @@ -908,8 +908,7 @@ static int caif_release(struct socket *sock) | |||
| 908 | sock->sk = NULL; | 908 | sock->sk = NULL; |
| 909 | 909 | ||
| 910 | WARN_ON(IS_ERR(cf_sk->debugfs_socket_dir)); | 910 | WARN_ON(IS_ERR(cf_sk->debugfs_socket_dir)); |
| 911 | if (cf_sk->debugfs_socket_dir != NULL) | 911 | debugfs_remove_recursive(cf_sk->debugfs_socket_dir); |
| 912 | debugfs_remove_recursive(cf_sk->debugfs_socket_dir); | ||
| 913 | 912 | ||
| 914 | lock_sock(&(cf_sk->sk)); | 913 | lock_sock(&(cf_sk->sk)); |
| 915 | sk->sk_state = CAIF_DISCONNECTED; | 914 | sk->sk_state = CAIF_DISCONNECTED; |
diff --git a/net/caif/cfctrl.c b/net/caif/cfctrl.c index 0f455227da83..f5afda1abc76 100644 --- a/net/caif/cfctrl.c +++ b/net/caif/cfctrl.c | |||
| @@ -547,7 +547,6 @@ static int cfctrl_recv(struct cflayer *layer, struct cfpkt *pkt) | |||
| 547 | default: | 547 | default: |
| 548 | pr_err("Unrecognized Control Frame\n"); | 548 | pr_err("Unrecognized Control Frame\n"); |
| 549 | goto error; | 549 | goto error; |
| 550 | break; | ||
| 551 | } | 550 | } |
| 552 | ret = 0; | 551 | ret = 0; |
| 553 | error: | 552 | error: |
diff --git a/net/ceph/crypto.c b/net/ceph/crypto.c index 6e7a236525b6..ffeba8f9dda9 100644 --- a/net/ceph/crypto.c +++ b/net/ceph/crypto.c | |||
| @@ -8,6 +8,7 @@ | |||
| 8 | #include <linux/key-type.h> | 8 | #include <linux/key-type.h> |
| 9 | 9 | ||
| 10 | #include <keys/ceph-type.h> | 10 | #include <keys/ceph-type.h> |
| 11 | #include <keys/user-type.h> | ||
| 11 | #include <linux/ceph/decode.h> | 12 | #include <linux/ceph/decode.h> |
| 12 | #include "crypto.h" | 13 | #include "crypto.h" |
| 13 | 14 | ||
| @@ -423,8 +424,7 @@ int ceph_encrypt2(struct ceph_crypto_key *secret, void *dst, size_t *dst_len, | |||
| 423 | } | 424 | } |
| 424 | } | 425 | } |
| 425 | 426 | ||
| 426 | static int ceph_key_instantiate(struct key *key, | 427 | static int ceph_key_preparse(struct key_preparsed_payload *prep) |
| 427 | struct key_preparsed_payload *prep) | ||
| 428 | { | 428 | { |
| 429 | struct ceph_crypto_key *ckey; | 429 | struct ceph_crypto_key *ckey; |
| 430 | size_t datalen = prep->datalen; | 430 | size_t datalen = prep->datalen; |
| @@ -435,10 +435,6 @@ static int ceph_key_instantiate(struct key *key, | |||
| 435 | if (datalen <= 0 || datalen > 32767 || !prep->data) | 435 | if (datalen <= 0 || datalen > 32767 || !prep->data) |
| 436 | goto err; | 436 | goto err; |
| 437 | 437 | ||
| 438 | ret = key_payload_reserve(key, datalen); | ||
| 439 | if (ret < 0) | ||
| 440 | goto err; | ||
| 441 | |||
| 442 | ret = -ENOMEM; | 438 | ret = -ENOMEM; |
| 443 | ckey = kmalloc(sizeof(*ckey), GFP_KERNEL); | 439 | ckey = kmalloc(sizeof(*ckey), GFP_KERNEL); |
| 444 | if (!ckey) | 440 | if (!ckey) |
| @@ -450,7 +446,8 @@ static int ceph_key_instantiate(struct key *key, | |||
| 450 | if (ret < 0) | 446 | if (ret < 0) |
| 451 | goto err_ckey; | 447 | goto err_ckey; |
| 452 | 448 | ||
| 453 | key->payload.data = ckey; | 449 | prep->payload[0] = ckey; |
| 450 | prep->quotalen = datalen; | ||
| 454 | return 0; | 451 | return 0; |
| 455 | 452 | ||
| 456 | err_ckey: | 453 | err_ckey: |
| @@ -459,12 +456,15 @@ err: | |||
| 459 | return ret; | 456 | return ret; |
| 460 | } | 457 | } |
| 461 | 458 | ||
| 462 | static int ceph_key_match(const struct key *key, const void *description) | 459 | static void ceph_key_free_preparse(struct key_preparsed_payload *prep) |
| 463 | { | 460 | { |
| 464 | return strcmp(key->description, description) == 0; | 461 | struct ceph_crypto_key *ckey = prep->payload[0]; |
| 462 | ceph_crypto_key_destroy(ckey); | ||
| 463 | kfree(ckey); | ||
| 465 | } | 464 | } |
| 466 | 465 | ||
| 467 | static void ceph_key_destroy(struct key *key) { | 466 | static void ceph_key_destroy(struct key *key) |
| 467 | { | ||
| 468 | struct ceph_crypto_key *ckey = key->payload.data; | 468 | struct ceph_crypto_key *ckey = key->payload.data; |
| 469 | 469 | ||
| 470 | ceph_crypto_key_destroy(ckey); | 470 | ceph_crypto_key_destroy(ckey); |
| @@ -473,8 +473,10 @@ static void ceph_key_destroy(struct key *key) { | |||
| 473 | 473 | ||
| 474 | struct key_type key_type_ceph = { | 474 | struct key_type key_type_ceph = { |
| 475 | .name = "ceph", | 475 | .name = "ceph", |
| 476 | .instantiate = ceph_key_instantiate, | 476 | .preparse = ceph_key_preparse, |
| 477 | .match = ceph_key_match, | 477 | .free_preparse = ceph_key_free_preparse, |
| 478 | .instantiate = generic_key_instantiate, | ||
| 479 | .match = user_match, | ||
| 478 | .destroy = ceph_key_destroy, | 480 | .destroy = ceph_key_destroy, |
| 479 | }; | 481 | }; |
| 480 | 482 | ||
diff --git a/net/ceph/messenger.c b/net/ceph/messenger.c index 1948d592aa54..b2f571dd933d 100644 --- a/net/ceph/messenger.c +++ b/net/ceph/messenger.c | |||
| @@ -174,6 +174,7 @@ static struct lock_class_key socket_class; | |||
| 174 | #define SKIP_BUF_SIZE 1024 | 174 | #define SKIP_BUF_SIZE 1024 |
| 175 | 175 | ||
| 176 | static void queue_con(struct ceph_connection *con); | 176 | static void queue_con(struct ceph_connection *con); |
| 177 | static void cancel_con(struct ceph_connection *con); | ||
| 177 | static void con_work(struct work_struct *); | 178 | static void con_work(struct work_struct *); |
| 178 | static void con_fault(struct ceph_connection *con); | 179 | static void con_fault(struct ceph_connection *con); |
| 179 | 180 | ||
| @@ -680,7 +681,7 @@ void ceph_con_close(struct ceph_connection *con) | |||
| 680 | 681 | ||
| 681 | reset_connection(con); | 682 | reset_connection(con); |
| 682 | con->peer_global_seq = 0; | 683 | con->peer_global_seq = 0; |
| 683 | cancel_delayed_work(&con->work); | 684 | cancel_con(con); |
| 684 | con_close_socket(con); | 685 | con_close_socket(con); |
| 685 | mutex_unlock(&con->mutex); | 686 | mutex_unlock(&con->mutex); |
| 686 | } | 687 | } |
| @@ -900,7 +901,7 @@ static void ceph_msg_data_pages_cursor_init(struct ceph_msg_data_cursor *cursor, | |||
| 900 | BUG_ON(page_count > (int)USHRT_MAX); | 901 | BUG_ON(page_count > (int)USHRT_MAX); |
| 901 | cursor->page_count = (unsigned short)page_count; | 902 | cursor->page_count = (unsigned short)page_count; |
| 902 | BUG_ON(length > SIZE_MAX - cursor->page_offset); | 903 | BUG_ON(length > SIZE_MAX - cursor->page_offset); |
| 903 | cursor->last_piece = (size_t)cursor->page_offset + length <= PAGE_SIZE; | 904 | cursor->last_piece = cursor->page_offset + cursor->resid <= PAGE_SIZE; |
| 904 | } | 905 | } |
| 905 | 906 | ||
| 906 | static struct page * | 907 | static struct page * |
| @@ -2667,19 +2668,16 @@ static int queue_con_delay(struct ceph_connection *con, unsigned long delay) | |||
| 2667 | { | 2668 | { |
| 2668 | if (!con->ops->get(con)) { | 2669 | if (!con->ops->get(con)) { |
| 2669 | dout("%s %p ref count 0\n", __func__, con); | 2670 | dout("%s %p ref count 0\n", __func__, con); |
| 2670 | |||
| 2671 | return -ENOENT; | 2671 | return -ENOENT; |
| 2672 | } | 2672 | } |
| 2673 | 2673 | ||
| 2674 | if (!queue_delayed_work(ceph_msgr_wq, &con->work, delay)) { | 2674 | if (!queue_delayed_work(ceph_msgr_wq, &con->work, delay)) { |
| 2675 | dout("%s %p - already queued\n", __func__, con); | 2675 | dout("%s %p - already queued\n", __func__, con); |
| 2676 | con->ops->put(con); | 2676 | con->ops->put(con); |
| 2677 | |||
| 2678 | return -EBUSY; | 2677 | return -EBUSY; |
| 2679 | } | 2678 | } |
| 2680 | 2679 | ||
| 2681 | dout("%s %p %lu\n", __func__, con, delay); | 2680 | dout("%s %p %lu\n", __func__, con, delay); |
| 2682 | |||
| 2683 | return 0; | 2681 | return 0; |
| 2684 | } | 2682 | } |
| 2685 | 2683 | ||
| @@ -2688,6 +2686,14 @@ static void queue_con(struct ceph_connection *con) | |||
| 2688 | (void) queue_con_delay(con, 0); | 2686 | (void) queue_con_delay(con, 0); |
| 2689 | } | 2687 | } |
| 2690 | 2688 | ||
| 2689 | static void cancel_con(struct ceph_connection *con) | ||
| 2690 | { | ||
| 2691 | if (cancel_delayed_work(&con->work)) { | ||
| 2692 | dout("%s %p\n", __func__, con); | ||
| 2693 | con->ops->put(con); | ||
| 2694 | } | ||
| 2695 | } | ||
| 2696 | |||
| 2691 | static bool con_sock_closed(struct ceph_connection *con) | 2697 | static bool con_sock_closed(struct ceph_connection *con) |
| 2692 | { | 2698 | { |
| 2693 | if (!con_flag_test_and_clear(con, CON_FLAG_SOCK_CLOSED)) | 2699 | if (!con_flag_test_and_clear(con, CON_FLAG_SOCK_CLOSED)) |
| @@ -3269,24 +3275,21 @@ static int ceph_con_in_msg_alloc(struct ceph_connection *con, int *skip) | |||
| 3269 | /* | 3275 | /* |
| 3270 | * Free a generically kmalloc'd message. | 3276 | * Free a generically kmalloc'd message. |
| 3271 | */ | 3277 | */ |
| 3272 | void ceph_msg_kfree(struct ceph_msg *m) | 3278 | static void ceph_msg_free(struct ceph_msg *m) |
| 3273 | { | 3279 | { |
| 3274 | dout("msg_kfree %p\n", m); | 3280 | dout("%s %p\n", __func__, m); |
| 3275 | ceph_kvfree(m->front.iov_base); | 3281 | ceph_kvfree(m->front.iov_base); |
| 3276 | kmem_cache_free(ceph_msg_cache, m); | 3282 | kmem_cache_free(ceph_msg_cache, m); |
| 3277 | } | 3283 | } |
| 3278 | 3284 | ||
| 3279 | /* | 3285 | static void ceph_msg_release(struct kref *kref) |
| 3280 | * Drop a msg ref. Destroy as needed. | ||
| 3281 | */ | ||
| 3282 | void ceph_msg_last_put(struct kref *kref) | ||
| 3283 | { | 3286 | { |
| 3284 | struct ceph_msg *m = container_of(kref, struct ceph_msg, kref); | 3287 | struct ceph_msg *m = container_of(kref, struct ceph_msg, kref); |
| 3285 | LIST_HEAD(data); | 3288 | LIST_HEAD(data); |
| 3286 | struct list_head *links; | 3289 | struct list_head *links; |
| 3287 | struct list_head *next; | 3290 | struct list_head *next; |
| 3288 | 3291 | ||
| 3289 | dout("ceph_msg_put last one on %p\n", m); | 3292 | dout("%s %p\n", __func__, m); |
| 3290 | WARN_ON(!list_empty(&m->list_head)); | 3293 | WARN_ON(!list_empty(&m->list_head)); |
| 3291 | 3294 | ||
| 3292 | /* drop middle, data, if any */ | 3295 | /* drop middle, data, if any */ |
| @@ -3308,9 +3311,25 @@ void ceph_msg_last_put(struct kref *kref) | |||
| 3308 | if (m->pool) | 3311 | if (m->pool) |
| 3309 | ceph_msgpool_put(m->pool, m); | 3312 | ceph_msgpool_put(m->pool, m); |
| 3310 | else | 3313 | else |
| 3311 | ceph_msg_kfree(m); | 3314 | ceph_msg_free(m); |
| 3315 | } | ||
| 3316 | |||
| 3317 | struct ceph_msg *ceph_msg_get(struct ceph_msg *msg) | ||
| 3318 | { | ||
| 3319 | dout("%s %p (was %d)\n", __func__, msg, | ||
| 3320 | atomic_read(&msg->kref.refcount)); | ||
| 3321 | kref_get(&msg->kref); | ||
| 3322 | return msg; | ||
| 3323 | } | ||
| 3324 | EXPORT_SYMBOL(ceph_msg_get); | ||
| 3325 | |||
| 3326 | void ceph_msg_put(struct ceph_msg *msg) | ||
| 3327 | { | ||
| 3328 | dout("%s %p (was %d)\n", __func__, msg, | ||
| 3329 | atomic_read(&msg->kref.refcount)); | ||
| 3330 | kref_put(&msg->kref, ceph_msg_release); | ||
| 3312 | } | 3331 | } |
| 3313 | EXPORT_SYMBOL(ceph_msg_last_put); | 3332 | EXPORT_SYMBOL(ceph_msg_put); |
| 3314 | 3333 | ||
| 3315 | void ceph_msg_dump(struct ceph_msg *msg) | 3334 | void ceph_msg_dump(struct ceph_msg *msg) |
| 3316 | { | 3335 | { |
diff --git a/net/ceph/osd_client.c b/net/ceph/osd_client.c index 05be0c181695..30f6faf3584f 100644 --- a/net/ceph/osd_client.c +++ b/net/ceph/osd_client.c | |||
| @@ -297,12 +297,21 @@ static void osd_req_op_data_release(struct ceph_osd_request *osd_req, | |||
| 297 | /* | 297 | /* |
| 298 | * requests | 298 | * requests |
| 299 | */ | 299 | */ |
| 300 | void ceph_osdc_release_request(struct kref *kref) | 300 | static void ceph_osdc_release_request(struct kref *kref) |
| 301 | { | 301 | { |
| 302 | struct ceph_osd_request *req; | 302 | struct ceph_osd_request *req = container_of(kref, |
| 303 | struct ceph_osd_request, r_kref); | ||
| 303 | unsigned int which; | 304 | unsigned int which; |
| 304 | 305 | ||
| 305 | req = container_of(kref, struct ceph_osd_request, r_kref); | 306 | dout("%s %p (r_request %p r_reply %p)\n", __func__, req, |
| 307 | req->r_request, req->r_reply); | ||
| 308 | WARN_ON(!RB_EMPTY_NODE(&req->r_node)); | ||
| 309 | WARN_ON(!list_empty(&req->r_req_lru_item)); | ||
| 310 | WARN_ON(!list_empty(&req->r_osd_item)); | ||
| 311 | WARN_ON(!list_empty(&req->r_linger_item)); | ||
| 312 | WARN_ON(!list_empty(&req->r_linger_osd_item)); | ||
| 313 | WARN_ON(req->r_osd); | ||
| 314 | |||
| 306 | if (req->r_request) | 315 | if (req->r_request) |
| 307 | ceph_msg_put(req->r_request); | 316 | ceph_msg_put(req->r_request); |
| 308 | if (req->r_reply) { | 317 | if (req->r_reply) { |
| @@ -320,7 +329,22 @@ void ceph_osdc_release_request(struct kref *kref) | |||
| 320 | kmem_cache_free(ceph_osd_request_cache, req); | 329 | kmem_cache_free(ceph_osd_request_cache, req); |
| 321 | 330 | ||
| 322 | } | 331 | } |
| 323 | EXPORT_SYMBOL(ceph_osdc_release_request); | 332 | |
| 333 | void ceph_osdc_get_request(struct ceph_osd_request *req) | ||
| 334 | { | ||
| 335 | dout("%s %p (was %d)\n", __func__, req, | ||
| 336 | atomic_read(&req->r_kref.refcount)); | ||
| 337 | kref_get(&req->r_kref); | ||
| 338 | } | ||
| 339 | EXPORT_SYMBOL(ceph_osdc_get_request); | ||
| 340 | |||
| 341 | void ceph_osdc_put_request(struct ceph_osd_request *req) | ||
| 342 | { | ||
| 343 | dout("%s %p (was %d)\n", __func__, req, | ||
| 344 | atomic_read(&req->r_kref.refcount)); | ||
| 345 | kref_put(&req->r_kref, ceph_osdc_release_request); | ||
| 346 | } | ||
| 347 | EXPORT_SYMBOL(ceph_osdc_put_request); | ||
| 324 | 348 | ||
| 325 | struct ceph_osd_request *ceph_osdc_alloc_request(struct ceph_osd_client *osdc, | 349 | struct ceph_osd_request *ceph_osdc_alloc_request(struct ceph_osd_client *osdc, |
| 326 | struct ceph_snap_context *snapc, | 350 | struct ceph_snap_context *snapc, |
| @@ -364,7 +388,7 @@ struct ceph_osd_request *ceph_osdc_alloc_request(struct ceph_osd_client *osdc, | |||
| 364 | RB_CLEAR_NODE(&req->r_node); | 388 | RB_CLEAR_NODE(&req->r_node); |
| 365 | INIT_LIST_HEAD(&req->r_unsafe_item); | 389 | INIT_LIST_HEAD(&req->r_unsafe_item); |
| 366 | INIT_LIST_HEAD(&req->r_linger_item); | 390 | INIT_LIST_HEAD(&req->r_linger_item); |
| 367 | INIT_LIST_HEAD(&req->r_linger_osd); | 391 | INIT_LIST_HEAD(&req->r_linger_osd_item); |
| 368 | INIT_LIST_HEAD(&req->r_req_lru_item); | 392 | INIT_LIST_HEAD(&req->r_req_lru_item); |
| 369 | INIT_LIST_HEAD(&req->r_osd_item); | 393 | INIT_LIST_HEAD(&req->r_osd_item); |
| 370 | 394 | ||
| @@ -916,7 +940,7 @@ static void __kick_osd_requests(struct ceph_osd_client *osdc, | |||
| 916 | * list at the end to keep things in tid order. | 940 | * list at the end to keep things in tid order. |
| 917 | */ | 941 | */ |
| 918 | list_for_each_entry_safe(req, nreq, &osd->o_linger_requests, | 942 | list_for_each_entry_safe(req, nreq, &osd->o_linger_requests, |
| 919 | r_linger_osd) { | 943 | r_linger_osd_item) { |
| 920 | /* | 944 | /* |
| 921 | * reregister request prior to unregistering linger so | 945 | * reregister request prior to unregistering linger so |
| 922 | * that r_osd is preserved. | 946 | * that r_osd is preserved. |
| @@ -1008,6 +1032,8 @@ static void __remove_osd(struct ceph_osd_client *osdc, struct ceph_osd *osd) | |||
| 1008 | { | 1032 | { |
| 1009 | dout("__remove_osd %p\n", osd); | 1033 | dout("__remove_osd %p\n", osd); |
| 1010 | BUG_ON(!list_empty(&osd->o_requests)); | 1034 | BUG_ON(!list_empty(&osd->o_requests)); |
| 1035 | BUG_ON(!list_empty(&osd->o_linger_requests)); | ||
| 1036 | |||
| 1011 | rb_erase(&osd->o_node, &osdc->osds); | 1037 | rb_erase(&osd->o_node, &osdc->osds); |
| 1012 | list_del_init(&osd->o_osd_lru); | 1038 | list_del_init(&osd->o_osd_lru); |
| 1013 | ceph_con_close(&osd->o_con); | 1039 | ceph_con_close(&osd->o_con); |
| @@ -1029,12 +1055,23 @@ static void remove_all_osds(struct ceph_osd_client *osdc) | |||
| 1029 | static void __move_osd_to_lru(struct ceph_osd_client *osdc, | 1055 | static void __move_osd_to_lru(struct ceph_osd_client *osdc, |
| 1030 | struct ceph_osd *osd) | 1056 | struct ceph_osd *osd) |
| 1031 | { | 1057 | { |
| 1032 | dout("__move_osd_to_lru %p\n", osd); | 1058 | dout("%s %p\n", __func__, osd); |
| 1033 | BUG_ON(!list_empty(&osd->o_osd_lru)); | 1059 | BUG_ON(!list_empty(&osd->o_osd_lru)); |
| 1060 | |||
| 1034 | list_add_tail(&osd->o_osd_lru, &osdc->osd_lru); | 1061 | list_add_tail(&osd->o_osd_lru, &osdc->osd_lru); |
| 1035 | osd->lru_ttl = jiffies + osdc->client->options->osd_idle_ttl * HZ; | 1062 | osd->lru_ttl = jiffies + osdc->client->options->osd_idle_ttl * HZ; |
| 1036 | } | 1063 | } |
| 1037 | 1064 | ||
| 1065 | static void maybe_move_osd_to_lru(struct ceph_osd_client *osdc, | ||
| 1066 | struct ceph_osd *osd) | ||
| 1067 | { | ||
| 1068 | dout("%s %p\n", __func__, osd); | ||
| 1069 | |||
| 1070 | if (list_empty(&osd->o_requests) && | ||
| 1071 | list_empty(&osd->o_linger_requests)) | ||
| 1072 | __move_osd_to_lru(osdc, osd); | ||
| 1073 | } | ||
| 1074 | |||
| 1038 | static void __remove_osd_from_lru(struct ceph_osd *osd) | 1075 | static void __remove_osd_from_lru(struct ceph_osd *osd) |
| 1039 | { | 1076 | { |
| 1040 | dout("__remove_osd_from_lru %p\n", osd); | 1077 | dout("__remove_osd_from_lru %p\n", osd); |
| @@ -1175,6 +1212,7 @@ static void __unregister_request(struct ceph_osd_client *osdc, | |||
| 1175 | 1212 | ||
| 1176 | dout("__unregister_request %p tid %lld\n", req, req->r_tid); | 1213 | dout("__unregister_request %p tid %lld\n", req, req->r_tid); |
| 1177 | rb_erase(&req->r_node, &osdc->requests); | 1214 | rb_erase(&req->r_node, &osdc->requests); |
| 1215 | RB_CLEAR_NODE(&req->r_node); | ||
| 1178 | osdc->num_requests--; | 1216 | osdc->num_requests--; |
| 1179 | 1217 | ||
| 1180 | if (req->r_osd) { | 1218 | if (req->r_osd) { |
| @@ -1182,12 +1220,8 @@ static void __unregister_request(struct ceph_osd_client *osdc, | |||
| 1182 | ceph_msg_revoke(req->r_request); | 1220 | ceph_msg_revoke(req->r_request); |
| 1183 | 1221 | ||
| 1184 | list_del_init(&req->r_osd_item); | 1222 | list_del_init(&req->r_osd_item); |
| 1185 | if (list_empty(&req->r_osd->o_requests) && | 1223 | maybe_move_osd_to_lru(osdc, req->r_osd); |
| 1186 | list_empty(&req->r_osd->o_linger_requests)) { | 1224 | if (list_empty(&req->r_linger_osd_item)) |
| 1187 | dout("moving osd to %p lru\n", req->r_osd); | ||
| 1188 | __move_osd_to_lru(osdc, req->r_osd); | ||
| 1189 | } | ||
| 1190 | if (list_empty(&req->r_linger_item)) | ||
| 1191 | req->r_osd = NULL; | 1225 | req->r_osd = NULL; |
| 1192 | } | 1226 | } |
| 1193 | 1227 | ||
| @@ -1214,45 +1248,39 @@ static void __cancel_request(struct ceph_osd_request *req) | |||
| 1214 | static void __register_linger_request(struct ceph_osd_client *osdc, | 1248 | static void __register_linger_request(struct ceph_osd_client *osdc, |
| 1215 | struct ceph_osd_request *req) | 1249 | struct ceph_osd_request *req) |
| 1216 | { | 1250 | { |
| 1217 | dout("__register_linger_request %p\n", req); | 1251 | dout("%s %p tid %llu\n", __func__, req, req->r_tid); |
| 1252 | WARN_ON(!req->r_linger); | ||
| 1253 | |||
| 1218 | ceph_osdc_get_request(req); | 1254 | ceph_osdc_get_request(req); |
| 1219 | list_add_tail(&req->r_linger_item, &osdc->req_linger); | 1255 | list_add_tail(&req->r_linger_item, &osdc->req_linger); |
| 1220 | if (req->r_osd) | 1256 | if (req->r_osd) |
| 1221 | list_add_tail(&req->r_linger_osd, | 1257 | list_add_tail(&req->r_linger_osd_item, |
| 1222 | &req->r_osd->o_linger_requests); | 1258 | &req->r_osd->o_linger_requests); |
| 1223 | } | 1259 | } |
| 1224 | 1260 | ||
| 1225 | static void __unregister_linger_request(struct ceph_osd_client *osdc, | 1261 | static void __unregister_linger_request(struct ceph_osd_client *osdc, |
| 1226 | struct ceph_osd_request *req) | 1262 | struct ceph_osd_request *req) |
| 1227 | { | 1263 | { |
| 1228 | dout("__unregister_linger_request %p\n", req); | 1264 | WARN_ON(!req->r_linger); |
| 1265 | |||
| 1266 | if (list_empty(&req->r_linger_item)) { | ||
| 1267 | dout("%s %p tid %llu not registered\n", __func__, req, | ||
| 1268 | req->r_tid); | ||
| 1269 | return; | ||
| 1270 | } | ||
| 1271 | |||
| 1272 | dout("%s %p tid %llu\n", __func__, req, req->r_tid); | ||
| 1229 | list_del_init(&req->r_linger_item); | 1273 | list_del_init(&req->r_linger_item); |
| 1230 | if (req->r_osd) { | ||
| 1231 | list_del_init(&req->r_linger_osd); | ||
| 1232 | 1274 | ||
| 1233 | if (list_empty(&req->r_osd->o_requests) && | 1275 | if (req->r_osd) { |
| 1234 | list_empty(&req->r_osd->o_linger_requests)) { | 1276 | list_del_init(&req->r_linger_osd_item); |
| 1235 | dout("moving osd to %p lru\n", req->r_osd); | 1277 | maybe_move_osd_to_lru(osdc, req->r_osd); |
| 1236 | __move_osd_to_lru(osdc, req->r_osd); | ||
| 1237 | } | ||
| 1238 | if (list_empty(&req->r_osd_item)) | 1278 | if (list_empty(&req->r_osd_item)) |
| 1239 | req->r_osd = NULL; | 1279 | req->r_osd = NULL; |
| 1240 | } | 1280 | } |
| 1241 | ceph_osdc_put_request(req); | 1281 | ceph_osdc_put_request(req); |
| 1242 | } | 1282 | } |
| 1243 | 1283 | ||
| 1244 | void ceph_osdc_unregister_linger_request(struct ceph_osd_client *osdc, | ||
| 1245 | struct ceph_osd_request *req) | ||
| 1246 | { | ||
| 1247 | mutex_lock(&osdc->request_mutex); | ||
| 1248 | if (req->r_linger) { | ||
| 1249 | req->r_linger = 0; | ||
| 1250 | __unregister_linger_request(osdc, req); | ||
| 1251 | } | ||
| 1252 | mutex_unlock(&osdc->request_mutex); | ||
| 1253 | } | ||
| 1254 | EXPORT_SYMBOL(ceph_osdc_unregister_linger_request); | ||
| 1255 | |||
| 1256 | void ceph_osdc_set_request_linger(struct ceph_osd_client *osdc, | 1284 | void ceph_osdc_set_request_linger(struct ceph_osd_client *osdc, |
| 1257 | struct ceph_osd_request *req) | 1285 | struct ceph_osd_request *req) |
| 1258 | { | 1286 | { |
| @@ -2430,6 +2458,25 @@ int ceph_osdc_start_request(struct ceph_osd_client *osdc, | |||
| 2430 | EXPORT_SYMBOL(ceph_osdc_start_request); | 2458 | EXPORT_SYMBOL(ceph_osdc_start_request); |
| 2431 | 2459 | ||
| 2432 | /* | 2460 | /* |
| 2461 | * Unregister a registered request. The request is not completed (i.e. | ||
| 2462 | * no callbacks or wakeups) - higher layers are supposed to know what | ||
| 2463 | * they are canceling. | ||
| 2464 | */ | ||
| 2465 | void ceph_osdc_cancel_request(struct ceph_osd_request *req) | ||
| 2466 | { | ||
| 2467 | struct ceph_osd_client *osdc = req->r_osdc; | ||
| 2468 | |||
| 2469 | mutex_lock(&osdc->request_mutex); | ||
| 2470 | if (req->r_linger) | ||
| 2471 | __unregister_linger_request(osdc, req); | ||
| 2472 | __unregister_request(osdc, req); | ||
| 2473 | mutex_unlock(&osdc->request_mutex); | ||
| 2474 | |||
| 2475 | dout("%s %p tid %llu canceled\n", __func__, req, req->r_tid); | ||
| 2476 | } | ||
| 2477 | EXPORT_SYMBOL(ceph_osdc_cancel_request); | ||
| 2478 | |||
| 2479 | /* | ||
| 2433 | * wait for a request to complete | 2480 | * wait for a request to complete |
| 2434 | */ | 2481 | */ |
| 2435 | int ceph_osdc_wait_request(struct ceph_osd_client *osdc, | 2482 | int ceph_osdc_wait_request(struct ceph_osd_client *osdc, |
| @@ -2437,18 +2484,18 @@ int ceph_osdc_wait_request(struct ceph_osd_client *osdc, | |||
| 2437 | { | 2484 | { |
| 2438 | int rc; | 2485 | int rc; |
| 2439 | 2486 | ||
| 2487 | dout("%s %p tid %llu\n", __func__, req, req->r_tid); | ||
| 2488 | |||
| 2440 | rc = wait_for_completion_interruptible(&req->r_completion); | 2489 | rc = wait_for_completion_interruptible(&req->r_completion); |
| 2441 | if (rc < 0) { | 2490 | if (rc < 0) { |
| 2442 | mutex_lock(&osdc->request_mutex); | 2491 | dout("%s %p tid %llu interrupted\n", __func__, req, req->r_tid); |
| 2443 | __cancel_request(req); | 2492 | ceph_osdc_cancel_request(req); |
| 2444 | __unregister_request(osdc, req); | ||
| 2445 | mutex_unlock(&osdc->request_mutex); | ||
| 2446 | complete_request(req); | 2493 | complete_request(req); |
| 2447 | dout("wait_request tid %llu canceled/timed out\n", req->r_tid); | ||
| 2448 | return rc; | 2494 | return rc; |
| 2449 | } | 2495 | } |
| 2450 | 2496 | ||
| 2451 | dout("wait_request tid %llu result %d\n", req->r_tid, req->r_result); | 2497 | dout("%s %p tid %llu result %d\n", __func__, req, req->r_tid, |
| 2498 | req->r_result); | ||
| 2452 | return req->r_result; | 2499 | return req->r_result; |
| 2453 | } | 2500 | } |
| 2454 | EXPORT_SYMBOL(ceph_osdc_wait_request); | 2501 | EXPORT_SYMBOL(ceph_osdc_wait_request); |
diff --git a/net/core/dev.c b/net/core/dev.c index 367a586d0c8a..b65a5051361f 100644 --- a/net/core/dev.c +++ b/net/core/dev.c | |||
| @@ -132,6 +132,7 @@ | |||
| 132 | #include <linux/hashtable.h> | 132 | #include <linux/hashtable.h> |
| 133 | #include <linux/vmalloc.h> | 133 | #include <linux/vmalloc.h> |
| 134 | #include <linux/if_macvlan.h> | 134 | #include <linux/if_macvlan.h> |
| 135 | #include <linux/errqueue.h> | ||
| 135 | 136 | ||
| 136 | #include "net-sysfs.h" | 137 | #include "net-sysfs.h" |
| 137 | 138 | ||
| @@ -1085,6 +1086,7 @@ static int dev_get_valid_name(struct net *net, | |||
| 1085 | */ | 1086 | */ |
| 1086 | int dev_change_name(struct net_device *dev, const char *newname) | 1087 | int dev_change_name(struct net_device *dev, const char *newname) |
| 1087 | { | 1088 | { |
| 1089 | unsigned char old_assign_type; | ||
| 1088 | char oldname[IFNAMSIZ]; | 1090 | char oldname[IFNAMSIZ]; |
| 1089 | int err = 0; | 1091 | int err = 0; |
| 1090 | int ret; | 1092 | int ret; |
| @@ -1112,10 +1114,17 @@ int dev_change_name(struct net_device *dev, const char *newname) | |||
| 1112 | return err; | 1114 | return err; |
| 1113 | } | 1115 | } |
| 1114 | 1116 | ||
| 1117 | if (oldname[0] && !strchr(oldname, '%')) | ||
| 1118 | netdev_info(dev, "renamed from %s\n", oldname); | ||
| 1119 | |||
| 1120 | old_assign_type = dev->name_assign_type; | ||
| 1121 | dev->name_assign_type = NET_NAME_RENAMED; | ||
| 1122 | |||
| 1115 | rollback: | 1123 | rollback: |
| 1116 | ret = device_rename(&dev->dev, dev->name); | 1124 | ret = device_rename(&dev->dev, dev->name); |
| 1117 | if (ret) { | 1125 | if (ret) { |
| 1118 | memcpy(dev->name, oldname, IFNAMSIZ); | 1126 | memcpy(dev->name, oldname, IFNAMSIZ); |
| 1127 | dev->name_assign_type = old_assign_type; | ||
| 1119 | write_seqcount_end(&devnet_rename_seq); | 1128 | write_seqcount_end(&devnet_rename_seq); |
| 1120 | return ret; | 1129 | return ret; |
| 1121 | } | 1130 | } |
| @@ -1144,6 +1153,8 @@ rollback: | |||
| 1144 | write_seqcount_begin(&devnet_rename_seq); | 1153 | write_seqcount_begin(&devnet_rename_seq); |
| 1145 | memcpy(dev->name, oldname, IFNAMSIZ); | 1154 | memcpy(dev->name, oldname, IFNAMSIZ); |
| 1146 | memcpy(oldname, newname, IFNAMSIZ); | 1155 | memcpy(oldname, newname, IFNAMSIZ); |
| 1156 | dev->name_assign_type = old_assign_type; | ||
| 1157 | old_assign_type = NET_NAME_RENAMED; | ||
| 1147 | goto rollback; | 1158 | goto rollback; |
| 1148 | } else { | 1159 | } else { |
| 1149 | pr_err("%s: name change rollback failed: %d\n", | 1160 | pr_err("%s: name change rollback failed: %d\n", |
| @@ -2316,7 +2327,7 @@ __be16 skb_network_protocol(struct sk_buff *skb, int *depth) | |||
| 2316 | */ | 2327 | */ |
| 2317 | if (type == htons(ETH_P_8021Q) || type == htons(ETH_P_8021AD)) { | 2328 | if (type == htons(ETH_P_8021Q) || type == htons(ETH_P_8021AD)) { |
| 2318 | if (vlan_depth) { | 2329 | if (vlan_depth) { |
| 2319 | if (unlikely(WARN_ON(vlan_depth < VLAN_HLEN))) | 2330 | if (WARN_ON(vlan_depth < VLAN_HLEN)) |
| 2320 | return 0; | 2331 | return 0; |
| 2321 | vlan_depth -= VLAN_HLEN; | 2332 | vlan_depth -= VLAN_HLEN; |
| 2322 | } else { | 2333 | } else { |
| @@ -2414,8 +2425,8 @@ struct sk_buff *__skb_gso_segment(struct sk_buff *skb, | |||
| 2414 | 2425 | ||
| 2415 | skb_warn_bad_offload(skb); | 2426 | skb_warn_bad_offload(skb); |
| 2416 | 2427 | ||
| 2417 | if (skb_header_cloned(skb) && | 2428 | err = skb_cow_head(skb, 0); |
| 2418 | (err = pskb_expand_head(skb, 0, 0, GFP_ATOMIC))) | 2429 | if (err < 0) |
| 2419 | return ERR_PTR(err); | 2430 | return ERR_PTR(err); |
| 2420 | } | 2431 | } |
| 2421 | 2432 | ||
| @@ -2745,8 +2756,8 @@ static inline int __dev_xmit_skb(struct sk_buff *skb, struct Qdisc *q, | |||
| 2745 | /* | 2756 | /* |
| 2746 | * Heuristic to force contended enqueues to serialize on a | 2757 | * Heuristic to force contended enqueues to serialize on a |
| 2747 | * separate lock before trying to get qdisc main lock. | 2758 | * separate lock before trying to get qdisc main lock. |
| 2748 | * This permits __QDISC_STATE_RUNNING owner to get the lock more often | 2759 | * This permits __QDISC___STATE_RUNNING owner to get the lock more |
| 2749 | * and dequeue packets faster. | 2760 | * often and dequeue packets faster. |
| 2750 | */ | 2761 | */ |
| 2751 | contended = qdisc_is_running(q); | 2762 | contended = qdisc_is_running(q); |
| 2752 | if (unlikely(contended)) | 2763 | if (unlikely(contended)) |
| @@ -2866,6 +2877,9 @@ static int __dev_queue_xmit(struct sk_buff *skb, void *accel_priv) | |||
| 2866 | 2877 | ||
| 2867 | skb_reset_mac_header(skb); | 2878 | skb_reset_mac_header(skb); |
| 2868 | 2879 | ||
| 2880 | if (unlikely(skb_shinfo(skb)->tx_flags & SKBTX_SCHED_TSTAMP)) | ||
| 2881 | __skb_tstamp_tx(skb, NULL, skb->sk, SCM_TSTAMP_SCHED); | ||
| 2882 | |||
| 2869 | /* Disable soft irqs for various locks below. Also | 2883 | /* Disable soft irqs for various locks below. Also |
| 2870 | * stops preemption for RCU. | 2884 | * stops preemption for RCU. |
| 2871 | */ | 2885 | */ |
| @@ -3588,7 +3602,7 @@ another_round: | |||
| 3588 | 3602 | ||
| 3589 | if (skb->protocol == cpu_to_be16(ETH_P_8021Q) || | 3603 | if (skb->protocol == cpu_to_be16(ETH_P_8021Q) || |
| 3590 | skb->protocol == cpu_to_be16(ETH_P_8021AD)) { | 3604 | skb->protocol == cpu_to_be16(ETH_P_8021AD)) { |
| 3591 | skb = vlan_untag(skb); | 3605 | skb = skb_vlan_untag(skb); |
| 3592 | if (unlikely(!skb)) | 3606 | if (unlikely(!skb)) |
| 3593 | goto unlock; | 3607 | goto unlock; |
| 3594 | } | 3608 | } |
| @@ -5440,13 +5454,9 @@ int __dev_change_flags(struct net_device *dev, unsigned int flags) | |||
| 5440 | */ | 5454 | */ |
| 5441 | 5455 | ||
| 5442 | ret = 0; | 5456 | ret = 0; |
| 5443 | if ((old_flags ^ flags) & IFF_UP) { /* Bit is different ? */ | 5457 | if ((old_flags ^ flags) & IFF_UP) |
| 5444 | ret = ((old_flags & IFF_UP) ? __dev_close : __dev_open)(dev); | 5458 | ret = ((old_flags & IFF_UP) ? __dev_close : __dev_open)(dev); |
| 5445 | 5459 | ||
| 5446 | if (!ret) | ||
| 5447 | dev_set_rx_mode(dev); | ||
| 5448 | } | ||
| 5449 | |||
| 5450 | if ((flags ^ dev->gflags) & IFF_PROMISC) { | 5460 | if ((flags ^ dev->gflags) & IFF_PROMISC) { |
| 5451 | int inc = (flags & IFF_PROMISC) ? 1 : -1; | 5461 | int inc = (flags & IFF_PROMISC) ? 1 : -1; |
| 5452 | unsigned int old_flags = dev->flags; | 5462 | unsigned int old_flags = dev->flags; |
| @@ -6446,17 +6456,19 @@ void netdev_freemem(struct net_device *dev) | |||
| 6446 | 6456 | ||
| 6447 | /** | 6457 | /** |
| 6448 | * alloc_netdev_mqs - allocate network device | 6458 | * alloc_netdev_mqs - allocate network device |
| 6449 | * @sizeof_priv: size of private data to allocate space for | 6459 | * @sizeof_priv: size of private data to allocate space for |
| 6450 | * @name: device name format string | 6460 | * @name: device name format string |
| 6451 | * @setup: callback to initialize device | 6461 | * @name_assign_type: origin of device name |
| 6452 | * @txqs: the number of TX subqueues to allocate | 6462 | * @setup: callback to initialize device |
| 6453 | * @rxqs: the number of RX subqueues to allocate | 6463 | * @txqs: the number of TX subqueues to allocate |
| 6464 | * @rxqs: the number of RX subqueues to allocate | ||
| 6454 | * | 6465 | * |
| 6455 | * Allocates a struct net_device with private data area for driver use | 6466 | * Allocates a struct net_device with private data area for driver use |
| 6456 | * and performs basic initialization. Also allocates subqueue structs | 6467 | * and performs basic initialization. Also allocates subqueue structs |
| 6457 | * for each queue on the device. | 6468 | * for each queue on the device. |
| 6458 | */ | 6469 | */ |
| 6459 | struct net_device *alloc_netdev_mqs(int sizeof_priv, const char *name, | 6470 | struct net_device *alloc_netdev_mqs(int sizeof_priv, const char *name, |
| 6471 | unsigned char name_assign_type, | ||
| 6460 | void (*setup)(struct net_device *), | 6472 | void (*setup)(struct net_device *), |
| 6461 | unsigned int txqs, unsigned int rxqs) | 6473 | unsigned int txqs, unsigned int rxqs) |
| 6462 | { | 6474 | { |
| @@ -6535,6 +6547,7 @@ struct net_device *alloc_netdev_mqs(int sizeof_priv, const char *name, | |||
| 6535 | #endif | 6547 | #endif |
| 6536 | 6548 | ||
| 6537 | strcpy(dev->name, name); | 6549 | strcpy(dev->name, name); |
| 6550 | dev->name_assign_type = name_assign_type; | ||
| 6538 | dev->group = INIT_NETDEV_GROUP; | 6551 | dev->group = INIT_NETDEV_GROUP; |
| 6539 | if (!dev->ethtool_ops) | 6552 | if (!dev->ethtool_ops) |
| 6540 | dev->ethtool_ops = &default_ethtool_ops; | 6553 | dev->ethtool_ops = &default_ethtool_ops; |
| @@ -6946,12 +6959,14 @@ static int __netdev_printk(const char *level, const struct net_device *dev, | |||
| 6946 | if (dev && dev->dev.parent) { | 6959 | if (dev && dev->dev.parent) { |
| 6947 | r = dev_printk_emit(level[1] - '0', | 6960 | r = dev_printk_emit(level[1] - '0', |
| 6948 | dev->dev.parent, | 6961 | dev->dev.parent, |
| 6949 | "%s %s %s: %pV", | 6962 | "%s %s %s%s: %pV", |
| 6950 | dev_driver_string(dev->dev.parent), | 6963 | dev_driver_string(dev->dev.parent), |
| 6951 | dev_name(dev->dev.parent), | 6964 | dev_name(dev->dev.parent), |
| 6952 | netdev_name(dev), vaf); | 6965 | netdev_name(dev), netdev_reg_state(dev), |
| 6966 | vaf); | ||
| 6953 | } else if (dev) { | 6967 | } else if (dev) { |
| 6954 | r = printk("%s%s: %pV", level, netdev_name(dev), vaf); | 6968 | r = printk("%s%s%s: %pV", level, netdev_name(dev), |
| 6969 | netdev_reg_state(dev), vaf); | ||
| 6955 | } else { | 6970 | } else { |
| 6956 | r = printk("%s(NULL net_device): %pV", level, vaf); | 6971 | r = printk("%s(NULL net_device): %pV", level, vaf); |
| 6957 | } | 6972 | } |
| @@ -7103,7 +7118,7 @@ static void __net_exit default_device_exit_batch(struct list_head *net_list) | |||
| 7103 | rtnl_lock_unregistering(net_list); | 7118 | rtnl_lock_unregistering(net_list); |
| 7104 | list_for_each_entry(net, net_list, exit_list) { | 7119 | list_for_each_entry(net, net_list, exit_list) { |
| 7105 | for_each_netdev_reverse(net, dev) { | 7120 | for_each_netdev_reverse(net, dev) { |
| 7106 | if (dev->rtnl_link_ops) | 7121 | if (dev->rtnl_link_ops && dev->rtnl_link_ops->dellink) |
| 7107 | dev->rtnl_link_ops->dellink(dev, &dev_kill_list); | 7122 | dev->rtnl_link_ops->dellink(dev, &dev_kill_list); |
| 7108 | else | 7123 | else |
| 7109 | unregister_netdevice_queue(dev, &dev_kill_list); | 7124 | unregister_netdevice_queue(dev, &dev_kill_list); |
diff --git a/net/core/drop_monitor.c b/net/core/drop_monitor.c index e70301eb7a4a..50f9a9db5792 100644 --- a/net/core/drop_monitor.c +++ b/net/core/drop_monitor.c | |||
| @@ -289,10 +289,8 @@ static int net_dm_cmd_trace(struct sk_buff *skb, | |||
| 289 | switch (info->genlhdr->cmd) { | 289 | switch (info->genlhdr->cmd) { |
| 290 | case NET_DM_CMD_START: | 290 | case NET_DM_CMD_START: |
| 291 | return set_all_monitor_traces(TRACE_ON); | 291 | return set_all_monitor_traces(TRACE_ON); |
| 292 | break; | ||
| 293 | case NET_DM_CMD_STOP: | 292 | case NET_DM_CMD_STOP: |
| 294 | return set_all_monitor_traces(TRACE_OFF); | 293 | return set_all_monitor_traces(TRACE_OFF); |
| 295 | break; | ||
| 296 | } | 294 | } |
| 297 | 295 | ||
| 298 | return -ENOTSUPP; | 296 | return -ENOTSUPP; |
diff --git a/net/core/filter.c b/net/core/filter.c index 1dbf6462f766..d814b8a89d0f 100644 --- a/net/core/filter.c +++ b/net/core/filter.c | |||
| @@ -18,7 +18,7 @@ | |||
| 18 | * 2 of the License, or (at your option) any later version. | 18 | * 2 of the License, or (at your option) any later version. |
| 19 | * | 19 | * |
| 20 | * Andi Kleen - Fix a few bad bugs and races. | 20 | * Andi Kleen - Fix a few bad bugs and races. |
| 21 | * Kris Katterjohn - Added many additional checks in sk_chk_filter() | 21 | * Kris Katterjohn - Added many additional checks in bpf_check_classic() |
| 22 | */ | 22 | */ |
| 23 | 23 | ||
| 24 | #include <linux/module.h> | 24 | #include <linux/module.h> |
| @@ -45,54 +45,6 @@ | |||
| 45 | #include <linux/seccomp.h> | 45 | #include <linux/seccomp.h> |
| 46 | #include <linux/if_vlan.h> | 46 | #include <linux/if_vlan.h> |
| 47 | 47 | ||
| 48 | /* Registers */ | ||
| 49 | #define BPF_R0 regs[BPF_REG_0] | ||
| 50 | #define BPF_R1 regs[BPF_REG_1] | ||
| 51 | #define BPF_R2 regs[BPF_REG_2] | ||
| 52 | #define BPF_R3 regs[BPF_REG_3] | ||
| 53 | #define BPF_R4 regs[BPF_REG_4] | ||
| 54 | #define BPF_R5 regs[BPF_REG_5] | ||
| 55 | #define BPF_R6 regs[BPF_REG_6] | ||
| 56 | #define BPF_R7 regs[BPF_REG_7] | ||
| 57 | #define BPF_R8 regs[BPF_REG_8] | ||
| 58 | #define BPF_R9 regs[BPF_REG_9] | ||
| 59 | #define BPF_R10 regs[BPF_REG_10] | ||
| 60 | |||
| 61 | /* Named registers */ | ||
| 62 | #define DST regs[insn->dst_reg] | ||
| 63 | #define SRC regs[insn->src_reg] | ||
| 64 | #define FP regs[BPF_REG_FP] | ||
| 65 | #define ARG1 regs[BPF_REG_ARG1] | ||
| 66 | #define CTX regs[BPF_REG_CTX] | ||
| 67 | #define IMM insn->imm | ||
| 68 | |||
| 69 | /* No hurry in this branch | ||
| 70 | * | ||
| 71 | * Exported for the bpf jit load helper. | ||
| 72 | */ | ||
| 73 | void *bpf_internal_load_pointer_neg_helper(const struct sk_buff *skb, int k, unsigned int size) | ||
| 74 | { | ||
| 75 | u8 *ptr = NULL; | ||
| 76 | |||
| 77 | if (k >= SKF_NET_OFF) | ||
| 78 | ptr = skb_network_header(skb) + k - SKF_NET_OFF; | ||
| 79 | else if (k >= SKF_LL_OFF) | ||
| 80 | ptr = skb_mac_header(skb) + k - SKF_LL_OFF; | ||
| 81 | if (ptr >= skb->head && ptr + size <= skb_tail_pointer(skb)) | ||
| 82 | return ptr; | ||
| 83 | |||
| 84 | return NULL; | ||
| 85 | } | ||
| 86 | |||
| 87 | static inline void *load_pointer(const struct sk_buff *skb, int k, | ||
| 88 | unsigned int size, void *buffer) | ||
| 89 | { | ||
| 90 | if (k >= 0) | ||
| 91 | return skb_header_pointer(skb, k, size, buffer); | ||
| 92 | |||
| 93 | return bpf_internal_load_pointer_neg_helper(skb, k, size); | ||
| 94 | } | ||
| 95 | |||
| 96 | /** | 48 | /** |
| 97 | * sk_filter - run a packet through a socket filter | 49 | * sk_filter - run a packet through a socket filter |
| 98 | * @sk: sock associated with &sk_buff | 50 | * @sk: sock associated with &sk_buff |
| @@ -135,451 +87,6 @@ int sk_filter(struct sock *sk, struct sk_buff *skb) | |||
| 135 | } | 87 | } |
| 136 | EXPORT_SYMBOL(sk_filter); | 88 | EXPORT_SYMBOL(sk_filter); |
| 137 | 89 | ||
| 138 | /* Base function for offset calculation. Needs to go into .text section, | ||
| 139 | * therefore keeping it non-static as well; will also be used by JITs | ||
| 140 | * anyway later on, so do not let the compiler omit it. | ||
| 141 | */ | ||
| 142 | noinline u64 __bpf_call_base(u64 r1, u64 r2, u64 r3, u64 r4, u64 r5) | ||
| 143 | { | ||
| 144 | return 0; | ||
| 145 | } | ||
| 146 | |||
| 147 | /** | ||
| 148 | * __sk_run_filter - run a filter on a given context | ||
| 149 | * @ctx: buffer to run the filter on | ||
| 150 | * @insn: filter to apply | ||
| 151 | * | ||
| 152 | * Decode and apply filter instructions to the skb->data. Return length to | ||
| 153 | * keep, 0 for none. @ctx is the data we are operating on, @insn is the | ||
| 154 | * array of filter instructions. | ||
| 155 | */ | ||
| 156 | static unsigned int __sk_run_filter(void *ctx, const struct sock_filter_int *insn) | ||
| 157 | { | ||
| 158 | u64 stack[MAX_BPF_STACK / sizeof(u64)]; | ||
| 159 | u64 regs[MAX_BPF_REG], tmp; | ||
| 160 | static const void *jumptable[256] = { | ||
| 161 | [0 ... 255] = &&default_label, | ||
| 162 | /* Now overwrite non-defaults ... */ | ||
| 163 | /* 32 bit ALU operations */ | ||
| 164 | [BPF_ALU | BPF_ADD | BPF_X] = &&ALU_ADD_X, | ||
| 165 | [BPF_ALU | BPF_ADD | BPF_K] = &&ALU_ADD_K, | ||
| 166 | [BPF_ALU | BPF_SUB | BPF_X] = &&ALU_SUB_X, | ||
| 167 | [BPF_ALU | BPF_SUB | BPF_K] = &&ALU_SUB_K, | ||
| 168 | [BPF_ALU | BPF_AND | BPF_X] = &&ALU_AND_X, | ||
| 169 | [BPF_ALU | BPF_AND | BPF_K] = &&ALU_AND_K, | ||
| 170 | [BPF_ALU | BPF_OR | BPF_X] = &&ALU_OR_X, | ||
| 171 | [BPF_ALU | BPF_OR | BPF_K] = &&ALU_OR_K, | ||
| 172 | [BPF_ALU | BPF_LSH | BPF_X] = &&ALU_LSH_X, | ||
| 173 | [BPF_ALU | BPF_LSH | BPF_K] = &&ALU_LSH_K, | ||
| 174 | [BPF_ALU | BPF_RSH | BPF_X] = &&ALU_RSH_X, | ||
| 175 | [BPF_ALU | BPF_RSH | BPF_K] = &&ALU_RSH_K, | ||
| 176 | [BPF_ALU | BPF_XOR | BPF_X] = &&ALU_XOR_X, | ||
| 177 | [BPF_ALU | BPF_XOR | BPF_K] = &&ALU_XOR_K, | ||
| 178 | [BPF_ALU | BPF_MUL | BPF_X] = &&ALU_MUL_X, | ||
| 179 | [BPF_ALU | BPF_MUL | BPF_K] = &&ALU_MUL_K, | ||
| 180 | [BPF_ALU | BPF_MOV | BPF_X] = &&ALU_MOV_X, | ||
| 181 | [BPF_ALU | BPF_MOV | BPF_K] = &&ALU_MOV_K, | ||
| 182 | [BPF_ALU | BPF_DIV | BPF_X] = &&ALU_DIV_X, | ||
| 183 | [BPF_ALU | BPF_DIV | BPF_K] = &&ALU_DIV_K, | ||
| 184 | [BPF_ALU | BPF_MOD | BPF_X] = &&ALU_MOD_X, | ||
| 185 | [BPF_ALU | BPF_MOD | BPF_K] = &&ALU_MOD_K, | ||
| 186 | [BPF_ALU | BPF_NEG] = &&ALU_NEG, | ||
| 187 | [BPF_ALU | BPF_END | BPF_TO_BE] = &&ALU_END_TO_BE, | ||
| 188 | [BPF_ALU | BPF_END | BPF_TO_LE] = &&ALU_END_TO_LE, | ||
| 189 | /* 64 bit ALU operations */ | ||
| 190 | [BPF_ALU64 | BPF_ADD | BPF_X] = &&ALU64_ADD_X, | ||
| 191 | [BPF_ALU64 | BPF_ADD | BPF_K] = &&ALU64_ADD_K, | ||
| 192 | [BPF_ALU64 | BPF_SUB | BPF_X] = &&ALU64_SUB_X, | ||
| 193 | [BPF_ALU64 | BPF_SUB | BPF_K] = &&ALU64_SUB_K, | ||
| 194 | [BPF_ALU64 | BPF_AND | BPF_X] = &&ALU64_AND_X, | ||
| 195 | [BPF_ALU64 | BPF_AND | BPF_K] = &&ALU64_AND_K, | ||
| 196 | [BPF_ALU64 | BPF_OR | BPF_X] = &&ALU64_OR_X, | ||
| 197 | [BPF_ALU64 | BPF_OR | BPF_K] = &&ALU64_OR_K, | ||
| 198 | [BPF_ALU64 | BPF_LSH | BPF_X] = &&ALU64_LSH_X, | ||
| 199 | [BPF_ALU64 | BPF_LSH | BPF_K] = &&ALU64_LSH_K, | ||
| 200 | [BPF_ALU64 | BPF_RSH | BPF_X] = &&ALU64_RSH_X, | ||
| 201 | [BPF_ALU64 | BPF_RSH | BPF_K] = &&ALU64_RSH_K, | ||
| 202 | [BPF_ALU64 | BPF_XOR | BPF_X] = &&ALU64_XOR_X, | ||
| 203 | [BPF_ALU64 | BPF_XOR | BPF_K] = &&ALU64_XOR_K, | ||
| 204 | [BPF_ALU64 | BPF_MUL | BPF_X] = &&ALU64_MUL_X, | ||
| 205 | [BPF_ALU64 | BPF_MUL | BPF_K] = &&ALU64_MUL_K, | ||
| 206 | [BPF_ALU64 | BPF_MOV | BPF_X] = &&ALU64_MOV_X, | ||
| 207 | [BPF_ALU64 | BPF_MOV | BPF_K] = &&ALU64_MOV_K, | ||
| 208 | [BPF_ALU64 | BPF_ARSH | BPF_X] = &&ALU64_ARSH_X, | ||
| 209 | [BPF_ALU64 | BPF_ARSH | BPF_K] = &&ALU64_ARSH_K, | ||
| 210 | [BPF_ALU64 | BPF_DIV | BPF_X] = &&ALU64_DIV_X, | ||
| 211 | [BPF_ALU64 | BPF_DIV | BPF_K] = &&ALU64_DIV_K, | ||
| 212 | [BPF_ALU64 | BPF_MOD | BPF_X] = &&ALU64_MOD_X, | ||
| 213 | [BPF_ALU64 | BPF_MOD | BPF_K] = &&ALU64_MOD_K, | ||
| 214 | [BPF_ALU64 | BPF_NEG] = &&ALU64_NEG, | ||
| 215 | /* Call instruction */ | ||
| 216 | [BPF_JMP | BPF_CALL] = &&JMP_CALL, | ||
| 217 | /* Jumps */ | ||
| 218 | [BPF_JMP | BPF_JA] = &&JMP_JA, | ||
| 219 | [BPF_JMP | BPF_JEQ | BPF_X] = &&JMP_JEQ_X, | ||
| 220 | [BPF_JMP | BPF_JEQ | BPF_K] = &&JMP_JEQ_K, | ||
| 221 | [BPF_JMP | BPF_JNE | BPF_X] = &&JMP_JNE_X, | ||
| 222 | [BPF_JMP | BPF_JNE | BPF_K] = &&JMP_JNE_K, | ||
| 223 | [BPF_JMP | BPF_JGT | BPF_X] = &&JMP_JGT_X, | ||
| 224 | [BPF_JMP | BPF_JGT | BPF_K] = &&JMP_JGT_K, | ||
| 225 | [BPF_JMP | BPF_JGE | BPF_X] = &&JMP_JGE_X, | ||
| 226 | [BPF_JMP | BPF_JGE | BPF_K] = &&JMP_JGE_K, | ||
| 227 | [BPF_JMP | BPF_JSGT | BPF_X] = &&JMP_JSGT_X, | ||
| 228 | [BPF_JMP | BPF_JSGT | BPF_K] = &&JMP_JSGT_K, | ||
| 229 | [BPF_JMP | BPF_JSGE | BPF_X] = &&JMP_JSGE_X, | ||
| 230 | [BPF_JMP | BPF_JSGE | BPF_K] = &&JMP_JSGE_K, | ||
| 231 | [BPF_JMP | BPF_JSET | BPF_X] = &&JMP_JSET_X, | ||
| 232 | [BPF_JMP | BPF_JSET | BPF_K] = &&JMP_JSET_K, | ||
| 233 | /* Program return */ | ||
| 234 | [BPF_JMP | BPF_EXIT] = &&JMP_EXIT, | ||
| 235 | /* Store instructions */ | ||
| 236 | [BPF_STX | BPF_MEM | BPF_B] = &&STX_MEM_B, | ||
| 237 | [BPF_STX | BPF_MEM | BPF_H] = &&STX_MEM_H, | ||
| 238 | [BPF_STX | BPF_MEM | BPF_W] = &&STX_MEM_W, | ||
| 239 | [BPF_STX | BPF_MEM | BPF_DW] = &&STX_MEM_DW, | ||
| 240 | [BPF_STX | BPF_XADD | BPF_W] = &&STX_XADD_W, | ||
| 241 | [BPF_STX | BPF_XADD | BPF_DW] = &&STX_XADD_DW, | ||
| 242 | [BPF_ST | BPF_MEM | BPF_B] = &&ST_MEM_B, | ||
| 243 | [BPF_ST | BPF_MEM | BPF_H] = &&ST_MEM_H, | ||
| 244 | [BPF_ST | BPF_MEM | BPF_W] = &&ST_MEM_W, | ||
| 245 | [BPF_ST | BPF_MEM | BPF_DW] = &&ST_MEM_DW, | ||
| 246 | /* Load instructions */ | ||
| 247 | [BPF_LDX | BPF_MEM | BPF_B] = &&LDX_MEM_B, | ||
| 248 | [BPF_LDX | BPF_MEM | BPF_H] = &&LDX_MEM_H, | ||
| 249 | [BPF_LDX | BPF_MEM | BPF_W] = &&LDX_MEM_W, | ||
| 250 | [BPF_LDX | BPF_MEM | BPF_DW] = &&LDX_MEM_DW, | ||
| 251 | [BPF_LD | BPF_ABS | BPF_W] = &&LD_ABS_W, | ||
| 252 | [BPF_LD | BPF_ABS | BPF_H] = &&LD_ABS_H, | ||
| 253 | [BPF_LD | BPF_ABS | BPF_B] = &&LD_ABS_B, | ||
| 254 | [BPF_LD | BPF_IND | BPF_W] = &&LD_IND_W, | ||
| 255 | [BPF_LD | BPF_IND | BPF_H] = &&LD_IND_H, | ||
| 256 | [BPF_LD | BPF_IND | BPF_B] = &&LD_IND_B, | ||
| 257 | }; | ||
| 258 | void *ptr; | ||
| 259 | int off; | ||
| 260 | |||
| 261 | #define CONT ({ insn++; goto select_insn; }) | ||
| 262 | #define CONT_JMP ({ insn++; goto select_insn; }) | ||
| 263 | |||
| 264 | FP = (u64) (unsigned long) &stack[ARRAY_SIZE(stack)]; | ||
| 265 | ARG1 = (u64) (unsigned long) ctx; | ||
| 266 | |||
| 267 | /* Registers used in classic BPF programs need to be reset first. */ | ||
| 268 | regs[BPF_REG_A] = 0; | ||
| 269 | regs[BPF_REG_X] = 0; | ||
| 270 | |||
| 271 | select_insn: | ||
| 272 | goto *jumptable[insn->code]; | ||
| 273 | |||
| 274 | /* ALU */ | ||
| 275 | #define ALU(OPCODE, OP) \ | ||
| 276 | ALU64_##OPCODE##_X: \ | ||
| 277 | DST = DST OP SRC; \ | ||
| 278 | CONT; \ | ||
| 279 | ALU_##OPCODE##_X: \ | ||
| 280 | DST = (u32) DST OP (u32) SRC; \ | ||
| 281 | CONT; \ | ||
| 282 | ALU64_##OPCODE##_K: \ | ||
| 283 | DST = DST OP IMM; \ | ||
| 284 | CONT; \ | ||
| 285 | ALU_##OPCODE##_K: \ | ||
| 286 | DST = (u32) DST OP (u32) IMM; \ | ||
| 287 | CONT; | ||
| 288 | |||
| 289 | ALU(ADD, +) | ||
| 290 | ALU(SUB, -) | ||
| 291 | ALU(AND, &) | ||
| 292 | ALU(OR, |) | ||
| 293 | ALU(LSH, <<) | ||
| 294 | ALU(RSH, >>) | ||
| 295 | ALU(XOR, ^) | ||
| 296 | ALU(MUL, *) | ||
| 297 | #undef ALU | ||
| 298 | ALU_NEG: | ||
| 299 | DST = (u32) -DST; | ||
| 300 | CONT; | ||
| 301 | ALU64_NEG: | ||
| 302 | DST = -DST; | ||
| 303 | CONT; | ||
| 304 | ALU_MOV_X: | ||
| 305 | DST = (u32) SRC; | ||
| 306 | CONT; | ||
| 307 | ALU_MOV_K: | ||
| 308 | DST = (u32) IMM; | ||
| 309 | CONT; | ||
| 310 | ALU64_MOV_X: | ||
| 311 | DST = SRC; | ||
| 312 | CONT; | ||
| 313 | ALU64_MOV_K: | ||
| 314 | DST = IMM; | ||
| 315 | CONT; | ||
| 316 | ALU64_ARSH_X: | ||
| 317 | (*(s64 *) &DST) >>= SRC; | ||
| 318 | CONT; | ||
| 319 | ALU64_ARSH_K: | ||
| 320 | (*(s64 *) &DST) >>= IMM; | ||
| 321 | CONT; | ||
| 322 | ALU64_MOD_X: | ||
| 323 | if (unlikely(SRC == 0)) | ||
| 324 | return 0; | ||
| 325 | tmp = DST; | ||
| 326 | DST = do_div(tmp, SRC); | ||
| 327 | CONT; | ||
| 328 | ALU_MOD_X: | ||
| 329 | if (unlikely(SRC == 0)) | ||
| 330 | return 0; | ||
| 331 | tmp = (u32) DST; | ||
| 332 | DST = do_div(tmp, (u32) SRC); | ||
| 333 | CONT; | ||
| 334 | ALU64_MOD_K: | ||
| 335 | tmp = DST; | ||
| 336 | DST = do_div(tmp, IMM); | ||
| 337 | CONT; | ||
| 338 | ALU_MOD_K: | ||
| 339 | tmp = (u32) DST; | ||
| 340 | DST = do_div(tmp, (u32) IMM); | ||
| 341 | CONT; | ||
| 342 | ALU64_DIV_X: | ||
| 343 | if (unlikely(SRC == 0)) | ||
| 344 | return 0; | ||
| 345 | do_div(DST, SRC); | ||
| 346 | CONT; | ||
| 347 | ALU_DIV_X: | ||
| 348 | if (unlikely(SRC == 0)) | ||
| 349 | return 0; | ||
| 350 | tmp = (u32) DST; | ||
| 351 | do_div(tmp, (u32) SRC); | ||
| 352 | DST = (u32) tmp; | ||
| 353 | CONT; | ||
| 354 | ALU64_DIV_K: | ||
| 355 | do_div(DST, IMM); | ||
| 356 | CONT; | ||
| 357 | ALU_DIV_K: | ||
| 358 | tmp = (u32) DST; | ||
| 359 | do_div(tmp, (u32) IMM); | ||
| 360 | DST = (u32) tmp; | ||
| 361 | CONT; | ||
| 362 | ALU_END_TO_BE: | ||
| 363 | switch (IMM) { | ||
| 364 | case 16: | ||
| 365 | DST = (__force u16) cpu_to_be16(DST); | ||
| 366 | break; | ||
| 367 | case 32: | ||
| 368 | DST = (__force u32) cpu_to_be32(DST); | ||
| 369 | break; | ||
| 370 | case 64: | ||
| 371 | DST = (__force u64) cpu_to_be64(DST); | ||
| 372 | break; | ||
| 373 | } | ||
| 374 | CONT; | ||
| 375 | ALU_END_TO_LE: | ||
| 376 | switch (IMM) { | ||
| 377 | case 16: | ||
| 378 | DST = (__force u16) cpu_to_le16(DST); | ||
| 379 | break; | ||
| 380 | case 32: | ||
| 381 | DST = (__force u32) cpu_to_le32(DST); | ||
| 382 | break; | ||
| 383 | case 64: | ||
| 384 | DST = (__force u64) cpu_to_le64(DST); | ||
| 385 | break; | ||
| 386 | } | ||
| 387 | CONT; | ||
| 388 | |||
| 389 | /* CALL */ | ||
| 390 | JMP_CALL: | ||
| 391 | /* Function call scratches BPF_R1-BPF_R5 registers, | ||
| 392 | * preserves BPF_R6-BPF_R9, and stores return value | ||
| 393 | * into BPF_R0. | ||
| 394 | */ | ||
| 395 | BPF_R0 = (__bpf_call_base + insn->imm)(BPF_R1, BPF_R2, BPF_R3, | ||
| 396 | BPF_R4, BPF_R5); | ||
| 397 | CONT; | ||
| 398 | |||
| 399 | /* JMP */ | ||
| 400 | JMP_JA: | ||
| 401 | insn += insn->off; | ||
| 402 | CONT; | ||
| 403 | JMP_JEQ_X: | ||
| 404 | if (DST == SRC) { | ||
| 405 | insn += insn->off; | ||
| 406 | CONT_JMP; | ||
| 407 | } | ||
| 408 | CONT; | ||
| 409 | JMP_JEQ_K: | ||
| 410 | if (DST == IMM) { | ||
| 411 | insn += insn->off; | ||
| 412 | CONT_JMP; | ||
| 413 | } | ||
| 414 | CONT; | ||
| 415 | JMP_JNE_X: | ||
| 416 | if (DST != SRC) { | ||
| 417 | insn += insn->off; | ||
| 418 | CONT_JMP; | ||
| 419 | } | ||
| 420 | CONT; | ||
| 421 | JMP_JNE_K: | ||
| 422 | if (DST != IMM) { | ||
| 423 | insn += insn->off; | ||
| 424 | CONT_JMP; | ||
| 425 | } | ||
| 426 | CONT; | ||
| 427 | JMP_JGT_X: | ||
| 428 | if (DST > SRC) { | ||
| 429 | insn += insn->off; | ||
| 430 | CONT_JMP; | ||
| 431 | } | ||
| 432 | CONT; | ||
| 433 | JMP_JGT_K: | ||
| 434 | if (DST > IMM) { | ||
| 435 | insn += insn->off; | ||
| 436 | CONT_JMP; | ||
| 437 | } | ||
| 438 | CONT; | ||
| 439 | JMP_JGE_X: | ||
| 440 | if (DST >= SRC) { | ||
| 441 | insn += insn->off; | ||
| 442 | CONT_JMP; | ||
| 443 | } | ||
| 444 | CONT; | ||
| 445 | JMP_JGE_K: | ||
| 446 | if (DST >= IMM) { | ||
| 447 | insn += insn->off; | ||
| 448 | CONT_JMP; | ||
| 449 | } | ||
| 450 | CONT; | ||
| 451 | JMP_JSGT_X: | ||
| 452 | if (((s64) DST) > ((s64) SRC)) { | ||
| 453 | insn += insn->off; | ||
| 454 | CONT_JMP; | ||
| 455 | } | ||
| 456 | CONT; | ||
| 457 | JMP_JSGT_K: | ||
| 458 | if (((s64) DST) > ((s64) IMM)) { | ||
| 459 | insn += insn->off; | ||
| 460 | CONT_JMP; | ||
| 461 | } | ||
| 462 | CONT; | ||
| 463 | JMP_JSGE_X: | ||
| 464 | if (((s64) DST) >= ((s64) SRC)) { | ||
| 465 | insn += insn->off; | ||
| 466 | CONT_JMP; | ||
| 467 | } | ||
| 468 | CONT; | ||
| 469 | JMP_JSGE_K: | ||
| 470 | if (((s64) DST) >= ((s64) IMM)) { | ||
| 471 | insn += insn->off; | ||
| 472 | CONT_JMP; | ||
| 473 | } | ||
| 474 | CONT; | ||
| 475 | JMP_JSET_X: | ||
| 476 | if (DST & SRC) { | ||
| 477 | insn += insn->off; | ||
| 478 | CONT_JMP; | ||
| 479 | } | ||
| 480 | CONT; | ||
| 481 | JMP_JSET_K: | ||
| 482 | if (DST & IMM) { | ||
| 483 | insn += insn->off; | ||
| 484 | CONT_JMP; | ||
| 485 | } | ||
| 486 | CONT; | ||
| 487 | JMP_EXIT: | ||
| 488 | return BPF_R0; | ||
| 489 | |||
| 490 | /* STX and ST and LDX*/ | ||
| 491 | #define LDST(SIZEOP, SIZE) \ | ||
| 492 | STX_MEM_##SIZEOP: \ | ||
| 493 | *(SIZE *)(unsigned long) (DST + insn->off) = SRC; \ | ||
| 494 | CONT; \ | ||
| 495 | ST_MEM_##SIZEOP: \ | ||
| 496 | *(SIZE *)(unsigned long) (DST + insn->off) = IMM; \ | ||
| 497 | CONT; \ | ||
| 498 | LDX_MEM_##SIZEOP: \ | ||
| 499 | DST = *(SIZE *)(unsigned long) (SRC + insn->off); \ | ||
| 500 | CONT; | ||
| 501 | |||
| 502 | LDST(B, u8) | ||
| 503 | LDST(H, u16) | ||
| 504 | LDST(W, u32) | ||
| 505 | LDST(DW, u64) | ||
| 506 | #undef LDST | ||
| 507 | STX_XADD_W: /* lock xadd *(u32 *)(dst_reg + off16) += src_reg */ | ||
| 508 | atomic_add((u32) SRC, (atomic_t *)(unsigned long) | ||
| 509 | (DST + insn->off)); | ||
| 510 | CONT; | ||
| 511 | STX_XADD_DW: /* lock xadd *(u64 *)(dst_reg + off16) += src_reg */ | ||
| 512 | atomic64_add((u64) SRC, (atomic64_t *)(unsigned long) | ||
| 513 | (DST + insn->off)); | ||
| 514 | CONT; | ||
| 515 | LD_ABS_W: /* BPF_R0 = ntohl(*(u32 *) (skb->data + imm32)) */ | ||
| 516 | off = IMM; | ||
| 517 | load_word: | ||
| 518 | /* BPF_LD + BPD_ABS and BPF_LD + BPF_IND insns are | ||
| 519 | * only appearing in the programs where ctx == | ||
| 520 | * skb. All programs keep 'ctx' in regs[BPF_REG_CTX] | ||
| 521 | * == BPF_R6, sk_convert_filter() saves it in BPF_R6, | ||
| 522 | * internal BPF verifier will check that BPF_R6 == | ||
| 523 | * ctx. | ||
| 524 | * | ||
| 525 | * BPF_ABS and BPF_IND are wrappers of function calls, | ||
| 526 | * so they scratch BPF_R1-BPF_R5 registers, preserve | ||
| 527 | * BPF_R6-BPF_R9, and store return value into BPF_R0. | ||
| 528 | * | ||
| 529 | * Implicit input: | ||
| 530 | * ctx == skb == BPF_R6 == CTX | ||
| 531 | * | ||
| 532 | * Explicit input: | ||
| 533 | * SRC == any register | ||
| 534 | * IMM == 32-bit immediate | ||
| 535 | * | ||
| 536 | * Output: | ||
| 537 | * BPF_R0 - 8/16/32-bit skb data converted to cpu endianness | ||
| 538 | */ | ||
| 539 | |||
| 540 | ptr = load_pointer((struct sk_buff *) (unsigned long) CTX, off, 4, &tmp); | ||
| 541 | if (likely(ptr != NULL)) { | ||
| 542 | BPF_R0 = get_unaligned_be32(ptr); | ||
| 543 | CONT; | ||
| 544 | } | ||
| 545 | |||
| 546 | return 0; | ||
| 547 | LD_ABS_H: /* BPF_R0 = ntohs(*(u16 *) (skb->data + imm32)) */ | ||
| 548 | off = IMM; | ||
| 549 | load_half: | ||
| 550 | ptr = load_pointer((struct sk_buff *) (unsigned long) CTX, off, 2, &tmp); | ||
| 551 | if (likely(ptr != NULL)) { | ||
| 552 | BPF_R0 = get_unaligned_be16(ptr); | ||
| 553 | CONT; | ||
| 554 | } | ||
| 555 | |||
| 556 | return 0; | ||
| 557 | LD_ABS_B: /* BPF_R0 = *(u8 *) (skb->data + imm32) */ | ||
| 558 | off = IMM; | ||
| 559 | load_byte: | ||
| 560 | ptr = load_pointer((struct sk_buff *) (unsigned long) CTX, off, 1, &tmp); | ||
| 561 | if (likely(ptr != NULL)) { | ||
| 562 | BPF_R0 = *(u8 *)ptr; | ||
| 563 | CONT; | ||
| 564 | } | ||
| 565 | |||
| 566 | return 0; | ||
| 567 | LD_IND_W: /* BPF_R0 = ntohl(*(u32 *) (skb->data + src_reg + imm32)) */ | ||
| 568 | off = IMM + SRC; | ||
| 569 | goto load_word; | ||
| 570 | LD_IND_H: /* BPF_R0 = ntohs(*(u16 *) (skb->data + src_reg + imm32)) */ | ||
| 571 | off = IMM + SRC; | ||
| 572 | goto load_half; | ||
| 573 | LD_IND_B: /* BPF_R0 = *(u8 *) (skb->data + src_reg + imm32) */ | ||
| 574 | off = IMM + SRC; | ||
| 575 | goto load_byte; | ||
| 576 | |||
| 577 | default_label: | ||
| 578 | /* If we ever reach this, we have a bug somewhere. */ | ||
| 579 | WARN_RATELIMIT(1, "unknown opcode %02x\n", insn->code); | ||
| 580 | return 0; | ||
| 581 | } | ||
| 582 | |||
| 583 | /* Helper to find the offset of pkt_type in sk_buff structure. We want | 90 | /* Helper to find the offset of pkt_type in sk_buff structure. We want |
| 584 | * to make sure its still a 3bit field starting at a byte boundary; | 91 | * to make sure its still a 3bit field starting at a byte boundary; |
| 585 | * taken from arch/x86/net/bpf_jit_comp.c. | 92 | * taken from arch/x86/net/bpf_jit_comp.c. |
| @@ -667,9 +174,9 @@ static u64 __get_random_u32(u64 ctx, u64 a, u64 x, u64 r4, u64 r5) | |||
| 667 | } | 174 | } |
| 668 | 175 | ||
| 669 | static bool convert_bpf_extensions(struct sock_filter *fp, | 176 | static bool convert_bpf_extensions(struct sock_filter *fp, |
| 670 | struct sock_filter_int **insnp) | 177 | struct bpf_insn **insnp) |
| 671 | { | 178 | { |
| 672 | struct sock_filter_int *insn = *insnp; | 179 | struct bpf_insn *insn = *insnp; |
| 673 | 180 | ||
| 674 | switch (fp->k) { | 181 | switch (fp->k) { |
| 675 | case SKF_AD_OFF + SKF_AD_PROTOCOL: | 182 | case SKF_AD_OFF + SKF_AD_PROTOCOL: |
| @@ -805,7 +312,7 @@ static bool convert_bpf_extensions(struct sock_filter *fp, | |||
| 805 | } | 312 | } |
| 806 | 313 | ||
| 807 | /** | 314 | /** |
| 808 | * sk_convert_filter - convert filter program | 315 | * bpf_convert_filter - convert filter program |
| 809 | * @prog: the user passed filter program | 316 | * @prog: the user passed filter program |
| 810 | * @len: the length of the user passed filter program | 317 | * @len: the length of the user passed filter program |
| 811 | * @new_prog: buffer where converted program will be stored | 318 | * @new_prog: buffer where converted program will be stored |
| @@ -815,12 +322,12 @@ static bool convert_bpf_extensions(struct sock_filter *fp, | |||
| 815 | * Conversion workflow: | 322 | * Conversion workflow: |
| 816 | * | 323 | * |
| 817 | * 1) First pass for calculating the new program length: | 324 | * 1) First pass for calculating the new program length: |
| 818 | * sk_convert_filter(old_prog, old_len, NULL, &new_len) | 325 | * bpf_convert_filter(old_prog, old_len, NULL, &new_len) |
| 819 | * | 326 | * |
| 820 | * 2) 2nd pass to remap in two passes: 1st pass finds new | 327 | * 2) 2nd pass to remap in two passes: 1st pass finds new |
| 821 | * jump offsets, 2nd pass remapping: | 328 | * jump offsets, 2nd pass remapping: |
| 822 | * new_prog = kmalloc(sizeof(struct sock_filter_int) * new_len); | 329 | * new_prog = kmalloc(sizeof(struct bpf_insn) * new_len); |
| 823 | * sk_convert_filter(old_prog, old_len, new_prog, &new_len); | 330 | * bpf_convert_filter(old_prog, old_len, new_prog, &new_len); |
| 824 | * | 331 | * |
| 825 | * User BPF's register A is mapped to our BPF register 6, user BPF | 332 | * User BPF's register A is mapped to our BPF register 6, user BPF |
| 826 | * register X is mapped to BPF register 7; frame pointer is always | 333 | * register X is mapped to BPF register 7; frame pointer is always |
| @@ -828,11 +335,11 @@ static bool convert_bpf_extensions(struct sock_filter *fp, | |||
| 828 | * for socket filters: ctx == 'struct sk_buff *', for seccomp: | 335 | * for socket filters: ctx == 'struct sk_buff *', for seccomp: |
| 829 | * ctx == 'struct seccomp_data *'. | 336 | * ctx == 'struct seccomp_data *'. |
| 830 | */ | 337 | */ |
| 831 | int sk_convert_filter(struct sock_filter *prog, int len, | 338 | int bpf_convert_filter(struct sock_filter *prog, int len, |
| 832 | struct sock_filter_int *new_prog, int *new_len) | 339 | struct bpf_insn *new_prog, int *new_len) |
| 833 | { | 340 | { |
| 834 | int new_flen = 0, pass = 0, target, i; | 341 | int new_flen = 0, pass = 0, target, i; |
| 835 | struct sock_filter_int *new_insn; | 342 | struct bpf_insn *new_insn; |
| 836 | struct sock_filter *fp; | 343 | struct sock_filter *fp; |
| 837 | int *addrs = NULL; | 344 | int *addrs = NULL; |
| 838 | u8 bpf_src; | 345 | u8 bpf_src; |
| @@ -858,8 +365,8 @@ do_pass: | |||
| 858 | new_insn++; | 365 | new_insn++; |
| 859 | 366 | ||
| 860 | for (i = 0; i < len; fp++, i++) { | 367 | for (i = 0; i < len; fp++, i++) { |
| 861 | struct sock_filter_int tmp_insns[6] = { }; | 368 | struct bpf_insn tmp_insns[6] = { }; |
| 862 | struct sock_filter_int *insn = tmp_insns; | 369 | struct bpf_insn *insn = tmp_insns; |
| 863 | 370 | ||
| 864 | if (addrs) | 371 | if (addrs) |
| 865 | addrs[i] = new_insn - new_prog; | 372 | addrs[i] = new_insn - new_prog; |
| @@ -1094,7 +601,7 @@ err: | |||
| 1094 | * a cell if not previously written, and we check all branches to be sure | 601 | * a cell if not previously written, and we check all branches to be sure |
| 1095 | * a malicious user doesn't try to abuse us. | 602 | * a malicious user doesn't try to abuse us. |
| 1096 | */ | 603 | */ |
| 1097 | static int check_load_and_stores(struct sock_filter *filter, int flen) | 604 | static int check_load_and_stores(const struct sock_filter *filter, int flen) |
| 1098 | { | 605 | { |
| 1099 | u16 *masks, memvalid = 0; /* One bit per cell, 16 cells */ | 606 | u16 *masks, memvalid = 0; /* One bit per cell, 16 cells */ |
| 1100 | int pc, ret = 0; | 607 | int pc, ret = 0; |
| @@ -1214,7 +721,7 @@ static bool chk_code_allowed(u16 code_to_probe) | |||
| 1214 | } | 721 | } |
| 1215 | 722 | ||
| 1216 | /** | 723 | /** |
| 1217 | * sk_chk_filter - verify socket filter code | 724 | * bpf_check_classic - verify socket filter code |
| 1218 | * @filter: filter to verify | 725 | * @filter: filter to verify |
| 1219 | * @flen: length of filter | 726 | * @flen: length of filter |
| 1220 | * | 727 | * |
| @@ -1227,7 +734,7 @@ static bool chk_code_allowed(u16 code_to_probe) | |||
| 1227 | * | 734 | * |
| 1228 | * Returns 0 if the rule set is legal or -EINVAL if not. | 735 | * Returns 0 if the rule set is legal or -EINVAL if not. |
| 1229 | */ | 736 | */ |
| 1230 | int sk_chk_filter(struct sock_filter *filter, unsigned int flen) | 737 | int bpf_check_classic(const struct sock_filter *filter, unsigned int flen) |
| 1231 | { | 738 | { |
| 1232 | bool anc_found; | 739 | bool anc_found; |
| 1233 | int pc; | 740 | int pc; |
| @@ -1237,7 +744,7 @@ int sk_chk_filter(struct sock_filter *filter, unsigned int flen) | |||
| 1237 | 744 | ||
| 1238 | /* Check the filter code now */ | 745 | /* Check the filter code now */ |
| 1239 | for (pc = 0; pc < flen; pc++) { | 746 | for (pc = 0; pc < flen; pc++) { |
| 1240 | struct sock_filter *ftest = &filter[pc]; | 747 | const struct sock_filter *ftest = &filter[pc]; |
| 1241 | 748 | ||
| 1242 | /* May we actually operate on this code? */ | 749 | /* May we actually operate on this code? */ |
| 1243 | if (!chk_code_allowed(ftest->code)) | 750 | if (!chk_code_allowed(ftest->code)) |
| @@ -1301,12 +808,12 @@ int sk_chk_filter(struct sock_filter *filter, unsigned int flen) | |||
| 1301 | 808 | ||
| 1302 | return -EINVAL; | 809 | return -EINVAL; |
| 1303 | } | 810 | } |
| 1304 | EXPORT_SYMBOL(sk_chk_filter); | 811 | EXPORT_SYMBOL(bpf_check_classic); |
| 1305 | 812 | ||
| 1306 | static int sk_store_orig_filter(struct sk_filter *fp, | 813 | static int bpf_prog_store_orig_filter(struct bpf_prog *fp, |
| 1307 | const struct sock_fprog *fprog) | 814 | const struct sock_fprog *fprog) |
| 1308 | { | 815 | { |
| 1309 | unsigned int fsize = sk_filter_proglen(fprog); | 816 | unsigned int fsize = bpf_classic_proglen(fprog); |
| 1310 | struct sock_fprog_kern *fkprog; | 817 | struct sock_fprog_kern *fkprog; |
| 1311 | 818 | ||
| 1312 | fp->orig_prog = kmalloc(sizeof(*fkprog), GFP_KERNEL); | 819 | fp->orig_prog = kmalloc(sizeof(*fkprog), GFP_KERNEL); |
| @@ -1324,7 +831,7 @@ static int sk_store_orig_filter(struct sk_filter *fp, | |||
| 1324 | return 0; | 831 | return 0; |
| 1325 | } | 832 | } |
| 1326 | 833 | ||
| 1327 | static void sk_release_orig_filter(struct sk_filter *fp) | 834 | static void bpf_release_orig_filter(struct bpf_prog *fp) |
| 1328 | { | 835 | { |
| 1329 | struct sock_fprog_kern *fprog = fp->orig_prog; | 836 | struct sock_fprog_kern *fprog = fp->orig_prog; |
| 1330 | 837 | ||
| @@ -1334,6 +841,18 @@ static void sk_release_orig_filter(struct sk_filter *fp) | |||
| 1334 | } | 841 | } |
| 1335 | } | 842 | } |
| 1336 | 843 | ||
| 844 | static void __bpf_prog_release(struct bpf_prog *prog) | ||
| 845 | { | ||
| 846 | bpf_release_orig_filter(prog); | ||
| 847 | bpf_prog_free(prog); | ||
| 848 | } | ||
| 849 | |||
| 850 | static void __sk_filter_release(struct sk_filter *fp) | ||
| 851 | { | ||
| 852 | __bpf_prog_release(fp->prog); | ||
| 853 | kfree(fp); | ||
| 854 | } | ||
| 855 | |||
| 1337 | /** | 856 | /** |
| 1338 | * sk_filter_release_rcu - Release a socket filter by rcu_head | 857 | * sk_filter_release_rcu - Release a socket filter by rcu_head |
| 1339 | * @rcu: rcu_head that contains the sk_filter to free | 858 | * @rcu: rcu_head that contains the sk_filter to free |
| @@ -1342,8 +861,7 @@ static void sk_filter_release_rcu(struct rcu_head *rcu) | |||
| 1342 | { | 861 | { |
| 1343 | struct sk_filter *fp = container_of(rcu, struct sk_filter, rcu); | 862 | struct sk_filter *fp = container_of(rcu, struct sk_filter, rcu); |
| 1344 | 863 | ||
| 1345 | sk_release_orig_filter(fp); | 864 | __sk_filter_release(fp); |
| 1346 | sk_filter_free(fp); | ||
| 1347 | } | 865 | } |
| 1348 | 866 | ||
| 1349 | /** | 867 | /** |
| @@ -1360,44 +878,33 @@ static void sk_filter_release(struct sk_filter *fp) | |||
| 1360 | 878 | ||
| 1361 | void sk_filter_uncharge(struct sock *sk, struct sk_filter *fp) | 879 | void sk_filter_uncharge(struct sock *sk, struct sk_filter *fp) |
| 1362 | { | 880 | { |
| 1363 | atomic_sub(sk_filter_size(fp->len), &sk->sk_omem_alloc); | 881 | u32 filter_size = bpf_prog_size(fp->prog->len); |
| 1364 | sk_filter_release(fp); | ||
| 1365 | } | ||
| 1366 | 882 | ||
| 1367 | void sk_filter_charge(struct sock *sk, struct sk_filter *fp) | 883 | atomic_sub(filter_size, &sk->sk_omem_alloc); |
| 1368 | { | 884 | sk_filter_release(fp); |
| 1369 | atomic_inc(&fp->refcnt); | ||
| 1370 | atomic_add(sk_filter_size(fp->len), &sk->sk_omem_alloc); | ||
| 1371 | } | 885 | } |
| 1372 | 886 | ||
| 1373 | static struct sk_filter *__sk_migrate_realloc(struct sk_filter *fp, | 887 | /* try to charge the socket memory if there is space available |
| 1374 | struct sock *sk, | 888 | * return true on success |
| 1375 | unsigned int len) | 889 | */ |
| 890 | bool sk_filter_charge(struct sock *sk, struct sk_filter *fp) | ||
| 1376 | { | 891 | { |
| 1377 | struct sk_filter *fp_new; | 892 | u32 filter_size = bpf_prog_size(fp->prog->len); |
| 1378 | 893 | ||
| 1379 | if (sk == NULL) | 894 | /* same check as in sock_kmalloc() */ |
| 1380 | return krealloc(fp, len, GFP_KERNEL); | 895 | if (filter_size <= sysctl_optmem_max && |
| 1381 | 896 | atomic_read(&sk->sk_omem_alloc) + filter_size < sysctl_optmem_max) { | |
| 1382 | fp_new = sock_kmalloc(sk, len, GFP_KERNEL); | 897 | atomic_inc(&fp->refcnt); |
| 1383 | if (fp_new) { | 898 | atomic_add(filter_size, &sk->sk_omem_alloc); |
| 1384 | *fp_new = *fp; | 899 | return true; |
| 1385 | /* As we're keeping orig_prog in fp_new along, | ||
| 1386 | * we need to make sure we're not evicting it | ||
| 1387 | * from the old fp. | ||
| 1388 | */ | ||
| 1389 | fp->orig_prog = NULL; | ||
| 1390 | sk_filter_uncharge(sk, fp); | ||
| 1391 | } | 900 | } |
| 1392 | 901 | return false; | |
| 1393 | return fp_new; | ||
| 1394 | } | 902 | } |
| 1395 | 903 | ||
| 1396 | static struct sk_filter *__sk_migrate_filter(struct sk_filter *fp, | 904 | static struct bpf_prog *bpf_migrate_filter(struct bpf_prog *fp) |
| 1397 | struct sock *sk) | ||
| 1398 | { | 905 | { |
| 1399 | struct sock_filter *old_prog; | 906 | struct sock_filter *old_prog; |
| 1400 | struct sk_filter *old_fp; | 907 | struct bpf_prog *old_fp; |
| 1401 | int err, new_len, old_len = fp->len; | 908 | int err, new_len, old_len = fp->len; |
| 1402 | 909 | ||
| 1403 | /* We are free to overwrite insns et al right here as it | 910 | /* We are free to overwrite insns et al right here as it |
| @@ -1406,7 +913,7 @@ static struct sk_filter *__sk_migrate_filter(struct sk_filter *fp, | |||
| 1406 | * representation. | 913 | * representation. |
| 1407 | */ | 914 | */ |
| 1408 | BUILD_BUG_ON(sizeof(struct sock_filter) != | 915 | BUILD_BUG_ON(sizeof(struct sock_filter) != |
| 1409 | sizeof(struct sock_filter_int)); | 916 | sizeof(struct bpf_insn)); |
| 1410 | 917 | ||
| 1411 | /* Conversion cannot happen on overlapping memory areas, | 918 | /* Conversion cannot happen on overlapping memory areas, |
| 1412 | * so we need to keep the user BPF around until the 2nd | 919 | * so we need to keep the user BPF around until the 2nd |
| @@ -1420,13 +927,13 @@ static struct sk_filter *__sk_migrate_filter(struct sk_filter *fp, | |||
| 1420 | } | 927 | } |
| 1421 | 928 | ||
| 1422 | /* 1st pass: calculate the new program length. */ | 929 | /* 1st pass: calculate the new program length. */ |
| 1423 | err = sk_convert_filter(old_prog, old_len, NULL, &new_len); | 930 | err = bpf_convert_filter(old_prog, old_len, NULL, &new_len); |
| 1424 | if (err) | 931 | if (err) |
| 1425 | goto out_err_free; | 932 | goto out_err_free; |
| 1426 | 933 | ||
| 1427 | /* Expand fp for appending the new filter representation. */ | 934 | /* Expand fp for appending the new filter representation. */ |
| 1428 | old_fp = fp; | 935 | old_fp = fp; |
| 1429 | fp = __sk_migrate_realloc(old_fp, sk, sk_filter_size(new_len)); | 936 | fp = krealloc(old_fp, bpf_prog_size(new_len), GFP_KERNEL); |
| 1430 | if (!fp) { | 937 | if (!fp) { |
| 1431 | /* The old_fp is still around in case we couldn't | 938 | /* The old_fp is still around in case we couldn't |
| 1432 | * allocate new memory, so uncharge on that one. | 939 | * allocate new memory, so uncharge on that one. |
| @@ -1438,17 +945,17 @@ static struct sk_filter *__sk_migrate_filter(struct sk_filter *fp, | |||
| 1438 | 945 | ||
| 1439 | fp->len = new_len; | 946 | fp->len = new_len; |
| 1440 | 947 | ||
| 1441 | /* 2nd pass: remap sock_filter insns into sock_filter_int insns. */ | 948 | /* 2nd pass: remap sock_filter insns into bpf_insn insns. */ |
| 1442 | err = sk_convert_filter(old_prog, old_len, fp->insnsi, &new_len); | 949 | err = bpf_convert_filter(old_prog, old_len, fp->insnsi, &new_len); |
| 1443 | if (err) | 950 | if (err) |
| 1444 | /* 2nd sk_convert_filter() can fail only if it fails | 951 | /* 2nd bpf_convert_filter() can fail only if it fails |
| 1445 | * to allocate memory, remapping must succeed. Note, | 952 | * to allocate memory, remapping must succeed. Note, |
| 1446 | * that at this time old_fp has already been released | 953 | * that at this time old_fp has already been released |
| 1447 | * by __sk_migrate_realloc(). | 954 | * by krealloc(). |
| 1448 | */ | 955 | */ |
| 1449 | goto out_err_free; | 956 | goto out_err_free; |
| 1450 | 957 | ||
| 1451 | sk_filter_select_runtime(fp); | 958 | bpf_prog_select_runtime(fp); |
| 1452 | 959 | ||
| 1453 | kfree(old_prog); | 960 | kfree(old_prog); |
| 1454 | return fp; | 961 | return fp; |
| @@ -1456,55 +963,20 @@ static struct sk_filter *__sk_migrate_filter(struct sk_filter *fp, | |||
| 1456 | out_err_free: | 963 | out_err_free: |
| 1457 | kfree(old_prog); | 964 | kfree(old_prog); |
| 1458 | out_err: | 965 | out_err: |
| 1459 | /* Rollback filter setup. */ | 966 | __bpf_prog_release(fp); |
| 1460 | if (sk != NULL) | ||
| 1461 | sk_filter_uncharge(sk, fp); | ||
| 1462 | else | ||
| 1463 | kfree(fp); | ||
| 1464 | return ERR_PTR(err); | 967 | return ERR_PTR(err); |
| 1465 | } | 968 | } |
| 1466 | 969 | ||
| 1467 | void __weak bpf_int_jit_compile(struct sk_filter *prog) | 970 | static struct bpf_prog *bpf_prepare_filter(struct bpf_prog *fp) |
| 1468 | { | ||
| 1469 | } | ||
| 1470 | |||
| 1471 | /** | ||
| 1472 | * sk_filter_select_runtime - select execution runtime for BPF program | ||
| 1473 | * @fp: sk_filter populated with internal BPF program | ||
| 1474 | * | ||
| 1475 | * try to JIT internal BPF program, if JIT is not available select interpreter | ||
| 1476 | * BPF program will be executed via SK_RUN_FILTER() macro | ||
| 1477 | */ | ||
| 1478 | void sk_filter_select_runtime(struct sk_filter *fp) | ||
| 1479 | { | ||
| 1480 | fp->bpf_func = (void *) __sk_run_filter; | ||
| 1481 | |||
| 1482 | /* Probe if internal BPF can be JITed */ | ||
| 1483 | bpf_int_jit_compile(fp); | ||
| 1484 | } | ||
| 1485 | EXPORT_SYMBOL_GPL(sk_filter_select_runtime); | ||
| 1486 | |||
| 1487 | /* free internal BPF program */ | ||
| 1488 | void sk_filter_free(struct sk_filter *fp) | ||
| 1489 | { | ||
| 1490 | bpf_jit_free(fp); | ||
| 1491 | } | ||
| 1492 | EXPORT_SYMBOL_GPL(sk_filter_free); | ||
| 1493 | |||
| 1494 | static struct sk_filter *__sk_prepare_filter(struct sk_filter *fp, | ||
| 1495 | struct sock *sk) | ||
| 1496 | { | 971 | { |
| 1497 | int err; | 972 | int err; |
| 1498 | 973 | ||
| 1499 | fp->bpf_func = NULL; | 974 | fp->bpf_func = NULL; |
| 1500 | fp->jited = 0; | 975 | fp->jited = 0; |
| 1501 | 976 | ||
| 1502 | err = sk_chk_filter(fp->insns, fp->len); | 977 | err = bpf_check_classic(fp->insns, fp->len); |
| 1503 | if (err) { | 978 | if (err) { |
| 1504 | if (sk != NULL) | 979 | __bpf_prog_release(fp); |
| 1505 | sk_filter_uncharge(sk, fp); | ||
| 1506 | else | ||
| 1507 | kfree(fp); | ||
| 1508 | return ERR_PTR(err); | 980 | return ERR_PTR(err); |
| 1509 | } | 981 | } |
| 1510 | 982 | ||
| @@ -1517,13 +989,13 @@ static struct sk_filter *__sk_prepare_filter(struct sk_filter *fp, | |||
| 1517 | * internal BPF translation for the optimized interpreter. | 989 | * internal BPF translation for the optimized interpreter. |
| 1518 | */ | 990 | */ |
| 1519 | if (!fp->jited) | 991 | if (!fp->jited) |
| 1520 | fp = __sk_migrate_filter(fp, sk); | 992 | fp = bpf_migrate_filter(fp); |
| 1521 | 993 | ||
| 1522 | return fp; | 994 | return fp; |
| 1523 | } | 995 | } |
| 1524 | 996 | ||
| 1525 | /** | 997 | /** |
| 1526 | * sk_unattached_filter_create - create an unattached filter | 998 | * bpf_prog_create - create an unattached filter |
| 1527 | * @pfp: the unattached filter that is created | 999 | * @pfp: the unattached filter that is created |
| 1528 | * @fprog: the filter program | 1000 | * @fprog: the filter program |
| 1529 | * | 1001 | * |
| @@ -1532,23 +1004,21 @@ static struct sk_filter *__sk_prepare_filter(struct sk_filter *fp, | |||
| 1532 | * If an error occurs or there is insufficient memory for the filter | 1004 | * If an error occurs or there is insufficient memory for the filter |
| 1533 | * a negative errno code is returned. On success the return is zero. | 1005 | * a negative errno code is returned. On success the return is zero. |
| 1534 | */ | 1006 | */ |
| 1535 | int sk_unattached_filter_create(struct sk_filter **pfp, | 1007 | int bpf_prog_create(struct bpf_prog **pfp, struct sock_fprog_kern *fprog) |
| 1536 | struct sock_fprog_kern *fprog) | ||
| 1537 | { | 1008 | { |
| 1538 | unsigned int fsize = sk_filter_proglen(fprog); | 1009 | unsigned int fsize = bpf_classic_proglen(fprog); |
| 1539 | struct sk_filter *fp; | 1010 | struct bpf_prog *fp; |
| 1540 | 1011 | ||
| 1541 | /* Make sure new filter is there and in the right amounts. */ | 1012 | /* Make sure new filter is there and in the right amounts. */ |
| 1542 | if (fprog->filter == NULL) | 1013 | if (fprog->filter == NULL) |
| 1543 | return -EINVAL; | 1014 | return -EINVAL; |
| 1544 | 1015 | ||
| 1545 | fp = kmalloc(sk_filter_size(fprog->len), GFP_KERNEL); | 1016 | fp = kmalloc(bpf_prog_size(fprog->len), GFP_KERNEL); |
| 1546 | if (!fp) | 1017 | if (!fp) |
| 1547 | return -ENOMEM; | 1018 | return -ENOMEM; |
| 1548 | 1019 | ||
| 1549 | memcpy(fp->insns, fprog->filter, fsize); | 1020 | memcpy(fp->insns, fprog->filter, fsize); |
| 1550 | 1021 | ||
| 1551 | atomic_set(&fp->refcnt, 1); | ||
| 1552 | fp->len = fprog->len; | 1022 | fp->len = fprog->len; |
| 1553 | /* Since unattached filters are not copied back to user | 1023 | /* Since unattached filters are not copied back to user |
| 1554 | * space through sk_get_filter(), we do not need to hold | 1024 | * space through sk_get_filter(), we do not need to hold |
| @@ -1556,23 +1026,23 @@ int sk_unattached_filter_create(struct sk_filter **pfp, | |||
| 1556 | */ | 1026 | */ |
| 1557 | fp->orig_prog = NULL; | 1027 | fp->orig_prog = NULL; |
| 1558 | 1028 | ||
| 1559 | /* __sk_prepare_filter() already takes care of uncharging | 1029 | /* bpf_prepare_filter() already takes care of freeing |
| 1560 | * memory in case something goes wrong. | 1030 | * memory in case something goes wrong. |
| 1561 | */ | 1031 | */ |
| 1562 | fp = __sk_prepare_filter(fp, NULL); | 1032 | fp = bpf_prepare_filter(fp); |
| 1563 | if (IS_ERR(fp)) | 1033 | if (IS_ERR(fp)) |
| 1564 | return PTR_ERR(fp); | 1034 | return PTR_ERR(fp); |
| 1565 | 1035 | ||
| 1566 | *pfp = fp; | 1036 | *pfp = fp; |
| 1567 | return 0; | 1037 | return 0; |
| 1568 | } | 1038 | } |
| 1569 | EXPORT_SYMBOL_GPL(sk_unattached_filter_create); | 1039 | EXPORT_SYMBOL_GPL(bpf_prog_create); |
| 1570 | 1040 | ||
| 1571 | void sk_unattached_filter_destroy(struct sk_filter *fp) | 1041 | void bpf_prog_destroy(struct bpf_prog *fp) |
| 1572 | { | 1042 | { |
| 1573 | sk_filter_release(fp); | 1043 | __bpf_prog_release(fp); |
| 1574 | } | 1044 | } |
| 1575 | EXPORT_SYMBOL_GPL(sk_unattached_filter_destroy); | 1045 | EXPORT_SYMBOL_GPL(bpf_prog_destroy); |
| 1576 | 1046 | ||
| 1577 | /** | 1047 | /** |
| 1578 | * sk_attach_filter - attach a socket filter | 1048 | * sk_attach_filter - attach a socket filter |
| @@ -1587,8 +1057,9 @@ EXPORT_SYMBOL_GPL(sk_unattached_filter_destroy); | |||
| 1587 | int sk_attach_filter(struct sock_fprog *fprog, struct sock *sk) | 1057 | int sk_attach_filter(struct sock_fprog *fprog, struct sock *sk) |
| 1588 | { | 1058 | { |
| 1589 | struct sk_filter *fp, *old_fp; | 1059 | struct sk_filter *fp, *old_fp; |
| 1590 | unsigned int fsize = sk_filter_proglen(fprog); | 1060 | unsigned int fsize = bpf_classic_proglen(fprog); |
| 1591 | unsigned int sk_fsize = sk_filter_size(fprog->len); | 1061 | unsigned int bpf_fsize = bpf_prog_size(fprog->len); |
| 1062 | struct bpf_prog *prog; | ||
| 1592 | int err; | 1063 | int err; |
| 1593 | 1064 | ||
| 1594 | if (sock_flag(sk, SOCK_FILTER_LOCKED)) | 1065 | if (sock_flag(sk, SOCK_FILTER_LOCKED)) |
| @@ -1598,30 +1069,43 @@ int sk_attach_filter(struct sock_fprog *fprog, struct sock *sk) | |||
| 1598 | if (fprog->filter == NULL) | 1069 | if (fprog->filter == NULL) |
| 1599 | return -EINVAL; | 1070 | return -EINVAL; |
| 1600 | 1071 | ||
| 1601 | fp = sock_kmalloc(sk, sk_fsize, GFP_KERNEL); | 1072 | prog = kmalloc(bpf_fsize, GFP_KERNEL); |
| 1602 | if (!fp) | 1073 | if (!prog) |
| 1603 | return -ENOMEM; | 1074 | return -ENOMEM; |
| 1604 | 1075 | ||
| 1605 | if (copy_from_user(fp->insns, fprog->filter, fsize)) { | 1076 | if (copy_from_user(prog->insns, fprog->filter, fsize)) { |
| 1606 | sock_kfree_s(sk, fp, sk_fsize); | 1077 | kfree(prog); |
| 1607 | return -EFAULT; | 1078 | return -EFAULT; |
| 1608 | } | 1079 | } |
| 1609 | 1080 | ||
| 1610 | atomic_set(&fp->refcnt, 1); | 1081 | prog->len = fprog->len; |
| 1611 | fp->len = fprog->len; | ||
| 1612 | 1082 | ||
| 1613 | err = sk_store_orig_filter(fp, fprog); | 1083 | err = bpf_prog_store_orig_filter(prog, fprog); |
| 1614 | if (err) { | 1084 | if (err) { |
| 1615 | sk_filter_uncharge(sk, fp); | 1085 | kfree(prog); |
| 1616 | return -ENOMEM; | 1086 | return -ENOMEM; |
| 1617 | } | 1087 | } |
| 1618 | 1088 | ||
| 1619 | /* __sk_prepare_filter() already takes care of uncharging | 1089 | /* bpf_prepare_filter() already takes care of freeing |
| 1620 | * memory in case something goes wrong. | 1090 | * memory in case something goes wrong. |
| 1621 | */ | 1091 | */ |
| 1622 | fp = __sk_prepare_filter(fp, sk); | 1092 | prog = bpf_prepare_filter(prog); |
| 1623 | if (IS_ERR(fp)) | 1093 | if (IS_ERR(prog)) |
| 1624 | return PTR_ERR(fp); | 1094 | return PTR_ERR(prog); |
| 1095 | |||
| 1096 | fp = kmalloc(sizeof(*fp), GFP_KERNEL); | ||
| 1097 | if (!fp) { | ||
| 1098 | __bpf_prog_release(prog); | ||
| 1099 | return -ENOMEM; | ||
| 1100 | } | ||
| 1101 | fp->prog = prog; | ||
| 1102 | |||
| 1103 | atomic_set(&fp->refcnt, 0); | ||
| 1104 | |||
| 1105 | if (!sk_filter_charge(sk, fp)) { | ||
| 1106 | __sk_filter_release(fp); | ||
| 1107 | return -ENOMEM; | ||
| 1108 | } | ||
| 1625 | 1109 | ||
| 1626 | old_fp = rcu_dereference_protected(sk->sk_filter, | 1110 | old_fp = rcu_dereference_protected(sk->sk_filter, |
| 1627 | sock_owned_by_user(sk)); | 1111 | sock_owned_by_user(sk)); |
| @@ -1670,7 +1154,7 @@ int sk_get_filter(struct sock *sk, struct sock_filter __user *ubuf, | |||
| 1670 | /* We're copying the filter that has been originally attached, | 1154 | /* We're copying the filter that has been originally attached, |
| 1671 | * so no conversion/decode needed anymore. | 1155 | * so no conversion/decode needed anymore. |
| 1672 | */ | 1156 | */ |
| 1673 | fprog = filter->orig_prog; | 1157 | fprog = filter->prog->orig_prog; |
| 1674 | 1158 | ||
| 1675 | ret = fprog->len; | 1159 | ret = fprog->len; |
| 1676 | if (!len) | 1160 | if (!len) |
| @@ -1682,7 +1166,7 @@ int sk_get_filter(struct sock *sk, struct sock_filter __user *ubuf, | |||
| 1682 | goto out; | 1166 | goto out; |
| 1683 | 1167 | ||
| 1684 | ret = -EFAULT; | 1168 | ret = -EFAULT; |
| 1685 | if (copy_to_user(ubuf, fprog->filter, sk_filter_proglen(fprog))) | 1169 | if (copy_to_user(ubuf, fprog->filter, bpf_classic_proglen(fprog))) |
| 1686 | goto out; | 1170 | goto out; |
| 1687 | 1171 | ||
| 1688 | /* Instead of bytes, the API requests to return the number | 1172 | /* Instead of bytes, the API requests to return the number |
diff --git a/net/core/flow_dissector.c b/net/core/flow_dissector.c index 107ed12a5323..5f362c1d0332 100644 --- a/net/core/flow_dissector.c +++ b/net/core/flow_dissector.c | |||
| @@ -80,6 +80,8 @@ ip: | |||
| 80 | case htons(ETH_P_IPV6): { | 80 | case htons(ETH_P_IPV6): { |
| 81 | const struct ipv6hdr *iph; | 81 | const struct ipv6hdr *iph; |
| 82 | struct ipv6hdr _iph; | 82 | struct ipv6hdr _iph; |
| 83 | __be32 flow_label; | ||
| 84 | |||
| 83 | ipv6: | 85 | ipv6: |
| 84 | iph = skb_header_pointer(skb, nhoff, sizeof(_iph), &_iph); | 86 | iph = skb_header_pointer(skb, nhoff, sizeof(_iph), &_iph); |
| 85 | if (!iph) | 87 | if (!iph) |
| @@ -89,6 +91,21 @@ ipv6: | |||
| 89 | flow->src = (__force __be32)ipv6_addr_hash(&iph->saddr); | 91 | flow->src = (__force __be32)ipv6_addr_hash(&iph->saddr); |
| 90 | flow->dst = (__force __be32)ipv6_addr_hash(&iph->daddr); | 92 | flow->dst = (__force __be32)ipv6_addr_hash(&iph->daddr); |
| 91 | nhoff += sizeof(struct ipv6hdr); | 93 | nhoff += sizeof(struct ipv6hdr); |
| 94 | |||
| 95 | flow_label = ip6_flowlabel(iph); | ||
| 96 | if (flow_label) { | ||
| 97 | /* Awesome, IPv6 packet has a flow label so we can | ||
| 98 | * use that to represent the ports without any | ||
| 99 | * further dissection. | ||
| 100 | */ | ||
| 101 | flow->n_proto = proto; | ||
| 102 | flow->ip_proto = ip_proto; | ||
| 103 | flow->ports = flow_label; | ||
| 104 | flow->thoff = (u16)nhoff; | ||
| 105 | |||
| 106 | return true; | ||
| 107 | } | ||
| 108 | |||
| 92 | break; | 109 | break; |
| 93 | } | 110 | } |
| 94 | case htons(ETH_P_8021AD): | 111 | case htons(ETH_P_8021AD): |
| @@ -175,6 +192,7 @@ ipv6: | |||
| 175 | break; | 192 | break; |
| 176 | } | 193 | } |
| 177 | 194 | ||
| 195 | flow->n_proto = proto; | ||
| 178 | flow->ip_proto = ip_proto; | 196 | flow->ip_proto = ip_proto; |
| 179 | flow->ports = skb_flow_get_ports(skb, nhoff, ip_proto); | 197 | flow->ports = skb_flow_get_ports(skb, nhoff, ip_proto); |
| 180 | flow->thoff = (u16) nhoff; | 198 | flow->thoff = (u16) nhoff; |
| @@ -195,12 +213,33 @@ static __always_inline u32 __flow_hash_3words(u32 a, u32 b, u32 c) | |||
| 195 | return jhash_3words(a, b, c, hashrnd); | 213 | return jhash_3words(a, b, c, hashrnd); |
| 196 | } | 214 | } |
| 197 | 215 | ||
| 198 | static __always_inline u32 __flow_hash_1word(u32 a) | 216 | static inline u32 __flow_hash_from_keys(struct flow_keys *keys) |
| 199 | { | 217 | { |
| 200 | __flow_hash_secret_init(); | 218 | u32 hash; |
| 201 | return jhash_1word(a, hashrnd); | 219 | |
| 220 | /* get a consistent hash (same value on both flow directions) */ | ||
| 221 | if (((__force u32)keys->dst < (__force u32)keys->src) || | ||
| 222 | (((__force u32)keys->dst == (__force u32)keys->src) && | ||
| 223 | ((__force u16)keys->port16[1] < (__force u16)keys->port16[0]))) { | ||
| 224 | swap(keys->dst, keys->src); | ||
| 225 | swap(keys->port16[0], keys->port16[1]); | ||
| 226 | } | ||
| 227 | |||
| 228 | hash = __flow_hash_3words((__force u32)keys->dst, | ||
| 229 | (__force u32)keys->src, | ||
| 230 | (__force u32)keys->ports); | ||
| 231 | if (!hash) | ||
| 232 | hash = 1; | ||
| 233 | |||
| 234 | return hash; | ||
| 202 | } | 235 | } |
| 203 | 236 | ||
| 237 | u32 flow_hash_from_keys(struct flow_keys *keys) | ||
| 238 | { | ||
| 239 | return __flow_hash_from_keys(keys); | ||
| 240 | } | ||
| 241 | EXPORT_SYMBOL(flow_hash_from_keys); | ||
| 242 | |||
| 204 | /* | 243 | /* |
| 205 | * __skb_get_hash: calculate a flow hash based on src/dst addresses | 244 | * __skb_get_hash: calculate a flow hash based on src/dst addresses |
| 206 | * and src/dst port numbers. Sets hash in skb to non-zero hash value | 245 | * and src/dst port numbers. Sets hash in skb to non-zero hash value |
| @@ -210,7 +249,6 @@ static __always_inline u32 __flow_hash_1word(u32 a) | |||
| 210 | void __skb_get_hash(struct sk_buff *skb) | 249 | void __skb_get_hash(struct sk_buff *skb) |
| 211 | { | 250 | { |
| 212 | struct flow_keys keys; | 251 | struct flow_keys keys; |
| 213 | u32 hash; | ||
| 214 | 252 | ||
| 215 | if (!skb_flow_dissect(skb, &keys)) | 253 | if (!skb_flow_dissect(skb, &keys)) |
| 216 | return; | 254 | return; |
| @@ -218,21 +256,9 @@ void __skb_get_hash(struct sk_buff *skb) | |||
| 218 | if (keys.ports) | 256 | if (keys.ports) |
| 219 | skb->l4_hash = 1; | 257 | skb->l4_hash = 1; |
| 220 | 258 | ||
| 221 | /* get a consistent hash (same value on both flow directions) */ | 259 | skb->sw_hash = 1; |
| 222 | if (((__force u32)keys.dst < (__force u32)keys.src) || | ||
| 223 | (((__force u32)keys.dst == (__force u32)keys.src) && | ||
| 224 | ((__force u16)keys.port16[1] < (__force u16)keys.port16[0]))) { | ||
| 225 | swap(keys.dst, keys.src); | ||
| 226 | swap(keys.port16[0], keys.port16[1]); | ||
| 227 | } | ||
| 228 | |||
| 229 | hash = __flow_hash_3words((__force u32)keys.dst, | ||
| 230 | (__force u32)keys.src, | ||
| 231 | (__force u32)keys.ports); | ||
| 232 | if (!hash) | ||
| 233 | hash = 1; | ||
| 234 | 260 | ||
| 235 | skb->hash = hash; | 261 | skb->hash = __flow_hash_from_keys(&keys); |
| 236 | } | 262 | } |
| 237 | EXPORT_SYMBOL(__skb_get_hash); | 263 | EXPORT_SYMBOL(__skb_get_hash); |
| 238 | 264 | ||
| @@ -240,7 +266,7 @@ EXPORT_SYMBOL(__skb_get_hash); | |||
| 240 | * Returns a Tx hash based on the given packet descriptor a Tx queues' number | 266 | * Returns a Tx hash based on the given packet descriptor a Tx queues' number |
| 241 | * to be used as a distribution range. | 267 | * to be used as a distribution range. |
| 242 | */ | 268 | */ |
| 243 | u16 __skb_tx_hash(const struct net_device *dev, const struct sk_buff *skb, | 269 | u16 __skb_tx_hash(const struct net_device *dev, struct sk_buff *skb, |
| 244 | unsigned int num_tx_queues) | 270 | unsigned int num_tx_queues) |
| 245 | { | 271 | { |
| 246 | u32 hash; | 272 | u32 hash; |
| @@ -260,13 +286,7 @@ u16 __skb_tx_hash(const struct net_device *dev, const struct sk_buff *skb, | |||
| 260 | qcount = dev->tc_to_txq[tc].count; | 286 | qcount = dev->tc_to_txq[tc].count; |
| 261 | } | 287 | } |
| 262 | 288 | ||
| 263 | if (skb->sk && skb->sk->sk_hash) | 289 | return (u16) (((u64)skb_get_hash(skb) * qcount) >> 32) + qoffset; |
| 264 | hash = skb->sk->sk_hash; | ||
| 265 | else | ||
| 266 | hash = (__force u16) skb->protocol; | ||
| 267 | hash = __flow_hash_1word(hash); | ||
| 268 | |||
| 269 | return (u16) (((u64) hash * qcount) >> 32) + qoffset; | ||
| 270 | } | 290 | } |
| 271 | EXPORT_SYMBOL(__skb_tx_hash); | 291 | EXPORT_SYMBOL(__skb_tx_hash); |
| 272 | 292 | ||
| @@ -338,17 +358,10 @@ static inline int get_xps_queue(struct net_device *dev, struct sk_buff *skb) | |||
| 338 | if (map) { | 358 | if (map) { |
| 339 | if (map->len == 1) | 359 | if (map->len == 1) |
| 340 | queue_index = map->queues[0]; | 360 | queue_index = map->queues[0]; |
| 341 | else { | 361 | else |
| 342 | u32 hash; | ||
| 343 | if (skb->sk && skb->sk->sk_hash) | ||
| 344 | hash = skb->sk->sk_hash; | ||
| 345 | else | ||
| 346 | hash = (__force u16) skb->protocol ^ | ||
| 347 | skb->hash; | ||
| 348 | hash = __flow_hash_1word(hash); | ||
| 349 | queue_index = map->queues[ | 362 | queue_index = map->queues[ |
| 350 | ((u64)hash * map->len) >> 32]; | 363 | ((u64)skb_get_hash(skb) * map->len) >> 32]; |
| 351 | } | 364 | |
| 352 | if (unlikely(queue_index >= dev->real_num_tx_queues)) | 365 | if (unlikely(queue_index >= dev->real_num_tx_queues)) |
| 353 | queue_index = -1; | 366 | queue_index = -1; |
| 354 | } | 367 | } |
diff --git a/net/core/net-sysfs.c b/net/core/net-sysfs.c index 1cac29ebb05b..9dd06699b09c 100644 --- a/net/core/net-sysfs.c +++ b/net/core/net-sysfs.c | |||
| @@ -43,12 +43,12 @@ static ssize_t netdev_show(const struct device *dev, | |||
| 43 | struct device_attribute *attr, char *buf, | 43 | struct device_attribute *attr, char *buf, |
| 44 | ssize_t (*format)(const struct net_device *, char *)) | 44 | ssize_t (*format)(const struct net_device *, char *)) |
| 45 | { | 45 | { |
| 46 | struct net_device *net = to_net_dev(dev); | 46 | struct net_device *ndev = to_net_dev(dev); |
| 47 | ssize_t ret = -EINVAL; | 47 | ssize_t ret = -EINVAL; |
| 48 | 48 | ||
| 49 | read_lock(&dev_base_lock); | 49 | read_lock(&dev_base_lock); |
| 50 | if (dev_isalive(net)) | 50 | if (dev_isalive(ndev)) |
| 51 | ret = (*format)(net, buf); | 51 | ret = (*format)(ndev, buf); |
| 52 | read_unlock(&dev_base_lock); | 52 | read_unlock(&dev_base_lock); |
| 53 | 53 | ||
| 54 | return ret; | 54 | return ret; |
| @@ -56,9 +56,9 @@ static ssize_t netdev_show(const struct device *dev, | |||
| 56 | 56 | ||
| 57 | /* generate a show function for simple field */ | 57 | /* generate a show function for simple field */ |
| 58 | #define NETDEVICE_SHOW(field, format_string) \ | 58 | #define NETDEVICE_SHOW(field, format_string) \ |
| 59 | static ssize_t format_##field(const struct net_device *net, char *buf) \ | 59 | static ssize_t format_##field(const struct net_device *dev, char *buf) \ |
| 60 | { \ | 60 | { \ |
| 61 | return sprintf(buf, format_string, net->field); \ | 61 | return sprintf(buf, format_string, dev->field); \ |
| 62 | } \ | 62 | } \ |
| 63 | static ssize_t field##_show(struct device *dev, \ | 63 | static ssize_t field##_show(struct device *dev, \ |
| 64 | struct device_attribute *attr, char *buf) \ | 64 | struct device_attribute *attr, char *buf) \ |
| @@ -112,16 +112,35 @@ NETDEVICE_SHOW_RO(ifindex, fmt_dec); | |||
| 112 | NETDEVICE_SHOW_RO(type, fmt_dec); | 112 | NETDEVICE_SHOW_RO(type, fmt_dec); |
| 113 | NETDEVICE_SHOW_RO(link_mode, fmt_dec); | 113 | NETDEVICE_SHOW_RO(link_mode, fmt_dec); |
| 114 | 114 | ||
| 115 | static ssize_t format_name_assign_type(const struct net_device *dev, char *buf) | ||
| 116 | { | ||
| 117 | return sprintf(buf, fmt_dec, dev->name_assign_type); | ||
| 118 | } | ||
| 119 | |||
| 120 | static ssize_t name_assign_type_show(struct device *dev, | ||
| 121 | struct device_attribute *attr, | ||
| 122 | char *buf) | ||
| 123 | { | ||
| 124 | struct net_device *ndev = to_net_dev(dev); | ||
| 125 | ssize_t ret = -EINVAL; | ||
| 126 | |||
| 127 | if (ndev->name_assign_type != NET_NAME_UNKNOWN) | ||
| 128 | ret = netdev_show(dev, attr, buf, format_name_assign_type); | ||
| 129 | |||
| 130 | return ret; | ||
| 131 | } | ||
| 132 | static DEVICE_ATTR_RO(name_assign_type); | ||
| 133 | |||
| 115 | /* use same locking rules as GIFHWADDR ioctl's */ | 134 | /* use same locking rules as GIFHWADDR ioctl's */ |
| 116 | static ssize_t address_show(struct device *dev, struct device_attribute *attr, | 135 | static ssize_t address_show(struct device *dev, struct device_attribute *attr, |
| 117 | char *buf) | 136 | char *buf) |
| 118 | { | 137 | { |
| 119 | struct net_device *net = to_net_dev(dev); | 138 | struct net_device *ndev = to_net_dev(dev); |
| 120 | ssize_t ret = -EINVAL; | 139 | ssize_t ret = -EINVAL; |
| 121 | 140 | ||
| 122 | read_lock(&dev_base_lock); | 141 | read_lock(&dev_base_lock); |
| 123 | if (dev_isalive(net)) | 142 | if (dev_isalive(ndev)) |
| 124 | ret = sysfs_format_mac(buf, net->dev_addr, net->addr_len); | 143 | ret = sysfs_format_mac(buf, ndev->dev_addr, ndev->addr_len); |
| 125 | read_unlock(&dev_base_lock); | 144 | read_unlock(&dev_base_lock); |
| 126 | return ret; | 145 | return ret; |
| 127 | } | 146 | } |
| @@ -130,18 +149,18 @@ static DEVICE_ATTR_RO(address); | |||
| 130 | static ssize_t broadcast_show(struct device *dev, | 149 | static ssize_t broadcast_show(struct device *dev, |
| 131 | struct device_attribute *attr, char *buf) | 150 | struct device_attribute *attr, char *buf) |
| 132 | { | 151 | { |
| 133 | struct net_device *net = to_net_dev(dev); | 152 | struct net_device *ndev = to_net_dev(dev); |
| 134 | if (dev_isalive(net)) | 153 | if (dev_isalive(ndev)) |
| 135 | return sysfs_format_mac(buf, net->broadcast, net->addr_len); | 154 | return sysfs_format_mac(buf, ndev->broadcast, ndev->addr_len); |
| 136 | return -EINVAL; | 155 | return -EINVAL; |
| 137 | } | 156 | } |
| 138 | static DEVICE_ATTR_RO(broadcast); | 157 | static DEVICE_ATTR_RO(broadcast); |
| 139 | 158 | ||
| 140 | static int change_carrier(struct net_device *net, unsigned long new_carrier) | 159 | static int change_carrier(struct net_device *dev, unsigned long new_carrier) |
| 141 | { | 160 | { |
| 142 | if (!netif_running(net)) | 161 | if (!netif_running(dev)) |
| 143 | return -EINVAL; | 162 | return -EINVAL; |
| 144 | return dev_change_carrier(net, (bool) new_carrier); | 163 | return dev_change_carrier(dev, (bool) new_carrier); |
| 145 | } | 164 | } |
| 146 | 165 | ||
| 147 | static ssize_t carrier_store(struct device *dev, struct device_attribute *attr, | 166 | static ssize_t carrier_store(struct device *dev, struct device_attribute *attr, |
| @@ -265,9 +284,9 @@ static DEVICE_ATTR_RO(carrier_changes); | |||
| 265 | 284 | ||
| 266 | /* read-write attributes */ | 285 | /* read-write attributes */ |
| 267 | 286 | ||
| 268 | static int change_mtu(struct net_device *net, unsigned long new_mtu) | 287 | static int change_mtu(struct net_device *dev, unsigned long new_mtu) |
| 269 | { | 288 | { |
| 270 | return dev_set_mtu(net, (int) new_mtu); | 289 | return dev_set_mtu(dev, (int) new_mtu); |
| 271 | } | 290 | } |
| 272 | 291 | ||
| 273 | static ssize_t mtu_store(struct device *dev, struct device_attribute *attr, | 292 | static ssize_t mtu_store(struct device *dev, struct device_attribute *attr, |
| @@ -277,9 +296,9 @@ static ssize_t mtu_store(struct device *dev, struct device_attribute *attr, | |||
| 277 | } | 296 | } |
| 278 | NETDEVICE_SHOW_RW(mtu, fmt_dec); | 297 | NETDEVICE_SHOW_RW(mtu, fmt_dec); |
| 279 | 298 | ||
| 280 | static int change_flags(struct net_device *net, unsigned long new_flags) | 299 | static int change_flags(struct net_device *dev, unsigned long new_flags) |
| 281 | { | 300 | { |
| 282 | return dev_change_flags(net, (unsigned int) new_flags); | 301 | return dev_change_flags(dev, (unsigned int) new_flags); |
| 283 | } | 302 | } |
| 284 | 303 | ||
| 285 | static ssize_t flags_store(struct device *dev, struct device_attribute *attr, | 304 | static ssize_t flags_store(struct device *dev, struct device_attribute *attr, |
| @@ -289,9 +308,9 @@ static ssize_t flags_store(struct device *dev, struct device_attribute *attr, | |||
| 289 | } | 308 | } |
| 290 | NETDEVICE_SHOW_RW(flags, fmt_hex); | 309 | NETDEVICE_SHOW_RW(flags, fmt_hex); |
| 291 | 310 | ||
| 292 | static int change_tx_queue_len(struct net_device *net, unsigned long new_len) | 311 | static int change_tx_queue_len(struct net_device *dev, unsigned long new_len) |
| 293 | { | 312 | { |
| 294 | net->tx_queue_len = new_len; | 313 | dev->tx_queue_len = new_len; |
| 295 | return 0; | 314 | return 0; |
| 296 | } | 315 | } |
| 297 | 316 | ||
| @@ -344,9 +363,9 @@ static ssize_t ifalias_show(struct device *dev, | |||
| 344 | } | 363 | } |
| 345 | static DEVICE_ATTR_RW(ifalias); | 364 | static DEVICE_ATTR_RW(ifalias); |
| 346 | 365 | ||
| 347 | static int change_group(struct net_device *net, unsigned long new_group) | 366 | static int change_group(struct net_device *dev, unsigned long new_group) |
| 348 | { | 367 | { |
| 349 | dev_set_group(net, (int) new_group); | 368 | dev_set_group(dev, (int) new_group); |
| 350 | return 0; | 369 | return 0; |
| 351 | } | 370 | } |
| 352 | 371 | ||
| @@ -387,6 +406,7 @@ static struct attribute *net_class_attrs[] = { | |||
| 387 | &dev_attr_dev_port.attr, | 406 | &dev_attr_dev_port.attr, |
| 388 | &dev_attr_iflink.attr, | 407 | &dev_attr_iflink.attr, |
| 389 | &dev_attr_ifindex.attr, | 408 | &dev_attr_ifindex.attr, |
| 409 | &dev_attr_name_assign_type.attr, | ||
| 390 | &dev_attr_addr_assign_type.attr, | 410 | &dev_attr_addr_assign_type.attr, |
| 391 | &dev_attr_addr_len.attr, | 411 | &dev_attr_addr_len.attr, |
| 392 | &dev_attr_link_mode.attr, | 412 | &dev_attr_link_mode.attr, |
| @@ -776,20 +796,20 @@ static struct kobj_type rx_queue_ktype = { | |||
| 776 | .namespace = rx_queue_namespace | 796 | .namespace = rx_queue_namespace |
| 777 | }; | 797 | }; |
| 778 | 798 | ||
| 779 | static int rx_queue_add_kobject(struct net_device *net, int index) | 799 | static int rx_queue_add_kobject(struct net_device *dev, int index) |
| 780 | { | 800 | { |
| 781 | struct netdev_rx_queue *queue = net->_rx + index; | 801 | struct netdev_rx_queue *queue = dev->_rx + index; |
| 782 | struct kobject *kobj = &queue->kobj; | 802 | struct kobject *kobj = &queue->kobj; |
| 783 | int error = 0; | 803 | int error = 0; |
| 784 | 804 | ||
| 785 | kobj->kset = net->queues_kset; | 805 | kobj->kset = dev->queues_kset; |
| 786 | error = kobject_init_and_add(kobj, &rx_queue_ktype, NULL, | 806 | error = kobject_init_and_add(kobj, &rx_queue_ktype, NULL, |
| 787 | "rx-%u", index); | 807 | "rx-%u", index); |
| 788 | if (error) | 808 | if (error) |
| 789 | goto exit; | 809 | goto exit; |
| 790 | 810 | ||
| 791 | if (net->sysfs_rx_queue_group) { | 811 | if (dev->sysfs_rx_queue_group) { |
| 792 | error = sysfs_create_group(kobj, net->sysfs_rx_queue_group); | 812 | error = sysfs_create_group(kobj, dev->sysfs_rx_queue_group); |
| 793 | if (error) | 813 | if (error) |
| 794 | goto exit; | 814 | goto exit; |
| 795 | } | 815 | } |
| @@ -805,18 +825,18 @@ exit: | |||
| 805 | #endif /* CONFIG_SYSFS */ | 825 | #endif /* CONFIG_SYSFS */ |
| 806 | 826 | ||
| 807 | int | 827 | int |
| 808 | net_rx_queue_update_kobjects(struct net_device *net, int old_num, int new_num) | 828 | net_rx_queue_update_kobjects(struct net_device *dev, int old_num, int new_num) |
| 809 | { | 829 | { |
| 810 | #ifdef CONFIG_SYSFS | 830 | #ifdef CONFIG_SYSFS |
| 811 | int i; | 831 | int i; |
| 812 | int error = 0; | 832 | int error = 0; |
| 813 | 833 | ||
| 814 | #ifndef CONFIG_RPS | 834 | #ifndef CONFIG_RPS |
| 815 | if (!net->sysfs_rx_queue_group) | 835 | if (!dev->sysfs_rx_queue_group) |
| 816 | return 0; | 836 | return 0; |
| 817 | #endif | 837 | #endif |
| 818 | for (i = old_num; i < new_num; i++) { | 838 | for (i = old_num; i < new_num; i++) { |
| 819 | error = rx_queue_add_kobject(net, i); | 839 | error = rx_queue_add_kobject(dev, i); |
| 820 | if (error) { | 840 | if (error) { |
| 821 | new_num = old_num; | 841 | new_num = old_num; |
| 822 | break; | 842 | break; |
| @@ -824,10 +844,10 @@ net_rx_queue_update_kobjects(struct net_device *net, int old_num, int new_num) | |||
| 824 | } | 844 | } |
| 825 | 845 | ||
| 826 | while (--i >= new_num) { | 846 | while (--i >= new_num) { |
| 827 | if (net->sysfs_rx_queue_group) | 847 | if (dev->sysfs_rx_queue_group) |
| 828 | sysfs_remove_group(&net->_rx[i].kobj, | 848 | sysfs_remove_group(&dev->_rx[i].kobj, |
| 829 | net->sysfs_rx_queue_group); | 849 | dev->sysfs_rx_queue_group); |
| 830 | kobject_put(&net->_rx[i].kobj); | 850 | kobject_put(&dev->_rx[i].kobj); |
| 831 | } | 851 | } |
| 832 | 852 | ||
| 833 | return error; | 853 | return error; |
| @@ -1135,13 +1155,13 @@ static struct kobj_type netdev_queue_ktype = { | |||
| 1135 | .namespace = netdev_queue_namespace, | 1155 | .namespace = netdev_queue_namespace, |
| 1136 | }; | 1156 | }; |
| 1137 | 1157 | ||
| 1138 | static int netdev_queue_add_kobject(struct net_device *net, int index) | 1158 | static int netdev_queue_add_kobject(struct net_device *dev, int index) |
| 1139 | { | 1159 | { |
| 1140 | struct netdev_queue *queue = net->_tx + index; | 1160 | struct netdev_queue *queue = dev->_tx + index; |
| 1141 | struct kobject *kobj = &queue->kobj; | 1161 | struct kobject *kobj = &queue->kobj; |
| 1142 | int error = 0; | 1162 | int error = 0; |
| 1143 | 1163 | ||
| 1144 | kobj->kset = net->queues_kset; | 1164 | kobj->kset = dev->queues_kset; |
| 1145 | error = kobject_init_and_add(kobj, &netdev_queue_ktype, NULL, | 1165 | error = kobject_init_and_add(kobj, &netdev_queue_ktype, NULL, |
| 1146 | "tx-%u", index); | 1166 | "tx-%u", index); |
| 1147 | if (error) | 1167 | if (error) |
| @@ -1164,14 +1184,14 @@ exit: | |||
| 1164 | #endif /* CONFIG_SYSFS */ | 1184 | #endif /* CONFIG_SYSFS */ |
| 1165 | 1185 | ||
| 1166 | int | 1186 | int |
| 1167 | netdev_queue_update_kobjects(struct net_device *net, int old_num, int new_num) | 1187 | netdev_queue_update_kobjects(struct net_device *dev, int old_num, int new_num) |
| 1168 | { | 1188 | { |
| 1169 | #ifdef CONFIG_SYSFS | 1189 | #ifdef CONFIG_SYSFS |
| 1170 | int i; | 1190 | int i; |
| 1171 | int error = 0; | 1191 | int error = 0; |
| 1172 | 1192 | ||
| 1173 | for (i = old_num; i < new_num; i++) { | 1193 | for (i = old_num; i < new_num; i++) { |
| 1174 | error = netdev_queue_add_kobject(net, i); | 1194 | error = netdev_queue_add_kobject(dev, i); |
| 1175 | if (error) { | 1195 | if (error) { |
| 1176 | new_num = old_num; | 1196 | new_num = old_num; |
| 1177 | break; | 1197 | break; |
| @@ -1179,7 +1199,7 @@ netdev_queue_update_kobjects(struct net_device *net, int old_num, int new_num) | |||
| 1179 | } | 1199 | } |
| 1180 | 1200 | ||
| 1181 | while (--i >= new_num) { | 1201 | while (--i >= new_num) { |
| 1182 | struct netdev_queue *queue = net->_tx + i; | 1202 | struct netdev_queue *queue = dev->_tx + i; |
| 1183 | 1203 | ||
| 1184 | #ifdef CONFIG_BQL | 1204 | #ifdef CONFIG_BQL |
| 1185 | sysfs_remove_group(&queue->kobj, &dql_group); | 1205 | sysfs_remove_group(&queue->kobj, &dql_group); |
| @@ -1193,25 +1213,25 @@ netdev_queue_update_kobjects(struct net_device *net, int old_num, int new_num) | |||
| 1193 | #endif /* CONFIG_SYSFS */ | 1213 | #endif /* CONFIG_SYSFS */ |
| 1194 | } | 1214 | } |
| 1195 | 1215 | ||
| 1196 | static int register_queue_kobjects(struct net_device *net) | 1216 | static int register_queue_kobjects(struct net_device *dev) |
| 1197 | { | 1217 | { |
| 1198 | int error = 0, txq = 0, rxq = 0, real_rx = 0, real_tx = 0; | 1218 | int error = 0, txq = 0, rxq = 0, real_rx = 0, real_tx = 0; |
| 1199 | 1219 | ||
| 1200 | #ifdef CONFIG_SYSFS | 1220 | #ifdef CONFIG_SYSFS |
| 1201 | net->queues_kset = kset_create_and_add("queues", | 1221 | dev->queues_kset = kset_create_and_add("queues", |
| 1202 | NULL, &net->dev.kobj); | 1222 | NULL, &dev->dev.kobj); |
| 1203 | if (!net->queues_kset) | 1223 | if (!dev->queues_kset) |
| 1204 | return -ENOMEM; | 1224 | return -ENOMEM; |
| 1205 | real_rx = net->real_num_rx_queues; | 1225 | real_rx = dev->real_num_rx_queues; |
| 1206 | #endif | 1226 | #endif |
| 1207 | real_tx = net->real_num_tx_queues; | 1227 | real_tx = dev->real_num_tx_queues; |
| 1208 | 1228 | ||
| 1209 | error = net_rx_queue_update_kobjects(net, 0, real_rx); | 1229 | error = net_rx_queue_update_kobjects(dev, 0, real_rx); |
| 1210 | if (error) | 1230 | if (error) |
| 1211 | goto error; | 1231 | goto error; |
| 1212 | rxq = real_rx; | 1232 | rxq = real_rx; |
| 1213 | 1233 | ||
| 1214 | error = netdev_queue_update_kobjects(net, 0, real_tx); | 1234 | error = netdev_queue_update_kobjects(dev, 0, real_tx); |
| 1215 | if (error) | 1235 | if (error) |
| 1216 | goto error; | 1236 | goto error; |
| 1217 | txq = real_tx; | 1237 | txq = real_tx; |
| @@ -1219,24 +1239,24 @@ static int register_queue_kobjects(struct net_device *net) | |||
| 1219 | return 0; | 1239 | return 0; |
| 1220 | 1240 | ||
| 1221 | error: | 1241 | error: |
| 1222 | netdev_queue_update_kobjects(net, txq, 0); | 1242 | netdev_queue_update_kobjects(dev, txq, 0); |
| 1223 | net_rx_queue_update_kobjects(net, rxq, 0); | 1243 | net_rx_queue_update_kobjects(dev, rxq, 0); |
| 1224 | return error; | 1244 | return error; |
| 1225 | } | 1245 | } |
| 1226 | 1246 | ||
| 1227 | static void remove_queue_kobjects(struct net_device *net) | 1247 | static void remove_queue_kobjects(struct net_device *dev) |
| 1228 | { | 1248 | { |
| 1229 | int real_rx = 0, real_tx = 0; | 1249 | int real_rx = 0, real_tx = 0; |
| 1230 | 1250 | ||
| 1231 | #ifdef CONFIG_SYSFS | 1251 | #ifdef CONFIG_SYSFS |
| 1232 | real_rx = net->real_num_rx_queues; | 1252 | real_rx = dev->real_num_rx_queues; |
| 1233 | #endif | 1253 | #endif |
| 1234 | real_tx = net->real_num_tx_queues; | 1254 | real_tx = dev->real_num_tx_queues; |
| 1235 | 1255 | ||
| 1236 | net_rx_queue_update_kobjects(net, real_rx, 0); | 1256 | net_rx_queue_update_kobjects(dev, real_rx, 0); |
| 1237 | netdev_queue_update_kobjects(net, real_tx, 0); | 1257 | netdev_queue_update_kobjects(dev, real_tx, 0); |
| 1238 | #ifdef CONFIG_SYSFS | 1258 | #ifdef CONFIG_SYSFS |
| 1239 | kset_unregister(net->queues_kset); | 1259 | kset_unregister(dev->queues_kset); |
| 1240 | #endif | 1260 | #endif |
| 1241 | } | 1261 | } |
| 1242 | 1262 | ||
| @@ -1329,13 +1349,13 @@ static struct class net_class = { | |||
| 1329 | /* Delete sysfs entries but hold kobject reference until after all | 1349 | /* Delete sysfs entries but hold kobject reference until after all |
| 1330 | * netdev references are gone. | 1350 | * netdev references are gone. |
| 1331 | */ | 1351 | */ |
| 1332 | void netdev_unregister_kobject(struct net_device * net) | 1352 | void netdev_unregister_kobject(struct net_device *ndev) |
| 1333 | { | 1353 | { |
| 1334 | struct device *dev = &(net->dev); | 1354 | struct device *dev = &(ndev->dev); |
| 1335 | 1355 | ||
| 1336 | kobject_get(&dev->kobj); | 1356 | kobject_get(&dev->kobj); |
| 1337 | 1357 | ||
| 1338 | remove_queue_kobjects(net); | 1358 | remove_queue_kobjects(ndev); |
| 1339 | 1359 | ||
| 1340 | pm_runtime_set_memalloc_noio(dev, false); | 1360 | pm_runtime_set_memalloc_noio(dev, false); |
| 1341 | 1361 | ||
| @@ -1343,18 +1363,18 @@ void netdev_unregister_kobject(struct net_device * net) | |||
| 1343 | } | 1363 | } |
| 1344 | 1364 | ||
| 1345 | /* Create sysfs entries for network device. */ | 1365 | /* Create sysfs entries for network device. */ |
| 1346 | int netdev_register_kobject(struct net_device *net) | 1366 | int netdev_register_kobject(struct net_device *ndev) |
| 1347 | { | 1367 | { |
| 1348 | struct device *dev = &(net->dev); | 1368 | struct device *dev = &(ndev->dev); |
| 1349 | const struct attribute_group **groups = net->sysfs_groups; | 1369 | const struct attribute_group **groups = ndev->sysfs_groups; |
| 1350 | int error = 0; | 1370 | int error = 0; |
| 1351 | 1371 | ||
| 1352 | device_initialize(dev); | 1372 | device_initialize(dev); |
| 1353 | dev->class = &net_class; | 1373 | dev->class = &net_class; |
| 1354 | dev->platform_data = net; | 1374 | dev->platform_data = ndev; |
| 1355 | dev->groups = groups; | 1375 | dev->groups = groups; |
| 1356 | 1376 | ||
| 1357 | dev_set_name(dev, "%s", net->name); | 1377 | dev_set_name(dev, "%s", ndev->name); |
| 1358 | 1378 | ||
| 1359 | #ifdef CONFIG_SYSFS | 1379 | #ifdef CONFIG_SYSFS |
| 1360 | /* Allow for a device specific group */ | 1380 | /* Allow for a device specific group */ |
| @@ -1364,10 +1384,10 @@ int netdev_register_kobject(struct net_device *net) | |||
| 1364 | *groups++ = &netstat_group; | 1384 | *groups++ = &netstat_group; |
| 1365 | 1385 | ||
| 1366 | #if IS_ENABLED(CONFIG_WIRELESS_EXT) || IS_ENABLED(CONFIG_CFG80211) | 1386 | #if IS_ENABLED(CONFIG_WIRELESS_EXT) || IS_ENABLED(CONFIG_CFG80211) |
| 1367 | if (net->ieee80211_ptr) | 1387 | if (ndev->ieee80211_ptr) |
| 1368 | *groups++ = &wireless_group; | 1388 | *groups++ = &wireless_group; |
| 1369 | #if IS_ENABLED(CONFIG_WIRELESS_EXT) | 1389 | #if IS_ENABLED(CONFIG_WIRELESS_EXT) |
| 1370 | else if (net->wireless_handlers) | 1390 | else if (ndev->wireless_handlers) |
| 1371 | *groups++ = &wireless_group; | 1391 | *groups++ = &wireless_group; |
| 1372 | #endif | 1392 | #endif |
| 1373 | #endif | 1393 | #endif |
| @@ -1377,7 +1397,7 @@ int netdev_register_kobject(struct net_device *net) | |||
| 1377 | if (error) | 1397 | if (error) |
| 1378 | return error; | 1398 | return error; |
| 1379 | 1399 | ||
| 1380 | error = register_queue_kobjects(net); | 1400 | error = register_queue_kobjects(ndev); |
| 1381 | if (error) { | 1401 | if (error) { |
| 1382 | device_del(dev); | 1402 | device_del(dev); |
| 1383 | return error; | 1403 | return error; |
diff --git a/net/core/net_namespace.c b/net/core/net_namespace.c index 85b62691f4f2..7c6b51a58968 100644 --- a/net/core/net_namespace.c +++ b/net/core/net_namespace.c | |||
| @@ -373,9 +373,11 @@ struct net *get_net_ns_by_pid(pid_t pid) | |||
| 373 | tsk = find_task_by_vpid(pid); | 373 | tsk = find_task_by_vpid(pid); |
| 374 | if (tsk) { | 374 | if (tsk) { |
| 375 | struct nsproxy *nsproxy; | 375 | struct nsproxy *nsproxy; |
| 376 | nsproxy = task_nsproxy(tsk); | 376 | task_lock(tsk); |
| 377 | nsproxy = tsk->nsproxy; | ||
| 377 | if (nsproxy) | 378 | if (nsproxy) |
| 378 | net = get_net(nsproxy->net_ns); | 379 | net = get_net(nsproxy->net_ns); |
| 380 | task_unlock(tsk); | ||
| 379 | } | 381 | } |
| 380 | rcu_read_unlock(); | 382 | rcu_read_unlock(); |
| 381 | return net; | 383 | return net; |
| @@ -632,11 +634,11 @@ static void *netns_get(struct task_struct *task) | |||
| 632 | struct net *net = NULL; | 634 | struct net *net = NULL; |
| 633 | struct nsproxy *nsproxy; | 635 | struct nsproxy *nsproxy; |
| 634 | 636 | ||
| 635 | rcu_read_lock(); | 637 | task_lock(task); |
| 636 | nsproxy = task_nsproxy(task); | 638 | nsproxy = task->nsproxy; |
| 637 | if (nsproxy) | 639 | if (nsproxy) |
| 638 | net = get_net(nsproxy->net_ns); | 640 | net = get_net(nsproxy->net_ns); |
| 639 | rcu_read_unlock(); | 641 | task_unlock(task); |
| 640 | 642 | ||
| 641 | return net; | 643 | return net; |
| 642 | } | 644 | } |
diff --git a/net/core/netclassid_cgroup.c b/net/core/netclassid_cgroup.c index 30d903b19c62..1f2a126f4ffa 100644 --- a/net/core/netclassid_cgroup.c +++ b/net/core/netclassid_cgroup.c | |||
| @@ -107,5 +107,5 @@ struct cgroup_subsys net_cls_cgrp_subsys = { | |||
| 107 | .css_online = cgrp_css_online, | 107 | .css_online = cgrp_css_online, |
| 108 | .css_free = cgrp_css_free, | 108 | .css_free = cgrp_css_free, |
| 109 | .attach = cgrp_attach, | 109 | .attach = cgrp_attach, |
| 110 | .base_cftypes = ss_files, | 110 | .legacy_cftypes = ss_files, |
| 111 | }; | 111 | }; |
diff --git a/net/core/netpoll.c b/net/core/netpoll.c index e33937fb32a0..907fb5e36c02 100644 --- a/net/core/netpoll.c +++ b/net/core/netpoll.c | |||
| @@ -822,7 +822,8 @@ void __netpoll_cleanup(struct netpoll *np) | |||
| 822 | 822 | ||
| 823 | RCU_INIT_POINTER(np->dev->npinfo, NULL); | 823 | RCU_INIT_POINTER(np->dev->npinfo, NULL); |
| 824 | call_rcu_bh(&npinfo->rcu, rcu_cleanup_netpoll_info); | 824 | call_rcu_bh(&npinfo->rcu, rcu_cleanup_netpoll_info); |
| 825 | } | 825 | } else |
| 826 | RCU_INIT_POINTER(np->dev->npinfo, NULL); | ||
| 826 | } | 827 | } |
| 827 | EXPORT_SYMBOL_GPL(__netpoll_cleanup); | 828 | EXPORT_SYMBOL_GPL(__netpoll_cleanup); |
| 828 | 829 | ||
diff --git a/net/core/netprio_cgroup.c b/net/core/netprio_cgroup.c index 2f385b9bccc0..cbd0a199bf52 100644 --- a/net/core/netprio_cgroup.c +++ b/net/core/netprio_cgroup.c | |||
| @@ -249,7 +249,7 @@ struct cgroup_subsys net_prio_cgrp_subsys = { | |||
| 249 | .css_online = cgrp_css_online, | 249 | .css_online = cgrp_css_online, |
| 250 | .css_free = cgrp_css_free, | 250 | .css_free = cgrp_css_free, |
| 251 | .attach = net_prio_attach, | 251 | .attach = net_prio_attach, |
| 252 | .base_cftypes = ss_files, | 252 | .legacy_cftypes = ss_files, |
| 253 | }; | 253 | }; |
| 254 | 254 | ||
| 255 | static int netprio_device_event(struct notifier_block *unused, | 255 | static int netprio_device_event(struct notifier_block *unused, |
diff --git a/net/core/pktgen.c b/net/core/pktgen.c index fc17a9d309ac..8b849ddfef2e 100644 --- a/net/core/pktgen.c +++ b/net/core/pktgen.c | |||
| @@ -69,8 +69,9 @@ | |||
| 69 | * for running devices in the if_list and sends packets until count is 0 it | 69 | * for running devices in the if_list and sends packets until count is 0 it |
| 70 | * also the thread checks the thread->control which is used for inter-process | 70 | * also the thread checks the thread->control which is used for inter-process |
| 71 | * communication. controlling process "posts" operations to the threads this | 71 | * communication. controlling process "posts" operations to the threads this |
| 72 | * way. The if_lock should be possible to remove when add/rem_device is merged | 72 | * way. |
| 73 | * into this too. | 73 | * The if_list is RCU protected, and the if_lock remains to protect updating |
| 74 | * of if_list, from "add_device" as it invoked from userspace (via proc write). | ||
| 74 | * | 75 | * |
| 75 | * By design there should only be *one* "controlling" process. In practice | 76 | * By design there should only be *one* "controlling" process. In practice |
| 76 | * multiple write accesses gives unpredictable result. Understood by "write" | 77 | * multiple write accesses gives unpredictable result. Understood by "write" |
| @@ -208,7 +209,7 @@ | |||
| 208 | #define T_REMDEVALL (1<<2) /* Remove all devs */ | 209 | #define T_REMDEVALL (1<<2) /* Remove all devs */ |
| 209 | #define T_REMDEV (1<<3) /* Remove one dev */ | 210 | #define T_REMDEV (1<<3) /* Remove one dev */ |
| 210 | 211 | ||
| 211 | /* If lock -- can be removed after some work */ | 212 | /* If lock -- protects updating of if_list */ |
| 212 | #define if_lock(t) spin_lock(&(t->if_lock)); | 213 | #define if_lock(t) spin_lock(&(t->if_lock)); |
| 213 | #define if_unlock(t) spin_unlock(&(t->if_lock)); | 214 | #define if_unlock(t) spin_unlock(&(t->if_lock)); |
| 214 | 215 | ||
| @@ -241,6 +242,7 @@ struct pktgen_dev { | |||
| 241 | struct proc_dir_entry *entry; /* proc file */ | 242 | struct proc_dir_entry *entry; /* proc file */ |
| 242 | struct pktgen_thread *pg_thread;/* the owner */ | 243 | struct pktgen_thread *pg_thread;/* the owner */ |
| 243 | struct list_head list; /* chaining in the thread's run-queue */ | 244 | struct list_head list; /* chaining in the thread's run-queue */ |
| 245 | struct rcu_head rcu; /* freed by RCU */ | ||
| 244 | 246 | ||
| 245 | int running; /* if false, the test will stop */ | 247 | int running; /* if false, the test will stop */ |
| 246 | 248 | ||
| @@ -802,7 +804,6 @@ static int strn_len(const char __user * user_buffer, unsigned int maxlen) | |||
| 802 | case '\t': | 804 | case '\t': |
| 803 | case ' ': | 805 | case ' ': |
| 804 | goto done_str; | 806 | goto done_str; |
| 805 | break; | ||
| 806 | default: | 807 | default: |
| 807 | break; | 808 | break; |
| 808 | } | 809 | } |
| @@ -1737,14 +1738,14 @@ static int pktgen_thread_show(struct seq_file *seq, void *v) | |||
| 1737 | 1738 | ||
| 1738 | seq_puts(seq, "Running: "); | 1739 | seq_puts(seq, "Running: "); |
| 1739 | 1740 | ||
| 1740 | if_lock(t); | 1741 | rcu_read_lock(); |
| 1741 | list_for_each_entry(pkt_dev, &t->if_list, list) | 1742 | list_for_each_entry_rcu(pkt_dev, &t->if_list, list) |
| 1742 | if (pkt_dev->running) | 1743 | if (pkt_dev->running) |
| 1743 | seq_printf(seq, "%s ", pkt_dev->odevname); | 1744 | seq_printf(seq, "%s ", pkt_dev->odevname); |
| 1744 | 1745 | ||
| 1745 | seq_puts(seq, "\nStopped: "); | 1746 | seq_puts(seq, "\nStopped: "); |
| 1746 | 1747 | ||
| 1747 | list_for_each_entry(pkt_dev, &t->if_list, list) | 1748 | list_for_each_entry_rcu(pkt_dev, &t->if_list, list) |
| 1748 | if (!pkt_dev->running) | 1749 | if (!pkt_dev->running) |
| 1749 | seq_printf(seq, "%s ", pkt_dev->odevname); | 1750 | seq_printf(seq, "%s ", pkt_dev->odevname); |
| 1750 | 1751 | ||
| @@ -1753,7 +1754,7 @@ static int pktgen_thread_show(struct seq_file *seq, void *v) | |||
| 1753 | else | 1754 | else |
| 1754 | seq_puts(seq, "\nResult: NA\n"); | 1755 | seq_puts(seq, "\nResult: NA\n"); |
| 1755 | 1756 | ||
| 1756 | if_unlock(t); | 1757 | rcu_read_unlock(); |
| 1757 | 1758 | ||
| 1758 | return 0; | 1759 | return 0; |
| 1759 | } | 1760 | } |
| @@ -1878,10 +1879,8 @@ static struct pktgen_dev *__pktgen_NN_threads(const struct pktgen_net *pn, | |||
| 1878 | pkt_dev = pktgen_find_dev(t, ifname, exact); | 1879 | pkt_dev = pktgen_find_dev(t, ifname, exact); |
| 1879 | if (pkt_dev) { | 1880 | if (pkt_dev) { |
| 1880 | if (remove) { | 1881 | if (remove) { |
| 1881 | if_lock(t); | ||
| 1882 | pkt_dev->removal_mark = 1; | 1882 | pkt_dev->removal_mark = 1; |
| 1883 | t->control |= T_REMDEV; | 1883 | t->control |= T_REMDEV; |
| 1884 | if_unlock(t); | ||
| 1885 | } | 1884 | } |
| 1886 | break; | 1885 | break; |
| 1887 | } | 1886 | } |
| @@ -1931,7 +1930,8 @@ static void pktgen_change_name(const struct pktgen_net *pn, struct net_device *d | |||
| 1931 | list_for_each_entry(t, &pn->pktgen_threads, th_list) { | 1930 | list_for_each_entry(t, &pn->pktgen_threads, th_list) { |
| 1932 | struct pktgen_dev *pkt_dev; | 1931 | struct pktgen_dev *pkt_dev; |
| 1933 | 1932 | ||
| 1934 | list_for_each_entry(pkt_dev, &t->if_list, list) { | 1933 | rcu_read_lock(); |
| 1934 | list_for_each_entry_rcu(pkt_dev, &t->if_list, list) { | ||
| 1935 | if (pkt_dev->odev != dev) | 1935 | if (pkt_dev->odev != dev) |
| 1936 | continue; | 1936 | continue; |
| 1937 | 1937 | ||
| @@ -1946,6 +1946,7 @@ static void pktgen_change_name(const struct pktgen_net *pn, struct net_device *d | |||
| 1946 | dev->name); | 1946 | dev->name); |
| 1947 | break; | 1947 | break; |
| 1948 | } | 1948 | } |
| 1949 | rcu_read_unlock(); | ||
| 1949 | } | 1950 | } |
| 1950 | } | 1951 | } |
| 1951 | 1952 | ||
| @@ -2997,8 +2998,8 @@ static void pktgen_run(struct pktgen_thread *t) | |||
| 2997 | 2998 | ||
| 2998 | func_enter(); | 2999 | func_enter(); |
| 2999 | 3000 | ||
| 3000 | if_lock(t); | 3001 | rcu_read_lock(); |
| 3001 | list_for_each_entry(pkt_dev, &t->if_list, list) { | 3002 | list_for_each_entry_rcu(pkt_dev, &t->if_list, list) { |
| 3002 | 3003 | ||
| 3003 | /* | 3004 | /* |
| 3004 | * setup odev and create initial packet. | 3005 | * setup odev and create initial packet. |
| @@ -3007,18 +3008,18 @@ static void pktgen_run(struct pktgen_thread *t) | |||
| 3007 | 3008 | ||
| 3008 | if (pkt_dev->odev) { | 3009 | if (pkt_dev->odev) { |
| 3009 | pktgen_clear_counters(pkt_dev); | 3010 | pktgen_clear_counters(pkt_dev); |
| 3010 | pkt_dev->running = 1; /* Cranke yeself! */ | ||
| 3011 | pkt_dev->skb = NULL; | 3011 | pkt_dev->skb = NULL; |
| 3012 | pkt_dev->started_at = pkt_dev->next_tx = ktime_get(); | 3012 | pkt_dev->started_at = pkt_dev->next_tx = ktime_get(); |
| 3013 | 3013 | ||
| 3014 | set_pkt_overhead(pkt_dev); | 3014 | set_pkt_overhead(pkt_dev); |
| 3015 | 3015 | ||
| 3016 | strcpy(pkt_dev->result, "Starting"); | 3016 | strcpy(pkt_dev->result, "Starting"); |
| 3017 | pkt_dev->running = 1; /* Cranke yeself! */ | ||
| 3017 | started++; | 3018 | started++; |
| 3018 | } else | 3019 | } else |
| 3019 | strcpy(pkt_dev->result, "Error starting"); | 3020 | strcpy(pkt_dev->result, "Error starting"); |
| 3020 | } | 3021 | } |
| 3021 | if_unlock(t); | 3022 | rcu_read_unlock(); |
| 3022 | if (started) | 3023 | if (started) |
| 3023 | t->control &= ~(T_STOP); | 3024 | t->control &= ~(T_STOP); |
| 3024 | } | 3025 | } |
| @@ -3041,27 +3042,25 @@ static int thread_is_running(const struct pktgen_thread *t) | |||
| 3041 | { | 3042 | { |
| 3042 | const struct pktgen_dev *pkt_dev; | 3043 | const struct pktgen_dev *pkt_dev; |
| 3043 | 3044 | ||
| 3044 | list_for_each_entry(pkt_dev, &t->if_list, list) | 3045 | rcu_read_lock(); |
| 3045 | if (pkt_dev->running) | 3046 | list_for_each_entry_rcu(pkt_dev, &t->if_list, list) |
| 3047 | if (pkt_dev->running) { | ||
| 3048 | rcu_read_unlock(); | ||
| 3046 | return 1; | 3049 | return 1; |
| 3050 | } | ||
| 3051 | rcu_read_unlock(); | ||
| 3047 | return 0; | 3052 | return 0; |
| 3048 | } | 3053 | } |
| 3049 | 3054 | ||
| 3050 | static int pktgen_wait_thread_run(struct pktgen_thread *t) | 3055 | static int pktgen_wait_thread_run(struct pktgen_thread *t) |
| 3051 | { | 3056 | { |
| 3052 | if_lock(t); | ||
| 3053 | |||
| 3054 | while (thread_is_running(t)) { | 3057 | while (thread_is_running(t)) { |
| 3055 | 3058 | ||
| 3056 | if_unlock(t); | ||
| 3057 | |||
| 3058 | msleep_interruptible(100); | 3059 | msleep_interruptible(100); |
| 3059 | 3060 | ||
| 3060 | if (signal_pending(current)) | 3061 | if (signal_pending(current)) |
| 3061 | goto signal; | 3062 | goto signal; |
| 3062 | if_lock(t); | ||
| 3063 | } | 3063 | } |
| 3064 | if_unlock(t); | ||
| 3065 | return 1; | 3064 | return 1; |
| 3066 | signal: | 3065 | signal: |
| 3067 | return 0; | 3066 | return 0; |
| @@ -3166,10 +3165,10 @@ static int pktgen_stop_device(struct pktgen_dev *pkt_dev) | |||
| 3166 | return -EINVAL; | 3165 | return -EINVAL; |
| 3167 | } | 3166 | } |
| 3168 | 3167 | ||
| 3168 | pkt_dev->running = 0; | ||
| 3169 | kfree_skb(pkt_dev->skb); | 3169 | kfree_skb(pkt_dev->skb); |
| 3170 | pkt_dev->skb = NULL; | 3170 | pkt_dev->skb = NULL; |
| 3171 | pkt_dev->stopped_at = ktime_get(); | 3171 | pkt_dev->stopped_at = ktime_get(); |
| 3172 | pkt_dev->running = 0; | ||
| 3173 | 3172 | ||
| 3174 | show_results(pkt_dev, nr_frags); | 3173 | show_results(pkt_dev, nr_frags); |
| 3175 | 3174 | ||
| @@ -3180,9 +3179,8 @@ static struct pktgen_dev *next_to_run(struct pktgen_thread *t) | |||
| 3180 | { | 3179 | { |
| 3181 | struct pktgen_dev *pkt_dev, *best = NULL; | 3180 | struct pktgen_dev *pkt_dev, *best = NULL; |
| 3182 | 3181 | ||
| 3183 | if_lock(t); | 3182 | rcu_read_lock(); |
| 3184 | 3183 | list_for_each_entry_rcu(pkt_dev, &t->if_list, list) { | |
| 3185 | list_for_each_entry(pkt_dev, &t->if_list, list) { | ||
| 3186 | if (!pkt_dev->running) | 3184 | if (!pkt_dev->running) |
| 3187 | continue; | 3185 | continue; |
| 3188 | if (best == NULL) | 3186 | if (best == NULL) |
| @@ -3190,7 +3188,8 @@ static struct pktgen_dev *next_to_run(struct pktgen_thread *t) | |||
| 3190 | else if (ktime_compare(pkt_dev->next_tx, best->next_tx) < 0) | 3188 | else if (ktime_compare(pkt_dev->next_tx, best->next_tx) < 0) |
| 3191 | best = pkt_dev; | 3189 | best = pkt_dev; |
| 3192 | } | 3190 | } |
| 3193 | if_unlock(t); | 3191 | rcu_read_unlock(); |
| 3192 | |||
| 3194 | return best; | 3193 | return best; |
| 3195 | } | 3194 | } |
| 3196 | 3195 | ||
| @@ -3200,13 +3199,13 @@ static void pktgen_stop(struct pktgen_thread *t) | |||
| 3200 | 3199 | ||
| 3201 | func_enter(); | 3200 | func_enter(); |
| 3202 | 3201 | ||
| 3203 | if_lock(t); | 3202 | rcu_read_lock(); |
| 3204 | 3203 | ||
| 3205 | list_for_each_entry(pkt_dev, &t->if_list, list) { | 3204 | list_for_each_entry_rcu(pkt_dev, &t->if_list, list) { |
| 3206 | pktgen_stop_device(pkt_dev); | 3205 | pktgen_stop_device(pkt_dev); |
| 3207 | } | 3206 | } |
| 3208 | 3207 | ||
| 3209 | if_unlock(t); | 3208 | rcu_read_unlock(); |
| 3210 | } | 3209 | } |
| 3211 | 3210 | ||
| 3212 | /* | 3211 | /* |
| @@ -3220,8 +3219,6 @@ static void pktgen_rem_one_if(struct pktgen_thread *t) | |||
| 3220 | 3219 | ||
| 3221 | func_enter(); | 3220 | func_enter(); |
| 3222 | 3221 | ||
| 3223 | if_lock(t); | ||
| 3224 | |||
| 3225 | list_for_each_safe(q, n, &t->if_list) { | 3222 | list_for_each_safe(q, n, &t->if_list) { |
| 3226 | cur = list_entry(q, struct pktgen_dev, list); | 3223 | cur = list_entry(q, struct pktgen_dev, list); |
| 3227 | 3224 | ||
| @@ -3235,8 +3232,6 @@ static void pktgen_rem_one_if(struct pktgen_thread *t) | |||
| 3235 | 3232 | ||
| 3236 | break; | 3233 | break; |
| 3237 | } | 3234 | } |
| 3238 | |||
| 3239 | if_unlock(t); | ||
| 3240 | } | 3235 | } |
| 3241 | 3236 | ||
| 3242 | static void pktgen_rem_all_ifs(struct pktgen_thread *t) | 3237 | static void pktgen_rem_all_ifs(struct pktgen_thread *t) |
| @@ -3248,8 +3243,6 @@ static void pktgen_rem_all_ifs(struct pktgen_thread *t) | |||
| 3248 | 3243 | ||
| 3249 | /* Remove all devices, free mem */ | 3244 | /* Remove all devices, free mem */ |
| 3250 | 3245 | ||
| 3251 | if_lock(t); | ||
| 3252 | |||
| 3253 | list_for_each_safe(q, n, &t->if_list) { | 3246 | list_for_each_safe(q, n, &t->if_list) { |
| 3254 | cur = list_entry(q, struct pktgen_dev, list); | 3247 | cur = list_entry(q, struct pktgen_dev, list); |
| 3255 | 3248 | ||
| @@ -3258,8 +3251,6 @@ static void pktgen_rem_all_ifs(struct pktgen_thread *t) | |||
| 3258 | 3251 | ||
| 3259 | pktgen_remove_device(t, cur); | 3252 | pktgen_remove_device(t, cur); |
| 3260 | } | 3253 | } |
| 3261 | |||
| 3262 | if_unlock(t); | ||
| 3263 | } | 3254 | } |
| 3264 | 3255 | ||
| 3265 | static void pktgen_rem_thread(struct pktgen_thread *t) | 3256 | static void pktgen_rem_thread(struct pktgen_thread *t) |
| @@ -3407,10 +3398,10 @@ static int pktgen_thread_worker(void *arg) | |||
| 3407 | 3398 | ||
| 3408 | pr_debug("starting pktgen/%d: pid=%d\n", cpu, task_pid_nr(current)); | 3399 | pr_debug("starting pktgen/%d: pid=%d\n", cpu, task_pid_nr(current)); |
| 3409 | 3400 | ||
| 3410 | set_current_state(TASK_INTERRUPTIBLE); | ||
| 3411 | |||
| 3412 | set_freezable(); | 3401 | set_freezable(); |
| 3413 | 3402 | ||
| 3403 | __set_current_state(TASK_RUNNING); | ||
| 3404 | |||
| 3414 | while (!kthread_should_stop()) { | 3405 | while (!kthread_should_stop()) { |
| 3415 | pkt_dev = next_to_run(t); | 3406 | pkt_dev = next_to_run(t); |
| 3416 | 3407 | ||
| @@ -3424,8 +3415,6 @@ static int pktgen_thread_worker(void *arg) | |||
| 3424 | continue; | 3415 | continue; |
| 3425 | } | 3416 | } |
| 3426 | 3417 | ||
| 3427 | __set_current_state(TASK_RUNNING); | ||
| 3428 | |||
| 3429 | if (likely(pkt_dev)) { | 3418 | if (likely(pkt_dev)) { |
| 3430 | pktgen_xmit(pkt_dev); | 3419 | pktgen_xmit(pkt_dev); |
| 3431 | 3420 | ||
| @@ -3456,9 +3445,8 @@ static int pktgen_thread_worker(void *arg) | |||
| 3456 | } | 3445 | } |
| 3457 | 3446 | ||
| 3458 | try_to_freeze(); | 3447 | try_to_freeze(); |
| 3459 | |||
| 3460 | set_current_state(TASK_INTERRUPTIBLE); | ||
| 3461 | } | 3448 | } |
| 3449 | set_current_state(TASK_INTERRUPTIBLE); | ||
| 3462 | 3450 | ||
| 3463 | pr_debug("%s stopping all device\n", t->tsk->comm); | 3451 | pr_debug("%s stopping all device\n", t->tsk->comm); |
| 3464 | pktgen_stop(t); | 3452 | pktgen_stop(t); |
| @@ -3485,8 +3473,8 @@ static struct pktgen_dev *pktgen_find_dev(struct pktgen_thread *t, | |||
| 3485 | struct pktgen_dev *p, *pkt_dev = NULL; | 3473 | struct pktgen_dev *p, *pkt_dev = NULL; |
| 3486 | size_t len = strlen(ifname); | 3474 | size_t len = strlen(ifname); |
| 3487 | 3475 | ||
| 3488 | if_lock(t); | 3476 | rcu_read_lock(); |
| 3489 | list_for_each_entry(p, &t->if_list, list) | 3477 | list_for_each_entry_rcu(p, &t->if_list, list) |
| 3490 | if (strncmp(p->odevname, ifname, len) == 0) { | 3478 | if (strncmp(p->odevname, ifname, len) == 0) { |
| 3491 | if (p->odevname[len]) { | 3479 | if (p->odevname[len]) { |
| 3492 | if (exact || p->odevname[len] != '@') | 3480 | if (exact || p->odevname[len] != '@') |
| @@ -3496,7 +3484,7 @@ static struct pktgen_dev *pktgen_find_dev(struct pktgen_thread *t, | |||
| 3496 | break; | 3484 | break; |
| 3497 | } | 3485 | } |
| 3498 | 3486 | ||
| 3499 | if_unlock(t); | 3487 | rcu_read_unlock(); |
| 3500 | pr_debug("find_dev(%s) returning %p\n", ifname, pkt_dev); | 3488 | pr_debug("find_dev(%s) returning %p\n", ifname, pkt_dev); |
| 3501 | return pkt_dev; | 3489 | return pkt_dev; |
| 3502 | } | 3490 | } |
| @@ -3510,6 +3498,12 @@ static int add_dev_to_thread(struct pktgen_thread *t, | |||
| 3510 | { | 3498 | { |
| 3511 | int rv = 0; | 3499 | int rv = 0; |
| 3512 | 3500 | ||
| 3501 | /* This function cannot be called concurrently, as its called | ||
| 3502 | * under pktgen_thread_lock mutex, but it can run from | ||
| 3503 | * userspace on another CPU than the kthread. The if_lock() | ||
| 3504 | * is used here to sync with concurrent instances of | ||
| 3505 | * _rem_dev_from_if_list() invoked via kthread, which is also | ||
| 3506 | * updating the if_list */ | ||
| 3513 | if_lock(t); | 3507 | if_lock(t); |
| 3514 | 3508 | ||
| 3515 | if (pkt_dev->pg_thread) { | 3509 | if (pkt_dev->pg_thread) { |
| @@ -3518,9 +3512,9 @@ static int add_dev_to_thread(struct pktgen_thread *t, | |||
| 3518 | goto out; | 3512 | goto out; |
| 3519 | } | 3513 | } |
| 3520 | 3514 | ||
| 3521 | list_add(&pkt_dev->list, &t->if_list); | ||
| 3522 | pkt_dev->pg_thread = t; | ||
| 3523 | pkt_dev->running = 0; | 3515 | pkt_dev->running = 0; |
| 3516 | pkt_dev->pg_thread = t; | ||
| 3517 | list_add_rcu(&pkt_dev->list, &t->if_list); | ||
| 3524 | 3518 | ||
| 3525 | out: | 3519 | out: |
| 3526 | if_unlock(t); | 3520 | if_unlock(t); |
| @@ -3675,11 +3669,13 @@ static void _rem_dev_from_if_list(struct pktgen_thread *t, | |||
| 3675 | struct list_head *q, *n; | 3669 | struct list_head *q, *n; |
| 3676 | struct pktgen_dev *p; | 3670 | struct pktgen_dev *p; |
| 3677 | 3671 | ||
| 3672 | if_lock(t); | ||
| 3678 | list_for_each_safe(q, n, &t->if_list) { | 3673 | list_for_each_safe(q, n, &t->if_list) { |
| 3679 | p = list_entry(q, struct pktgen_dev, list); | 3674 | p = list_entry(q, struct pktgen_dev, list); |
| 3680 | if (p == pkt_dev) | 3675 | if (p == pkt_dev) |
| 3681 | list_del(&p->list); | 3676 | list_del_rcu(&p->list); |
| 3682 | } | 3677 | } |
| 3678 | if_unlock(t); | ||
| 3683 | } | 3679 | } |
| 3684 | 3680 | ||
| 3685 | static int pktgen_remove_device(struct pktgen_thread *t, | 3681 | static int pktgen_remove_device(struct pktgen_thread *t, |
| @@ -3699,20 +3695,22 @@ static int pktgen_remove_device(struct pktgen_thread *t, | |||
| 3699 | pkt_dev->odev = NULL; | 3695 | pkt_dev->odev = NULL; |
| 3700 | } | 3696 | } |
| 3701 | 3697 | ||
| 3702 | /* And update the thread if_list */ | 3698 | /* Remove proc before if_list entry, because add_device uses |
| 3703 | 3699 | * list to determine if interface already exist, avoid race | |
| 3704 | _rem_dev_from_if_list(t, pkt_dev); | 3700 | * with proc_create_data() */ |
| 3705 | |||
| 3706 | if (pkt_dev->entry) | 3701 | if (pkt_dev->entry) |
| 3707 | proc_remove(pkt_dev->entry); | 3702 | proc_remove(pkt_dev->entry); |
| 3708 | 3703 | ||
| 3704 | /* And update the thread if_list */ | ||
| 3705 | _rem_dev_from_if_list(t, pkt_dev); | ||
| 3706 | |||
| 3709 | #ifdef CONFIG_XFRM | 3707 | #ifdef CONFIG_XFRM |
| 3710 | free_SAs(pkt_dev); | 3708 | free_SAs(pkt_dev); |
| 3711 | #endif | 3709 | #endif |
| 3712 | vfree(pkt_dev->flows); | 3710 | vfree(pkt_dev->flows); |
| 3713 | if (pkt_dev->page) | 3711 | if (pkt_dev->page) |
| 3714 | put_page(pkt_dev->page); | 3712 | put_page(pkt_dev->page); |
| 3715 | kfree(pkt_dev); | 3713 | kfree_rcu(pkt_dev, rcu); |
| 3716 | return 0; | 3714 | return 0; |
| 3717 | } | 3715 | } |
| 3718 | 3716 | ||
| @@ -3812,6 +3810,7 @@ static void __exit pg_cleanup(void) | |||
| 3812 | { | 3810 | { |
| 3813 | unregister_netdevice_notifier(&pktgen_notifier_block); | 3811 | unregister_netdevice_notifier(&pktgen_notifier_block); |
| 3814 | unregister_pernet_subsys(&pg_net_ops); | 3812 | unregister_pernet_subsys(&pg_net_ops); |
| 3813 | /* Don't need rcu_barrier() due to use of kfree_rcu() */ | ||
| 3815 | } | 3814 | } |
| 3816 | 3815 | ||
| 3817 | module_init(pg_init); | 3816 | module_init(pg_init); |
diff --git a/net/core/ptp_classifier.c b/net/core/ptp_classifier.c index d3027a73fd4b..4eab4a94a59d 100644 --- a/net/core/ptp_classifier.c +++ b/net/core/ptp_classifier.c | |||
| @@ -52,14 +52,43 @@ | |||
| 52 | * test_8021q: | 52 | * test_8021q: |
| 53 | * jneq #0x8100, test_ieee1588 ; ETH_P_8021Q ? | 53 | * jneq #0x8100, test_ieee1588 ; ETH_P_8021Q ? |
| 54 | * ldh [16] ; load inner type | 54 | * ldh [16] ; load inner type |
| 55 | * jneq #0x88f7, drop_ieee1588 ; ETH_P_1588 ? | 55 | * jneq #0x88f7, test_8021q_ipv4 ; ETH_P_1588 ? |
| 56 | * ldb [18] ; load payload | 56 | * ldb [18] ; load payload |
| 57 | * and #0x8 ; as we don't have ports here, test | 57 | * and #0x8 ; as we don't have ports here, test |
| 58 | * jneq #0x0, drop_ieee1588 ; for PTP_GEN_BIT and drop these | 58 | * jneq #0x0, drop_ieee1588 ; for PTP_GEN_BIT and drop these |
| 59 | * ldh [18] ; reload payload | 59 | * ldh [18] ; reload payload |
| 60 | * and #0xf ; mask PTP_CLASS_VMASK | 60 | * and #0xf ; mask PTP_CLASS_VMASK |
| 61 | * or #0x40 ; PTP_CLASS_V2_VLAN | 61 | * or #0x70 ; PTP_CLASS_VLAN|PTP_CLASS_L2 |
| 62 | * ret a ; return PTP class | ||
| 63 | * | ||
| 64 | * ; PTP over UDP over IPv4 over 802.1Q over Ethernet | ||
| 65 | * test_8021q_ipv4: | ||
| 66 | * jneq #0x800, test_8021q_ipv6 ; ETH_P_IP ? | ||
| 67 | * ldb [27] ; load proto | ||
| 68 | * jneq #17, drop_8021q_ipv4 ; IPPROTO_UDP ? | ||
| 69 | * ldh [24] ; load frag offset field | ||
| 70 | * jset #0x1fff, drop_8021q_ipv4; don't allow fragments | ||
| 71 | * ldxb 4*([18]&0xf) ; load IP header len | ||
| 72 | * ldh [x + 20] ; load UDP dst port | ||
| 73 | * jneq #319, drop_8021q_ipv4 ; is port PTP_EV_PORT ? | ||
| 74 | * ldh [x + 26] ; load payload | ||
| 75 | * and #0xf ; mask PTP_CLASS_VMASK | ||
| 76 | * or #0x50 ; PTP_CLASS_VLAN|PTP_CLASS_IPV4 | ||
| 77 | * ret a ; return PTP class | ||
| 78 | * drop_8021q_ipv4: ret #0x0 ; PTP_CLASS_NONE | ||
| 79 | * | ||
| 80 | * ; PTP over UDP over IPv6 over 802.1Q over Ethernet | ||
| 81 | * test_8021q_ipv6: | ||
| 82 | * jneq #0x86dd, drop_8021q_ipv6 ; ETH_P_IPV6 ? | ||
| 83 | * ldb [24] ; load proto | ||
| 84 | * jneq #17, drop_8021q_ipv6 ; IPPROTO_UDP ? | ||
| 85 | * ldh [60] ; load UDP dst port | ||
| 86 | * jneq #319, drop_8021q_ipv6 ; is port PTP_EV_PORT ? | ||
| 87 | * ldh [66] ; load payload | ||
| 88 | * and #0xf ; mask PTP_CLASS_VMASK | ||
| 89 | * or #0x60 ; PTP_CLASS_VLAN|PTP_CLASS_IPV6 | ||
| 62 | * ret a ; return PTP class | 90 | * ret a ; return PTP class |
| 91 | * drop_8021q_ipv6: ret #0x0 ; PTP_CLASS_NONE | ||
| 63 | * | 92 | * |
| 64 | * ; PTP over Ethernet | 93 | * ; PTP over Ethernet |
| 65 | * test_ieee1588: | 94 | * test_ieee1588: |
| @@ -78,11 +107,11 @@ | |||
| 78 | #include <linux/filter.h> | 107 | #include <linux/filter.h> |
| 79 | #include <linux/ptp_classify.h> | 108 | #include <linux/ptp_classify.h> |
| 80 | 109 | ||
| 81 | static struct sk_filter *ptp_insns __read_mostly; | 110 | static struct bpf_prog *ptp_insns __read_mostly; |
| 82 | 111 | ||
| 83 | unsigned int ptp_classify_raw(const struct sk_buff *skb) | 112 | unsigned int ptp_classify_raw(const struct sk_buff *skb) |
| 84 | { | 113 | { |
| 85 | return SK_RUN_FILTER(ptp_insns, skb); | 114 | return BPF_PROG_RUN(ptp_insns, skb); |
| 86 | } | 115 | } |
| 87 | EXPORT_SYMBOL_GPL(ptp_classify_raw); | 116 | EXPORT_SYMBOL_GPL(ptp_classify_raw); |
| 88 | 117 | ||
| @@ -113,16 +142,39 @@ void __init ptp_classifier_init(void) | |||
| 113 | { 0x44, 0, 0, 0x00000020 }, | 142 | { 0x44, 0, 0, 0x00000020 }, |
| 114 | { 0x16, 0, 0, 0x00000000 }, | 143 | { 0x16, 0, 0, 0x00000000 }, |
| 115 | { 0x06, 0, 0, 0x00000000 }, | 144 | { 0x06, 0, 0, 0x00000000 }, |
| 116 | { 0x15, 0, 9, 0x00008100 }, | 145 | { 0x15, 0, 32, 0x00008100 }, |
| 117 | { 0x28, 0, 0, 0x00000010 }, | 146 | { 0x28, 0, 0, 0x00000010 }, |
| 118 | { 0x15, 0, 15, 0x000088f7 }, | 147 | { 0x15, 0, 7, 0x000088f7 }, |
| 119 | { 0x30, 0, 0, 0x00000012 }, | 148 | { 0x30, 0, 0, 0x00000012 }, |
| 120 | { 0x54, 0, 0, 0x00000008 }, | 149 | { 0x54, 0, 0, 0x00000008 }, |
| 121 | { 0x15, 0, 12, 0x00000000 }, | 150 | { 0x15, 0, 35, 0x00000000 }, |
| 122 | { 0x28, 0, 0, 0x00000012 }, | 151 | { 0x28, 0, 0, 0x00000012 }, |
| 123 | { 0x54, 0, 0, 0x0000000f }, | 152 | { 0x54, 0, 0, 0x0000000f }, |
| 124 | { 0x44, 0, 0, 0x00000040 }, | 153 | { 0x44, 0, 0, 0x00000070 }, |
| 154 | { 0x16, 0, 0, 0x00000000 }, | ||
| 155 | { 0x15, 0, 12, 0x00000800 }, | ||
| 156 | { 0x30, 0, 0, 0x0000001b }, | ||
| 157 | { 0x15, 0, 9, 0x00000011 }, | ||
| 158 | { 0x28, 0, 0, 0x00000018 }, | ||
| 159 | { 0x45, 7, 0, 0x00001fff }, | ||
| 160 | { 0xb1, 0, 0, 0x00000012 }, | ||
| 161 | { 0x48, 0, 0, 0x00000014 }, | ||
| 162 | { 0x15, 0, 4, 0x0000013f }, | ||
| 163 | { 0x48, 0, 0, 0x0000001a }, | ||
| 164 | { 0x54, 0, 0, 0x0000000f }, | ||
| 165 | { 0x44, 0, 0, 0x00000050 }, | ||
| 166 | { 0x16, 0, 0, 0x00000000 }, | ||
| 167 | { 0x06, 0, 0, 0x00000000 }, | ||
| 168 | { 0x15, 0, 8, 0x000086dd }, | ||
| 169 | { 0x30, 0, 0, 0x00000018 }, | ||
| 170 | { 0x15, 0, 6, 0x00000011 }, | ||
| 171 | { 0x28, 0, 0, 0x0000003c }, | ||
| 172 | { 0x15, 0, 4, 0x0000013f }, | ||
| 173 | { 0x28, 0, 0, 0x00000042 }, | ||
| 174 | { 0x54, 0, 0, 0x0000000f }, | ||
| 175 | { 0x44, 0, 0, 0x00000060 }, | ||
| 125 | { 0x16, 0, 0, 0x00000000 }, | 176 | { 0x16, 0, 0, 0x00000000 }, |
| 177 | { 0x06, 0, 0, 0x00000000 }, | ||
| 126 | { 0x15, 0, 7, 0x000088f7 }, | 178 | { 0x15, 0, 7, 0x000088f7 }, |
| 127 | { 0x30, 0, 0, 0x0000000e }, | 179 | { 0x30, 0, 0, 0x0000000e }, |
| 128 | { 0x54, 0, 0, 0x00000008 }, | 180 | { 0x54, 0, 0, 0x00000008 }, |
| @@ -137,5 +189,5 @@ void __init ptp_classifier_init(void) | |||
| 137 | .len = ARRAY_SIZE(ptp_filter), .filter = ptp_filter, | 189 | .len = ARRAY_SIZE(ptp_filter), .filter = ptp_filter, |
| 138 | }; | 190 | }; |
| 139 | 191 | ||
| 140 | BUG_ON(sk_unattached_filter_create(&ptp_insns, &ptp_prog)); | 192 | BUG_ON(bpf_prog_create(&ptp_insns, &ptp_prog)); |
| 141 | } | 193 | } |
diff --git a/net/core/request_sock.c b/net/core/request_sock.c index 467f326126e0..04db318e6218 100644 --- a/net/core/request_sock.c +++ b/net/core/request_sock.c | |||
| @@ -41,27 +41,27 @@ int reqsk_queue_alloc(struct request_sock_queue *queue, | |||
| 41 | unsigned int nr_table_entries) | 41 | unsigned int nr_table_entries) |
| 42 | { | 42 | { |
| 43 | size_t lopt_size = sizeof(struct listen_sock); | 43 | size_t lopt_size = sizeof(struct listen_sock); |
| 44 | struct listen_sock *lopt; | 44 | struct listen_sock *lopt = NULL; |
| 45 | 45 | ||
| 46 | nr_table_entries = min_t(u32, nr_table_entries, sysctl_max_syn_backlog); | 46 | nr_table_entries = min_t(u32, nr_table_entries, sysctl_max_syn_backlog); |
| 47 | nr_table_entries = max_t(u32, nr_table_entries, 8); | 47 | nr_table_entries = max_t(u32, nr_table_entries, 8); |
| 48 | nr_table_entries = roundup_pow_of_two(nr_table_entries + 1); | 48 | nr_table_entries = roundup_pow_of_two(nr_table_entries + 1); |
| 49 | lopt_size += nr_table_entries * sizeof(struct request_sock *); | 49 | lopt_size += nr_table_entries * sizeof(struct request_sock *); |
| 50 | if (lopt_size > PAGE_SIZE) | 50 | |
| 51 | if (lopt_size <= (PAGE_SIZE << PAGE_ALLOC_COSTLY_ORDER)) | ||
| 52 | lopt = kzalloc(lopt_size, GFP_KERNEL | | ||
| 53 | __GFP_NOWARN | | ||
| 54 | __GFP_NORETRY); | ||
| 55 | if (!lopt) | ||
| 51 | lopt = vzalloc(lopt_size); | 56 | lopt = vzalloc(lopt_size); |
| 52 | else | 57 | if (!lopt) |
| 53 | lopt = kzalloc(lopt_size, GFP_KERNEL); | ||
| 54 | if (lopt == NULL) | ||
| 55 | return -ENOMEM; | 58 | return -ENOMEM; |
| 56 | 59 | ||
| 57 | for (lopt->max_qlen_log = 3; | ||
| 58 | (1 << lopt->max_qlen_log) < nr_table_entries; | ||
| 59 | lopt->max_qlen_log++); | ||
| 60 | |||
| 61 | get_random_bytes(&lopt->hash_rnd, sizeof(lopt->hash_rnd)); | 60 | get_random_bytes(&lopt->hash_rnd, sizeof(lopt->hash_rnd)); |
| 62 | rwlock_init(&queue->syn_wait_lock); | 61 | rwlock_init(&queue->syn_wait_lock); |
| 63 | queue->rskq_accept_head = NULL; | 62 | queue->rskq_accept_head = NULL; |
| 64 | lopt->nr_table_entries = nr_table_entries; | 63 | lopt->nr_table_entries = nr_table_entries; |
| 64 | lopt->max_qlen_log = ilog2(nr_table_entries); | ||
| 65 | 65 | ||
| 66 | write_lock_bh(&queue->syn_wait_lock); | 66 | write_lock_bh(&queue->syn_wait_lock); |
| 67 | queue->listen_opt = lopt; | 67 | queue->listen_opt = lopt; |
| @@ -72,22 +72,8 @@ int reqsk_queue_alloc(struct request_sock_queue *queue, | |||
| 72 | 72 | ||
| 73 | void __reqsk_queue_destroy(struct request_sock_queue *queue) | 73 | void __reqsk_queue_destroy(struct request_sock_queue *queue) |
| 74 | { | 74 | { |
| 75 | struct listen_sock *lopt; | 75 | /* This is an error recovery path only, no locking needed */ |
| 76 | size_t lopt_size; | 76 | kvfree(queue->listen_opt); |
| 77 | |||
| 78 | /* | ||
| 79 | * this is an error recovery path only | ||
| 80 | * no locking needed and the lopt is not NULL | ||
| 81 | */ | ||
| 82 | |||
| 83 | lopt = queue->listen_opt; | ||
| 84 | lopt_size = sizeof(struct listen_sock) + | ||
| 85 | lopt->nr_table_entries * sizeof(struct request_sock *); | ||
| 86 | |||
| 87 | if (lopt_size > PAGE_SIZE) | ||
| 88 | vfree(lopt); | ||
| 89 | else | ||
| 90 | kfree(lopt); | ||
| 91 | } | 77 | } |
| 92 | 78 | ||
| 93 | static inline struct listen_sock *reqsk_queue_yank_listen_sk( | 79 | static inline struct listen_sock *reqsk_queue_yank_listen_sk( |
| @@ -107,8 +93,6 @@ void reqsk_queue_destroy(struct request_sock_queue *queue) | |||
| 107 | { | 93 | { |
| 108 | /* make all the listen_opt local to us */ | 94 | /* make all the listen_opt local to us */ |
| 109 | struct listen_sock *lopt = reqsk_queue_yank_listen_sk(queue); | 95 | struct listen_sock *lopt = reqsk_queue_yank_listen_sk(queue); |
| 110 | size_t lopt_size = sizeof(struct listen_sock) + | ||
| 111 | lopt->nr_table_entries * sizeof(struct request_sock *); | ||
| 112 | 96 | ||
| 113 | if (lopt->qlen != 0) { | 97 | if (lopt->qlen != 0) { |
| 114 | unsigned int i; | 98 | unsigned int i; |
| @@ -125,10 +109,7 @@ void reqsk_queue_destroy(struct request_sock_queue *queue) | |||
| 125 | } | 109 | } |
| 126 | 110 | ||
| 127 | WARN_ON(lopt->qlen != 0); | 111 | WARN_ON(lopt->qlen != 0); |
| 128 | if (lopt_size > PAGE_SIZE) | 112 | kvfree(lopt); |
| 129 | vfree(lopt); | ||
| 130 | else | ||
| 131 | kfree(lopt); | ||
| 132 | } | 113 | } |
| 133 | 114 | ||
| 134 | /* | 115 | /* |
diff --git a/net/core/rtnetlink.c b/net/core/rtnetlink.c index 1063996f8317..f0493e3b7471 100644 --- a/net/core/rtnetlink.c +++ b/net/core/rtnetlink.c | |||
| @@ -299,7 +299,12 @@ int __rtnl_link_register(struct rtnl_link_ops *ops) | |||
| 299 | if (rtnl_link_ops_get(ops->kind)) | 299 | if (rtnl_link_ops_get(ops->kind)) |
| 300 | return -EEXIST; | 300 | return -EEXIST; |
| 301 | 301 | ||
| 302 | if (!ops->dellink) | 302 | /* The check for setup is here because if ops |
| 303 | * does not have that filled up, it is not possible | ||
| 304 | * to use the ops for creating device. So do not | ||
| 305 | * fill up dellink as well. That disables rtnl_dellink. | ||
| 306 | */ | ||
| 307 | if (ops->setup && !ops->dellink) | ||
| 303 | ops->dellink = unregister_netdevice_queue; | 308 | ops->dellink = unregister_netdevice_queue; |
| 304 | 309 | ||
| 305 | list_add_tail(&ops->list, &link_ops); | 310 | list_add_tail(&ops->list, &link_ops); |
| @@ -799,7 +804,8 @@ static inline int rtnl_vfinfo_size(const struct net_device *dev, | |||
| 799 | (nla_total_size(sizeof(struct ifla_vf_mac)) + | 804 | (nla_total_size(sizeof(struct ifla_vf_mac)) + |
| 800 | nla_total_size(sizeof(struct ifla_vf_vlan)) + | 805 | nla_total_size(sizeof(struct ifla_vf_vlan)) + |
| 801 | nla_total_size(sizeof(struct ifla_vf_spoofchk)) + | 806 | nla_total_size(sizeof(struct ifla_vf_spoofchk)) + |
| 802 | nla_total_size(sizeof(struct ifla_vf_rate))); | 807 | nla_total_size(sizeof(struct ifla_vf_rate)) + |
| 808 | nla_total_size(sizeof(struct ifla_vf_link_state))); | ||
| 803 | return size; | 809 | return size; |
| 804 | } else | 810 | } else |
| 805 | return 0; | 811 | return 0; |
| @@ -1777,7 +1783,7 @@ static int rtnl_dellink(struct sk_buff *skb, struct nlmsghdr *nlh) | |||
| 1777 | return -ENODEV; | 1783 | return -ENODEV; |
| 1778 | 1784 | ||
| 1779 | ops = dev->rtnl_link_ops; | 1785 | ops = dev->rtnl_link_ops; |
| 1780 | if (!ops) | 1786 | if (!ops || !ops->dellink) |
| 1781 | return -EOPNOTSUPP; | 1787 | return -EOPNOTSUPP; |
| 1782 | 1788 | ||
| 1783 | ops->dellink(dev, &list_kill); | 1789 | ops->dellink(dev, &list_kill); |
| @@ -1805,7 +1811,8 @@ int rtnl_configure_link(struct net_device *dev, const struct ifinfomsg *ifm) | |||
| 1805 | EXPORT_SYMBOL(rtnl_configure_link); | 1811 | EXPORT_SYMBOL(rtnl_configure_link); |
| 1806 | 1812 | ||
| 1807 | struct net_device *rtnl_create_link(struct net *net, | 1813 | struct net_device *rtnl_create_link(struct net *net, |
| 1808 | char *ifname, const struct rtnl_link_ops *ops, struct nlattr *tb[]) | 1814 | char *ifname, unsigned char name_assign_type, |
| 1815 | const struct rtnl_link_ops *ops, struct nlattr *tb[]) | ||
| 1809 | { | 1816 | { |
| 1810 | int err; | 1817 | int err; |
| 1811 | struct net_device *dev; | 1818 | struct net_device *dev; |
| @@ -1823,8 +1830,8 @@ struct net_device *rtnl_create_link(struct net *net, | |||
| 1823 | num_rx_queues = ops->get_num_rx_queues(); | 1830 | num_rx_queues = ops->get_num_rx_queues(); |
| 1824 | 1831 | ||
| 1825 | err = -ENOMEM; | 1832 | err = -ENOMEM; |
| 1826 | dev = alloc_netdev_mqs(ops->priv_size, ifname, ops->setup, | 1833 | dev = alloc_netdev_mqs(ops->priv_size, ifname, name_assign_type, |
| 1827 | num_tx_queues, num_rx_queues); | 1834 | ops->setup, num_tx_queues, num_rx_queues); |
| 1828 | if (!dev) | 1835 | if (!dev) |
| 1829 | goto err; | 1836 | goto err; |
| 1830 | 1837 | ||
| @@ -1889,6 +1896,7 @@ static int rtnl_newlink(struct sk_buff *skb, struct nlmsghdr *nlh) | |||
| 1889 | char ifname[IFNAMSIZ]; | 1896 | char ifname[IFNAMSIZ]; |
| 1890 | struct nlattr *tb[IFLA_MAX+1]; | 1897 | struct nlattr *tb[IFLA_MAX+1]; |
| 1891 | struct nlattr *linkinfo[IFLA_INFO_MAX+1]; | 1898 | struct nlattr *linkinfo[IFLA_INFO_MAX+1]; |
| 1899 | unsigned char name_assign_type = NET_NAME_USER; | ||
| 1892 | int err; | 1900 | int err; |
| 1893 | 1901 | ||
| 1894 | #ifdef CONFIG_MODULES | 1902 | #ifdef CONFIG_MODULES |
| @@ -2038,14 +2046,19 @@ replay: | |||
| 2038 | return -EOPNOTSUPP; | 2046 | return -EOPNOTSUPP; |
| 2039 | } | 2047 | } |
| 2040 | 2048 | ||
| 2041 | if (!ifname[0]) | 2049 | if (!ops->setup) |
| 2050 | return -EOPNOTSUPP; | ||
| 2051 | |||
| 2052 | if (!ifname[0]) { | ||
| 2042 | snprintf(ifname, IFNAMSIZ, "%s%%d", ops->kind); | 2053 | snprintf(ifname, IFNAMSIZ, "%s%%d", ops->kind); |
| 2054 | name_assign_type = NET_NAME_ENUM; | ||
| 2055 | } | ||
| 2043 | 2056 | ||
| 2044 | dest_net = rtnl_link_get_net(net, tb); | 2057 | dest_net = rtnl_link_get_net(net, tb); |
| 2045 | if (IS_ERR(dest_net)) | 2058 | if (IS_ERR(dest_net)) |
| 2046 | return PTR_ERR(dest_net); | 2059 | return PTR_ERR(dest_net); |
| 2047 | 2060 | ||
| 2048 | dev = rtnl_create_link(dest_net, ifname, ops, tb); | 2061 | dev = rtnl_create_link(dest_net, ifname, name_assign_type, ops, tb); |
| 2049 | if (IS_ERR(dev)) { | 2062 | if (IS_ERR(dev)) { |
| 2050 | err = PTR_ERR(dev); | 2063 | err = PTR_ERR(dev); |
| 2051 | goto out; | 2064 | goto out; |
| @@ -2380,22 +2393,20 @@ int ndo_dflt_fdb_del(struct ndmsg *ndm, | |||
| 2380 | struct net_device *dev, | 2393 | struct net_device *dev, |
| 2381 | const unsigned char *addr) | 2394 | const unsigned char *addr) |
| 2382 | { | 2395 | { |
| 2383 | int err = -EOPNOTSUPP; | 2396 | int err = -EINVAL; |
| 2384 | 2397 | ||
| 2385 | /* If aging addresses are supported device will need to | 2398 | /* If aging addresses are supported device will need to |
| 2386 | * implement its own handler for this. | 2399 | * implement its own handler for this. |
| 2387 | */ | 2400 | */ |
| 2388 | if (!(ndm->ndm_state & NUD_PERMANENT)) { | 2401 | if (!(ndm->ndm_state & NUD_PERMANENT)) { |
| 2389 | pr_info("%s: FDB only supports static addresses\n", dev->name); | 2402 | pr_info("%s: FDB only supports static addresses\n", dev->name); |
| 2390 | return -EINVAL; | 2403 | return err; |
| 2391 | } | 2404 | } |
| 2392 | 2405 | ||
| 2393 | if (is_unicast_ether_addr(addr) || is_link_local_ether_addr(addr)) | 2406 | if (is_unicast_ether_addr(addr) || is_link_local_ether_addr(addr)) |
| 2394 | err = dev_uc_del(dev, addr); | 2407 | err = dev_uc_del(dev, addr); |
| 2395 | else if (is_multicast_ether_addr(addr)) | 2408 | else if (is_multicast_ether_addr(addr)) |
| 2396 | err = dev_mc_del(dev, addr); | 2409 | err = dev_mc_del(dev, addr); |
| 2397 | else | ||
| 2398 | err = -EINVAL; | ||
| 2399 | 2410 | ||
| 2400 | return err; | 2411 | return err; |
| 2401 | } | 2412 | } |
| @@ -2509,6 +2520,7 @@ skip: | |||
| 2509 | int ndo_dflt_fdb_dump(struct sk_buff *skb, | 2520 | int ndo_dflt_fdb_dump(struct sk_buff *skb, |
| 2510 | struct netlink_callback *cb, | 2521 | struct netlink_callback *cb, |
| 2511 | struct net_device *dev, | 2522 | struct net_device *dev, |
| 2523 | struct net_device *filter_dev, | ||
| 2512 | int idx) | 2524 | int idx) |
| 2513 | { | 2525 | { |
| 2514 | int err; | 2526 | int err; |
| @@ -2526,28 +2538,72 @@ EXPORT_SYMBOL(ndo_dflt_fdb_dump); | |||
| 2526 | 2538 | ||
| 2527 | static int rtnl_fdb_dump(struct sk_buff *skb, struct netlink_callback *cb) | 2539 | static int rtnl_fdb_dump(struct sk_buff *skb, struct netlink_callback *cb) |
| 2528 | { | 2540 | { |
| 2529 | int idx = 0; | ||
| 2530 | struct net *net = sock_net(skb->sk); | ||
| 2531 | struct net_device *dev; | 2541 | struct net_device *dev; |
| 2542 | struct nlattr *tb[IFLA_MAX+1]; | ||
| 2543 | struct net_device *bdev = NULL; | ||
| 2544 | struct net_device *br_dev = NULL; | ||
| 2545 | const struct net_device_ops *ops = NULL; | ||
| 2546 | const struct net_device_ops *cops = NULL; | ||
| 2547 | struct ifinfomsg *ifm = nlmsg_data(cb->nlh); | ||
| 2548 | struct net *net = sock_net(skb->sk); | ||
| 2549 | int brport_idx = 0; | ||
| 2550 | int br_idx = 0; | ||
| 2551 | int idx = 0; | ||
| 2532 | 2552 | ||
| 2533 | rcu_read_lock(); | 2553 | if (nlmsg_parse(cb->nlh, sizeof(struct ifinfomsg), tb, IFLA_MAX, |
| 2534 | for_each_netdev_rcu(net, dev) { | 2554 | ifla_policy) == 0) { |
| 2535 | if (dev->priv_flags & IFF_BRIDGE_PORT) { | 2555 | if (tb[IFLA_MASTER]) |
| 2536 | struct net_device *br_dev; | 2556 | br_idx = nla_get_u32(tb[IFLA_MASTER]); |
| 2537 | const struct net_device_ops *ops; | 2557 | } |
| 2558 | |||
| 2559 | brport_idx = ifm->ifi_index; | ||
| 2538 | 2560 | ||
| 2539 | br_dev = netdev_master_upper_dev_get(dev); | 2561 | if (br_idx) { |
| 2540 | ops = br_dev->netdev_ops; | 2562 | br_dev = __dev_get_by_index(net, br_idx); |
| 2541 | if (ops->ndo_fdb_dump) | 2563 | if (!br_dev) |
| 2542 | idx = ops->ndo_fdb_dump(skb, cb, dev, idx); | 2564 | return -ENODEV; |
| 2565 | |||
| 2566 | ops = br_dev->netdev_ops; | ||
| 2567 | bdev = br_dev; | ||
| 2568 | } | ||
| 2569 | |||
| 2570 | for_each_netdev(net, dev) { | ||
| 2571 | if (brport_idx && (dev->ifindex != brport_idx)) | ||
| 2572 | continue; | ||
| 2573 | |||
| 2574 | if (!br_idx) { /* user did not specify a specific bridge */ | ||
| 2575 | if (dev->priv_flags & IFF_BRIDGE_PORT) { | ||
| 2576 | br_dev = netdev_master_upper_dev_get(dev); | ||
| 2577 | cops = br_dev->netdev_ops; | ||
| 2578 | } | ||
| 2579 | |||
| 2580 | bdev = dev; | ||
| 2581 | } else { | ||
| 2582 | if (dev != br_dev && | ||
| 2583 | !(dev->priv_flags & IFF_BRIDGE_PORT)) | ||
| 2584 | continue; | ||
| 2585 | |||
| 2586 | if (br_dev != netdev_master_upper_dev_get(dev) && | ||
| 2587 | !(dev->priv_flags & IFF_EBRIDGE)) | ||
| 2588 | continue; | ||
| 2589 | |||
| 2590 | bdev = br_dev; | ||
| 2591 | cops = ops; | ||
| 2592 | } | ||
| 2593 | |||
| 2594 | if (dev->priv_flags & IFF_BRIDGE_PORT) { | ||
| 2595 | if (cops && cops->ndo_fdb_dump) | ||
| 2596 | idx = cops->ndo_fdb_dump(skb, cb, br_dev, dev, | ||
| 2597 | idx); | ||
| 2543 | } | 2598 | } |
| 2544 | 2599 | ||
| 2600 | idx = ndo_dflt_fdb_dump(skb, cb, dev, NULL, idx); | ||
| 2545 | if (dev->netdev_ops->ndo_fdb_dump) | 2601 | if (dev->netdev_ops->ndo_fdb_dump) |
| 2546 | idx = dev->netdev_ops->ndo_fdb_dump(skb, cb, dev, idx); | 2602 | idx = dev->netdev_ops->ndo_fdb_dump(skb, cb, bdev, dev, |
| 2547 | else | 2603 | idx); |
| 2548 | idx = ndo_dflt_fdb_dump(skb, cb, dev, idx); | 2604 | |
| 2605 | cops = NULL; | ||
| 2549 | } | 2606 | } |
| 2550 | rcu_read_unlock(); | ||
| 2551 | 2607 | ||
| 2552 | cb->args[0] = idx; | 2608 | cb->args[0] = idx; |
| 2553 | return skb->len; | 2609 | return skb->len; |
diff --git a/net/core/skbuff.c b/net/core/skbuff.c index c1a33033cbe2..163b673f9e62 100644 --- a/net/core/skbuff.c +++ b/net/core/skbuff.c | |||
| @@ -62,6 +62,7 @@ | |||
| 62 | #include <linux/scatterlist.h> | 62 | #include <linux/scatterlist.h> |
| 63 | #include <linux/errqueue.h> | 63 | #include <linux/errqueue.h> |
| 64 | #include <linux/prefetch.h> | 64 | #include <linux/prefetch.h> |
| 65 | #include <linux/if_vlan.h> | ||
| 65 | 66 | ||
| 66 | #include <net/protocol.h> | 67 | #include <net/protocol.h> |
| 67 | #include <net/dst.h> | 68 | #include <net/dst.h> |
| @@ -2976,9 +2977,9 @@ struct sk_buff *skb_segment(struct sk_buff *head_skb, | |||
| 2976 | tail = nskb; | 2977 | tail = nskb; |
| 2977 | 2978 | ||
| 2978 | __copy_skb_header(nskb, head_skb); | 2979 | __copy_skb_header(nskb, head_skb); |
| 2979 | nskb->mac_len = head_skb->mac_len; | ||
| 2980 | 2980 | ||
| 2981 | skb_headers_offset_update(nskb, skb_headroom(nskb) - headroom); | 2981 | skb_headers_offset_update(nskb, skb_headroom(nskb) - headroom); |
| 2982 | skb_reset_mac_len(nskb); | ||
| 2982 | 2983 | ||
| 2983 | skb_copy_from_linear_data_offset(head_skb, -tnl_hlen, | 2984 | skb_copy_from_linear_data_offset(head_skb, -tnl_hlen, |
| 2984 | nskb->data - tnl_hlen, | 2985 | nskb->data - tnl_hlen, |
| @@ -3490,10 +3491,10 @@ int sock_queue_err_skb(struct sock *sk, struct sk_buff *skb) | |||
| 3490 | } | 3491 | } |
| 3491 | EXPORT_SYMBOL(sock_queue_err_skb); | 3492 | EXPORT_SYMBOL(sock_queue_err_skb); |
| 3492 | 3493 | ||
| 3493 | void skb_tstamp_tx(struct sk_buff *orig_skb, | 3494 | void __skb_tstamp_tx(struct sk_buff *orig_skb, |
| 3494 | struct skb_shared_hwtstamps *hwtstamps) | 3495 | struct skb_shared_hwtstamps *hwtstamps, |
| 3496 | struct sock *sk, int tstype) | ||
| 3495 | { | 3497 | { |
| 3496 | struct sock *sk = orig_skb->sk; | ||
| 3497 | struct sock_exterr_skb *serr; | 3498 | struct sock_exterr_skb *serr; |
| 3498 | struct sk_buff *skb; | 3499 | struct sk_buff *skb; |
| 3499 | int err; | 3500 | int err; |
| @@ -3521,12 +3522,26 @@ void skb_tstamp_tx(struct sk_buff *orig_skb, | |||
| 3521 | memset(serr, 0, sizeof(*serr)); | 3522 | memset(serr, 0, sizeof(*serr)); |
| 3522 | serr->ee.ee_errno = ENOMSG; | 3523 | serr->ee.ee_errno = ENOMSG; |
| 3523 | serr->ee.ee_origin = SO_EE_ORIGIN_TIMESTAMPING; | 3524 | serr->ee.ee_origin = SO_EE_ORIGIN_TIMESTAMPING; |
| 3525 | serr->ee.ee_info = tstype; | ||
| 3526 | if (sk->sk_tsflags & SOF_TIMESTAMPING_OPT_ID) { | ||
| 3527 | serr->ee.ee_data = skb_shinfo(skb)->tskey; | ||
| 3528 | if (sk->sk_protocol == IPPROTO_TCP) | ||
| 3529 | serr->ee.ee_data -= sk->sk_tskey; | ||
| 3530 | } | ||
| 3524 | 3531 | ||
| 3525 | err = sock_queue_err_skb(sk, skb); | 3532 | err = sock_queue_err_skb(sk, skb); |
| 3526 | 3533 | ||
| 3527 | if (err) | 3534 | if (err) |
| 3528 | kfree_skb(skb); | 3535 | kfree_skb(skb); |
| 3529 | } | 3536 | } |
| 3537 | EXPORT_SYMBOL_GPL(__skb_tstamp_tx); | ||
| 3538 | |||
| 3539 | void skb_tstamp_tx(struct sk_buff *orig_skb, | ||
| 3540 | struct skb_shared_hwtstamps *hwtstamps) | ||
| 3541 | { | ||
| 3542 | return __skb_tstamp_tx(orig_skb, hwtstamps, orig_skb->sk, | ||
| 3543 | SCM_TSTAMP_SND); | ||
| 3544 | } | ||
| 3530 | EXPORT_SYMBOL_GPL(skb_tstamp_tx); | 3545 | EXPORT_SYMBOL_GPL(skb_tstamp_tx); |
| 3531 | 3546 | ||
| 3532 | void skb_complete_wifi_ack(struct sk_buff *skb, bool acked) | 3547 | void skb_complete_wifi_ack(struct sk_buff *skb, bool acked) |
| @@ -3959,3 +3974,55 @@ unsigned int skb_gso_transport_seglen(const struct sk_buff *skb) | |||
| 3959 | return shinfo->gso_size; | 3974 | return shinfo->gso_size; |
| 3960 | } | 3975 | } |
| 3961 | EXPORT_SYMBOL_GPL(skb_gso_transport_seglen); | 3976 | EXPORT_SYMBOL_GPL(skb_gso_transport_seglen); |
| 3977 | |||
| 3978 | static struct sk_buff *skb_reorder_vlan_header(struct sk_buff *skb) | ||
| 3979 | { | ||
| 3980 | if (skb_cow(skb, skb_headroom(skb)) < 0) { | ||
| 3981 | kfree_skb(skb); | ||
| 3982 | return NULL; | ||
| 3983 | } | ||
| 3984 | |||
| 3985 | memmove(skb->data - ETH_HLEN, skb->data - VLAN_ETH_HLEN, 2 * ETH_ALEN); | ||
| 3986 | skb->mac_header += VLAN_HLEN; | ||
| 3987 | return skb; | ||
| 3988 | } | ||
| 3989 | |||
| 3990 | struct sk_buff *skb_vlan_untag(struct sk_buff *skb) | ||
| 3991 | { | ||
| 3992 | struct vlan_hdr *vhdr; | ||
| 3993 | u16 vlan_tci; | ||
| 3994 | |||
| 3995 | if (unlikely(vlan_tx_tag_present(skb))) { | ||
| 3996 | /* vlan_tci is already set-up so leave this for another time */ | ||
| 3997 | return skb; | ||
| 3998 | } | ||
| 3999 | |||
| 4000 | skb = skb_share_check(skb, GFP_ATOMIC); | ||
| 4001 | if (unlikely(!skb)) | ||
| 4002 | goto err_free; | ||
| 4003 | |||
| 4004 | if (unlikely(!pskb_may_pull(skb, VLAN_HLEN))) | ||
| 4005 | goto err_free; | ||
| 4006 | |||
| 4007 | vhdr = (struct vlan_hdr *)skb->data; | ||
| 4008 | vlan_tci = ntohs(vhdr->h_vlan_TCI); | ||
| 4009 | __vlan_hwaccel_put_tag(skb, skb->protocol, vlan_tci); | ||
| 4010 | |||
| 4011 | skb_pull_rcsum(skb, VLAN_HLEN); | ||
| 4012 | vlan_set_encap_proto(skb, vhdr); | ||
| 4013 | |||
| 4014 | skb = skb_reorder_vlan_header(skb); | ||
| 4015 | if (unlikely(!skb)) | ||
| 4016 | goto err_free; | ||
| 4017 | |||
| 4018 | skb_reset_network_header(skb); | ||
| 4019 | skb_reset_transport_header(skb); | ||
| 4020 | skb_reset_mac_len(skb); | ||
| 4021 | |||
| 4022 | return skb; | ||
| 4023 | |||
| 4024 | err_free: | ||
| 4025 | kfree_skb(skb); | ||
| 4026 | return NULL; | ||
| 4027 | } | ||
| 4028 | EXPORT_SYMBOL(skb_vlan_untag); | ||
diff --git a/net/core/sock.c b/net/core/sock.c index 026e01f70274..2714811afbd8 100644 --- a/net/core/sock.c +++ b/net/core/sock.c | |||
| @@ -491,7 +491,7 @@ int sk_receive_skb(struct sock *sk, struct sk_buff *skb, const int nested) | |||
| 491 | 491 | ||
| 492 | skb->dev = NULL; | 492 | skb->dev = NULL; |
| 493 | 493 | ||
| 494 | if (sk_rcvqueues_full(sk, skb, sk->sk_rcvbuf)) { | 494 | if (sk_rcvqueues_full(sk, sk->sk_rcvbuf)) { |
| 495 | atomic_inc(&sk->sk_drops); | 495 | atomic_inc(&sk->sk_drops); |
| 496 | goto discard_and_relse; | 496 | goto discard_and_relse; |
| 497 | } | 497 | } |
| @@ -848,24 +848,25 @@ set_rcvbuf: | |||
| 848 | ret = -EINVAL; | 848 | ret = -EINVAL; |
| 849 | break; | 849 | break; |
| 850 | } | 850 | } |
| 851 | sock_valbool_flag(sk, SOCK_TIMESTAMPING_TX_HARDWARE, | 851 | if (val & SOF_TIMESTAMPING_OPT_ID && |
| 852 | val & SOF_TIMESTAMPING_TX_HARDWARE); | 852 | !(sk->sk_tsflags & SOF_TIMESTAMPING_OPT_ID)) { |
| 853 | sock_valbool_flag(sk, SOCK_TIMESTAMPING_TX_SOFTWARE, | 853 | if (sk->sk_protocol == IPPROTO_TCP) { |
| 854 | val & SOF_TIMESTAMPING_TX_SOFTWARE); | 854 | if (sk->sk_state != TCP_ESTABLISHED) { |
| 855 | sock_valbool_flag(sk, SOCK_TIMESTAMPING_RX_HARDWARE, | 855 | ret = -EINVAL; |
| 856 | val & SOF_TIMESTAMPING_RX_HARDWARE); | 856 | break; |
| 857 | } | ||
| 858 | sk->sk_tskey = tcp_sk(sk)->snd_una; | ||
| 859 | } else { | ||
| 860 | sk->sk_tskey = 0; | ||
| 861 | } | ||
| 862 | } | ||
| 863 | sk->sk_tsflags = val; | ||
| 857 | if (val & SOF_TIMESTAMPING_RX_SOFTWARE) | 864 | if (val & SOF_TIMESTAMPING_RX_SOFTWARE) |
| 858 | sock_enable_timestamp(sk, | 865 | sock_enable_timestamp(sk, |
| 859 | SOCK_TIMESTAMPING_RX_SOFTWARE); | 866 | SOCK_TIMESTAMPING_RX_SOFTWARE); |
| 860 | else | 867 | else |
| 861 | sock_disable_timestamp(sk, | 868 | sock_disable_timestamp(sk, |
| 862 | (1UL << SOCK_TIMESTAMPING_RX_SOFTWARE)); | 869 | (1UL << SOCK_TIMESTAMPING_RX_SOFTWARE)); |
| 863 | sock_valbool_flag(sk, SOCK_TIMESTAMPING_SOFTWARE, | ||
| 864 | val & SOF_TIMESTAMPING_SOFTWARE); | ||
| 865 | sock_valbool_flag(sk, SOCK_TIMESTAMPING_SYS_HARDWARE, | ||
| 866 | val & SOF_TIMESTAMPING_SYS_HARDWARE); | ||
| 867 | sock_valbool_flag(sk, SOCK_TIMESTAMPING_RAW_HARDWARE, | ||
| 868 | val & SOF_TIMESTAMPING_RAW_HARDWARE); | ||
| 869 | break; | 870 | break; |
| 870 | 871 | ||
| 871 | case SO_RCVLOWAT: | 872 | case SO_RCVLOWAT: |
| @@ -1091,21 +1092,7 @@ int sock_getsockopt(struct socket *sock, int level, int optname, | |||
| 1091 | break; | 1092 | break; |
| 1092 | 1093 | ||
| 1093 | case SO_TIMESTAMPING: | 1094 | case SO_TIMESTAMPING: |
| 1094 | v.val = 0; | 1095 | v.val = sk->sk_tsflags; |
| 1095 | if (sock_flag(sk, SOCK_TIMESTAMPING_TX_HARDWARE)) | ||
| 1096 | v.val |= SOF_TIMESTAMPING_TX_HARDWARE; | ||
| 1097 | if (sock_flag(sk, SOCK_TIMESTAMPING_TX_SOFTWARE)) | ||
| 1098 | v.val |= SOF_TIMESTAMPING_TX_SOFTWARE; | ||
| 1099 | if (sock_flag(sk, SOCK_TIMESTAMPING_RX_HARDWARE)) | ||
| 1100 | v.val |= SOF_TIMESTAMPING_RX_HARDWARE; | ||
| 1101 | if (sock_flag(sk, SOCK_TIMESTAMPING_RX_SOFTWARE)) | ||
| 1102 | v.val |= SOF_TIMESTAMPING_RX_SOFTWARE; | ||
| 1103 | if (sock_flag(sk, SOCK_TIMESTAMPING_SOFTWARE)) | ||
| 1104 | v.val |= SOF_TIMESTAMPING_SOFTWARE; | ||
| 1105 | if (sock_flag(sk, SOCK_TIMESTAMPING_SYS_HARDWARE)) | ||
| 1106 | v.val |= SOF_TIMESTAMPING_SYS_HARDWARE; | ||
| 1107 | if (sock_flag(sk, SOCK_TIMESTAMPING_RAW_HARDWARE)) | ||
| 1108 | v.val |= SOF_TIMESTAMPING_RAW_HARDWARE; | ||
| 1109 | break; | 1096 | break; |
| 1110 | 1097 | ||
| 1111 | case SO_RCVTIMEO: | 1098 | case SO_RCVTIMEO: |
| @@ -1478,6 +1465,7 @@ static void sk_update_clone(const struct sock *sk, struct sock *newsk) | |||
| 1478 | struct sock *sk_clone_lock(const struct sock *sk, const gfp_t priority) | 1465 | struct sock *sk_clone_lock(const struct sock *sk, const gfp_t priority) |
| 1479 | { | 1466 | { |
| 1480 | struct sock *newsk; | 1467 | struct sock *newsk; |
| 1468 | bool is_charged = true; | ||
| 1481 | 1469 | ||
| 1482 | newsk = sk_prot_alloc(sk->sk_prot, priority, sk->sk_family); | 1470 | newsk = sk_prot_alloc(sk->sk_prot, priority, sk->sk_family); |
| 1483 | if (newsk != NULL) { | 1471 | if (newsk != NULL) { |
| @@ -1522,9 +1510,13 @@ struct sock *sk_clone_lock(const struct sock *sk, const gfp_t priority) | |||
| 1522 | 1510 | ||
| 1523 | filter = rcu_dereference_protected(newsk->sk_filter, 1); | 1511 | filter = rcu_dereference_protected(newsk->sk_filter, 1); |
| 1524 | if (filter != NULL) | 1512 | if (filter != NULL) |
| 1525 | sk_filter_charge(newsk, filter); | 1513 | /* though it's an empty new sock, the charging may fail |
| 1514 | * if sysctl_optmem_max was changed between creation of | ||
| 1515 | * original socket and cloning | ||
| 1516 | */ | ||
| 1517 | is_charged = sk_filter_charge(newsk, filter); | ||
| 1526 | 1518 | ||
| 1527 | if (unlikely(xfrm_sk_clone_policy(newsk))) { | 1519 | if (unlikely(!is_charged || xfrm_sk_clone_policy(newsk))) { |
| 1528 | /* It is still raw copy of parent, so invalidate | 1520 | /* It is still raw copy of parent, so invalidate |
| 1529 | * destructor and make plain sk_free() */ | 1521 | * destructor and make plain sk_free() */ |
| 1530 | newsk->sk_destruct = NULL; | 1522 | newsk->sk_destruct = NULL; |
diff --git a/net/core/sock_diag.c b/net/core/sock_diag.c index a4216a4c9572..ad704c757bb4 100644 --- a/net/core/sock_diag.c +++ b/net/core/sock_diag.c | |||
| @@ -68,8 +68,8 @@ int sock_diag_put_filterinfo(bool may_report_filterinfo, struct sock *sk, | |||
| 68 | if (!filter) | 68 | if (!filter) |
| 69 | goto out; | 69 | goto out; |
| 70 | 70 | ||
| 71 | fprog = filter->orig_prog; | 71 | fprog = filter->prog->orig_prog; |
| 72 | flen = sk_filter_proglen(fprog); | 72 | flen = bpf_classic_proglen(fprog); |
| 73 | 73 | ||
| 74 | attr = nla_reserve(skb, attrtype, flen); | 74 | attr = nla_reserve(skb, attrtype, flen); |
| 75 | if (attr == NULL) { | 75 | if (attr == NULL) { |
diff --git a/net/core/timestamping.c b/net/core/timestamping.c index 6521dfd8b7c8..a8770391ea5b 100644 --- a/net/core/timestamping.c +++ b/net/core/timestamping.c | |||
| @@ -43,31 +43,22 @@ void skb_clone_tx_timestamp(struct sk_buff *skb) | |||
| 43 | return; | 43 | return; |
| 44 | 44 | ||
| 45 | type = classify(skb); | 45 | type = classify(skb); |
| 46 | if (type == PTP_CLASS_NONE) | ||
| 47 | return; | ||
| 48 | |||
| 49 | phydev = skb->dev->phydev; | ||
| 50 | if (likely(phydev->drv->txtstamp)) { | ||
| 51 | if (!atomic_inc_not_zero(&sk->sk_refcnt)) | ||
| 52 | return; | ||
| 46 | 53 | ||
| 47 | switch (type) { | 54 | clone = skb_clone(skb, GFP_ATOMIC); |
| 48 | case PTP_CLASS_V1_IPV4: | 55 | if (!clone) { |
| 49 | case PTP_CLASS_V1_IPV6: | 56 | sock_put(sk); |
| 50 | case PTP_CLASS_V2_IPV4: | 57 | return; |
| 51 | case PTP_CLASS_V2_IPV6: | ||
| 52 | case PTP_CLASS_V2_L2: | ||
| 53 | case PTP_CLASS_V2_VLAN: | ||
| 54 | phydev = skb->dev->phydev; | ||
| 55 | if (likely(phydev->drv->txtstamp)) { | ||
| 56 | if (!atomic_inc_not_zero(&sk->sk_refcnt)) | ||
| 57 | return; | ||
| 58 | |||
| 59 | clone = skb_clone(skb, GFP_ATOMIC); | ||
| 60 | if (!clone) { | ||
| 61 | sock_put(sk); | ||
| 62 | return; | ||
| 63 | } | ||
| 64 | |||
| 65 | clone->sk = sk; | ||
| 66 | phydev->drv->txtstamp(phydev, clone, type); | ||
| 67 | } | 58 | } |
| 68 | break; | 59 | |
| 69 | default: | 60 | clone->sk = sk; |
| 70 | break; | 61 | phydev->drv->txtstamp(phydev, clone, type); |
| 71 | } | 62 | } |
| 72 | } | 63 | } |
| 73 | EXPORT_SYMBOL_GPL(skb_clone_tx_timestamp); | 64 | EXPORT_SYMBOL_GPL(skb_clone_tx_timestamp); |
| @@ -114,20 +105,12 @@ bool skb_defer_rx_timestamp(struct sk_buff *skb) | |||
| 114 | 105 | ||
| 115 | __skb_pull(skb, ETH_HLEN); | 106 | __skb_pull(skb, ETH_HLEN); |
| 116 | 107 | ||
| 117 | switch (type) { | 108 | if (type == PTP_CLASS_NONE) |
| 118 | case PTP_CLASS_V1_IPV4: | 109 | return false; |
| 119 | case PTP_CLASS_V1_IPV6: | 110 | |
| 120 | case PTP_CLASS_V2_IPV4: | 111 | phydev = skb->dev->phydev; |
| 121 | case PTP_CLASS_V2_IPV6: | 112 | if (likely(phydev->drv->rxtstamp)) |
| 122 | case PTP_CLASS_V2_L2: | 113 | return phydev->drv->rxtstamp(phydev, skb, type); |
| 123 | case PTP_CLASS_V2_VLAN: | ||
| 124 | phydev = skb->dev->phydev; | ||
| 125 | if (likely(phydev->drv->rxtstamp)) | ||
| 126 | return phydev->drv->rxtstamp(phydev, skb, type); | ||
| 127 | break; | ||
| 128 | default: | ||
| 129 | break; | ||
| 130 | } | ||
| 131 | 114 | ||
| 132 | return false; | 115 | return false; |
| 133 | } | 116 | } |
diff --git a/net/dcb/dcbnl.c b/net/dcb/dcbnl.c index f8b98d89c285..ca11d283bbeb 100644 --- a/net/dcb/dcbnl.c +++ b/net/dcb/dcbnl.c | |||
| @@ -471,7 +471,11 @@ static int dcbnl_getapp(struct net_device *netdev, struct nlmsghdr *nlh, | |||
| 471 | id = nla_get_u16(app_tb[DCB_APP_ATTR_ID]); | 471 | id = nla_get_u16(app_tb[DCB_APP_ATTR_ID]); |
| 472 | 472 | ||
| 473 | if (netdev->dcbnl_ops->getapp) { | 473 | if (netdev->dcbnl_ops->getapp) { |
| 474 | up = netdev->dcbnl_ops->getapp(netdev, idtype, id); | 474 | ret = netdev->dcbnl_ops->getapp(netdev, idtype, id); |
| 475 | if (ret < 0) | ||
| 476 | return ret; | ||
| 477 | else | ||
| 478 | up = ret; | ||
| 475 | } else { | 479 | } else { |
| 476 | struct dcb_app app = { | 480 | struct dcb_app app = { |
| 477 | .selector = idtype, | 481 | .selector = idtype, |
| @@ -538,6 +542,8 @@ static int dcbnl_setapp(struct net_device *netdev, struct nlmsghdr *nlh, | |||
| 538 | 542 | ||
| 539 | if (netdev->dcbnl_ops->setapp) { | 543 | if (netdev->dcbnl_ops->setapp) { |
| 540 | ret = netdev->dcbnl_ops->setapp(netdev, idtype, id, up); | 544 | ret = netdev->dcbnl_ops->setapp(netdev, idtype, id, up); |
| 545 | if (ret < 0) | ||
| 546 | return ret; | ||
| 541 | } else { | 547 | } else { |
| 542 | struct dcb_app app; | 548 | struct dcb_app app; |
| 543 | app.selector = idtype; | 549 | app.selector = idtype; |
| @@ -1770,7 +1776,7 @@ EXPORT_SYMBOL(dcb_getapp); | |||
| 1770 | * | 1776 | * |
| 1771 | * Priority 0 is an invalid priority in CEE spec. This routine | 1777 | * Priority 0 is an invalid priority in CEE spec. This routine |
| 1772 | * removes applications from the app list if the priority is | 1778 | * removes applications from the app list if the priority is |
| 1773 | * set to zero. | 1779 | * set to zero. Priority is expected to be 8-bit 802.1p user priority bitmap |
| 1774 | */ | 1780 | */ |
| 1775 | int dcb_setapp(struct net_device *dev, struct dcb_app *new) | 1781 | int dcb_setapp(struct net_device *dev, struct dcb_app *new) |
| 1776 | { | 1782 | { |
| @@ -1831,7 +1837,8 @@ EXPORT_SYMBOL(dcb_ieee_getapp_mask); | |||
| 1831 | * | 1837 | * |
| 1832 | * This adds Application data to the list. Multiple application | 1838 | * This adds Application data to the list. Multiple application |
| 1833 | * entries may exists for the same selector and protocol as long | 1839 | * entries may exists for the same selector and protocol as long |
| 1834 | * as the priorities are different. | 1840 | * as the priorities are different. Priority is expected to be a |
| 1841 | * 3-bit unsigned integer | ||
| 1835 | */ | 1842 | */ |
| 1836 | int dcb_ieee_setapp(struct net_device *dev, struct dcb_app *new) | 1843 | int dcb_ieee_setapp(struct net_device *dev, struct dcb_app *new) |
| 1837 | { | 1844 | { |
diff --git a/net/dccp/ipv6.c b/net/dccp/ipv6.c index 4db3c2a1679c..04cb17d4b0ce 100644 --- a/net/dccp/ipv6.c +++ b/net/dccp/ipv6.c | |||
| @@ -386,7 +386,7 @@ static int dccp_v6_conn_request(struct sock *sk, struct sk_buff *skb) | |||
| 386 | if (sk_acceptq_is_full(sk) && inet_csk_reqsk_queue_young(sk) > 1) | 386 | if (sk_acceptq_is_full(sk) && inet_csk_reqsk_queue_young(sk) > 1) |
| 387 | goto drop; | 387 | goto drop; |
| 388 | 388 | ||
| 389 | req = inet6_reqsk_alloc(&dccp6_request_sock_ops); | 389 | req = inet_reqsk_alloc(&dccp6_request_sock_ops); |
| 390 | if (req == NULL) | 390 | if (req == NULL) |
| 391 | goto drop; | 391 | goto drop; |
| 392 | 392 | ||
diff --git a/net/dccp/minisocks.c b/net/dccp/minisocks.c index c69eb9c4fbb8..b50dc436db1f 100644 --- a/net/dccp/minisocks.c +++ b/net/dccp/minisocks.c | |||
| @@ -55,11 +55,9 @@ void dccp_time_wait(struct sock *sk, int state, int timeo) | |||
| 55 | const int rto = (icsk->icsk_rto << 2) - (icsk->icsk_rto >> 1); | 55 | const int rto = (icsk->icsk_rto << 2) - (icsk->icsk_rto >> 1); |
| 56 | #if IS_ENABLED(CONFIG_IPV6) | 56 | #if IS_ENABLED(CONFIG_IPV6) |
| 57 | if (tw->tw_family == PF_INET6) { | 57 | if (tw->tw_family == PF_INET6) { |
| 58 | const struct ipv6_pinfo *np = inet6_sk(sk); | ||
| 59 | |||
| 60 | tw->tw_v6_daddr = sk->sk_v6_daddr; | 58 | tw->tw_v6_daddr = sk->sk_v6_daddr; |
| 61 | tw->tw_v6_rcv_saddr = sk->sk_v6_rcv_saddr; | 59 | tw->tw_v6_rcv_saddr = sk->sk_v6_rcv_saddr; |
| 62 | tw->tw_ipv6only = np->ipv6only; | 60 | tw->tw_ipv6only = sk->sk_ipv6only; |
| 63 | } | 61 | } |
| 64 | #endif | 62 | #endif |
| 65 | /* Linkage updates. */ | 63 | /* Linkage updates. */ |
diff --git a/net/dns_resolver/dns_key.c b/net/dns_resolver/dns_key.c index bf8584339048..f380b2c58178 100644 --- a/net/dns_resolver/dns_key.c +++ b/net/dns_resolver/dns_key.c | |||
| @@ -46,7 +46,7 @@ const struct cred *dns_resolver_cache; | |||
| 46 | #define DNS_ERRORNO_OPTION "dnserror" | 46 | #define DNS_ERRORNO_OPTION "dnserror" |
| 47 | 47 | ||
| 48 | /* | 48 | /* |
| 49 | * Instantiate a user defined key for dns_resolver. | 49 | * Preparse instantiation data for a dns_resolver key. |
| 50 | * | 50 | * |
| 51 | * The data must be a NUL-terminated string, with the NUL char accounted in | 51 | * The data must be a NUL-terminated string, with the NUL char accounted in |
| 52 | * datalen. | 52 | * datalen. |
| @@ -58,17 +58,15 @@ const struct cred *dns_resolver_cache; | |||
| 58 | * "ip1,ip2,...#foo=bar" | 58 | * "ip1,ip2,...#foo=bar" |
| 59 | */ | 59 | */ |
| 60 | static int | 60 | static int |
| 61 | dns_resolver_instantiate(struct key *key, struct key_preparsed_payload *prep) | 61 | dns_resolver_preparse(struct key_preparsed_payload *prep) |
| 62 | { | 62 | { |
| 63 | struct user_key_payload *upayload; | 63 | struct user_key_payload *upayload; |
| 64 | unsigned long derrno; | 64 | unsigned long derrno; |
| 65 | int ret; | 65 | int ret; |
| 66 | size_t datalen = prep->datalen, result_len = 0; | 66 | int datalen = prep->datalen, result_len = 0; |
| 67 | const char *data = prep->data, *end, *opt; | 67 | const char *data = prep->data, *end, *opt; |
| 68 | 68 | ||
| 69 | kenter("%%%d,%s,'%*.*s',%zu", | 69 | kenter("'%*.*s',%u", datalen, datalen, data, datalen); |
| 70 | key->serial, key->description, | ||
| 71 | (int)datalen, (int)datalen, data, datalen); | ||
| 72 | 70 | ||
| 73 | if (datalen <= 1 || !data || data[datalen - 1] != '\0') | 71 | if (datalen <= 1 || !data || data[datalen - 1] != '\0') |
| 74 | return -EINVAL; | 72 | return -EINVAL; |
| @@ -95,8 +93,7 @@ dns_resolver_instantiate(struct key *key, struct key_preparsed_payload *prep) | |||
| 95 | opt_len = next_opt - opt; | 93 | opt_len = next_opt - opt; |
| 96 | if (!opt_len) { | 94 | if (!opt_len) { |
| 97 | printk(KERN_WARNING | 95 | printk(KERN_WARNING |
| 98 | "Empty option to dns_resolver key %d\n", | 96 | "Empty option to dns_resolver key\n"); |
| 99 | key->serial); | ||
| 100 | return -EINVAL; | 97 | return -EINVAL; |
| 101 | } | 98 | } |
| 102 | 99 | ||
| @@ -125,30 +122,28 @@ dns_resolver_instantiate(struct key *key, struct key_preparsed_payload *prep) | |||
| 125 | goto bad_option_value; | 122 | goto bad_option_value; |
| 126 | 123 | ||
| 127 | kdebug("dns error no. = %lu", derrno); | 124 | kdebug("dns error no. = %lu", derrno); |
| 128 | key->type_data.x[0] = -derrno; | 125 | prep->type_data[0] = ERR_PTR(-derrno); |
| 129 | continue; | 126 | continue; |
| 130 | } | 127 | } |
| 131 | 128 | ||
| 132 | bad_option_value: | 129 | bad_option_value: |
| 133 | printk(KERN_WARNING | 130 | printk(KERN_WARNING |
| 134 | "Option '%*.*s' to dns_resolver key %d:" | 131 | "Option '%*.*s' to dns_resolver key:" |
| 135 | " bad/missing value\n", | 132 | " bad/missing value\n", |
| 136 | opt_nlen, opt_nlen, opt, key->serial); | 133 | opt_nlen, opt_nlen, opt); |
| 137 | return -EINVAL; | 134 | return -EINVAL; |
| 138 | } while (opt = next_opt + 1, opt < end); | 135 | } while (opt = next_opt + 1, opt < end); |
| 139 | } | 136 | } |
| 140 | 137 | ||
| 141 | /* don't cache the result if we're caching an error saying there's no | 138 | /* don't cache the result if we're caching an error saying there's no |
| 142 | * result */ | 139 | * result */ |
| 143 | if (key->type_data.x[0]) { | 140 | if (prep->type_data[0]) { |
| 144 | kleave(" = 0 [h_error %ld]", key->type_data.x[0]); | 141 | kleave(" = 0 [h_error %ld]", PTR_ERR(prep->type_data[0])); |
| 145 | return 0; | 142 | return 0; |
| 146 | } | 143 | } |
| 147 | 144 | ||
| 148 | kdebug("store result"); | 145 | kdebug("store result"); |
| 149 | ret = key_payload_reserve(key, result_len); | 146 | prep->quotalen = result_len; |
| 150 | if (ret < 0) | ||
| 151 | return -EINVAL; | ||
| 152 | 147 | ||
| 153 | upayload = kmalloc(sizeof(*upayload) + result_len + 1, GFP_KERNEL); | 148 | upayload = kmalloc(sizeof(*upayload) + result_len + 1, GFP_KERNEL); |
| 154 | if (!upayload) { | 149 | if (!upayload) { |
| @@ -159,13 +154,23 @@ dns_resolver_instantiate(struct key *key, struct key_preparsed_payload *prep) | |||
| 159 | upayload->datalen = result_len; | 154 | upayload->datalen = result_len; |
| 160 | memcpy(upayload->data, data, result_len); | 155 | memcpy(upayload->data, data, result_len); |
| 161 | upayload->data[result_len] = '\0'; | 156 | upayload->data[result_len] = '\0'; |
| 162 | rcu_assign_pointer(key->payload.data, upayload); | ||
| 163 | 157 | ||
| 158 | prep->payload[0] = upayload; | ||
| 164 | kleave(" = 0"); | 159 | kleave(" = 0"); |
| 165 | return 0; | 160 | return 0; |
| 166 | } | 161 | } |
| 167 | 162 | ||
| 168 | /* | 163 | /* |
| 164 | * Clean up the preparse data | ||
| 165 | */ | ||
| 166 | static void dns_resolver_free_preparse(struct key_preparsed_payload *prep) | ||
| 167 | { | ||
| 168 | pr_devel("==>%s()\n", __func__); | ||
| 169 | |||
| 170 | kfree(prep->payload[0]); | ||
| 171 | } | ||
| 172 | |||
| 173 | /* | ||
| 169 | * The description is of the form "[<type>:]<domain_name>" | 174 | * The description is of the form "[<type>:]<domain_name>" |
| 170 | * | 175 | * |
| 171 | * The domain name may be a simple name or an absolute domain name (which | 176 | * The domain name may be a simple name or an absolute domain name (which |
| @@ -234,7 +239,9 @@ static long dns_resolver_read(const struct key *key, | |||
| 234 | 239 | ||
| 235 | struct key_type key_type_dns_resolver = { | 240 | struct key_type key_type_dns_resolver = { |
| 236 | .name = "dns_resolver", | 241 | .name = "dns_resolver", |
| 237 | .instantiate = dns_resolver_instantiate, | 242 | .preparse = dns_resolver_preparse, |
| 243 | .free_preparse = dns_resolver_free_preparse, | ||
| 244 | .instantiate = generic_key_instantiate, | ||
| 238 | .match = dns_resolver_match, | 245 | .match = dns_resolver_match, |
| 239 | .revoke = user_revoke, | 246 | .revoke = user_revoke, |
| 240 | .destroy = user_destroy, | 247 | .destroy = user_destroy, |
diff --git a/net/dns_resolver/dns_query.c b/net/dns_resolver/dns_query.c index dd8696a3dbec..39d2c39bdf87 100644 --- a/net/dns_resolver/dns_query.c +++ b/net/dns_resolver/dns_query.c | |||
| @@ -129,6 +129,7 @@ int dns_query(const char *type, const char *name, size_t namelen, | |||
| 129 | } | 129 | } |
| 130 | 130 | ||
| 131 | down_read(&rkey->sem); | 131 | down_read(&rkey->sem); |
| 132 | set_bit(KEY_FLAG_ROOT_CAN_INVAL, &rkey->flags); | ||
| 132 | rkey->perm |= KEY_USR_VIEW; | 133 | rkey->perm |= KEY_USR_VIEW; |
| 133 | 134 | ||
| 134 | ret = key_validate(rkey); | 135 | ret = key_validate(rkey); |
diff --git a/net/dsa/dsa.c b/net/dsa/dsa.c index 5db37cef50a9..0a49632fac47 100644 --- a/net/dsa/dsa.c +++ b/net/dsa/dsa.c | |||
| @@ -351,8 +351,7 @@ static void dsa_of_free_platform_data(struct dsa_platform_data *pd) | |||
| 351 | for (i = 0; i < pd->nr_chips; i++) { | 351 | for (i = 0; i < pd->nr_chips; i++) { |
| 352 | port_index = 0; | 352 | port_index = 0; |
| 353 | while (port_index < DSA_MAX_PORTS) { | 353 | while (port_index < DSA_MAX_PORTS) { |
| 354 | if (pd->chip[i].port_names[port_index]) | 354 | kfree(pd->chip[i].port_names[port_index]); |
| 355 | kfree(pd->chip[i].port_names[port_index]); | ||
| 356 | port_index++; | 355 | port_index++; |
| 357 | } | 356 | } |
| 358 | kfree(pd->chip[i].rtable); | 357 | kfree(pd->chip[i].rtable); |
diff --git a/net/dsa/slave.c b/net/dsa/slave.c index 64c5af0a10dd..45a1e34c89e0 100644 --- a/net/dsa/slave.c +++ b/net/dsa/slave.c | |||
| @@ -340,8 +340,8 @@ dsa_slave_create(struct dsa_switch *ds, struct device *parent, | |||
| 340 | struct dsa_slave_priv *p; | 340 | struct dsa_slave_priv *p; |
| 341 | int ret; | 341 | int ret; |
| 342 | 342 | ||
| 343 | slave_dev = alloc_netdev(sizeof(struct dsa_slave_priv), | 343 | slave_dev = alloc_netdev(sizeof(struct dsa_slave_priv), name, |
| 344 | name, ether_setup); | 344 | NET_NAME_UNKNOWN, ether_setup); |
| 345 | if (slave_dev == NULL) | 345 | if (slave_dev == NULL) |
| 346 | return slave_dev; | 346 | return slave_dev; |
| 347 | 347 | ||
diff --git a/net/ethernet/eth.c b/net/ethernet/eth.c index 5dc638cad2e1..f405e0592407 100644 --- a/net/ethernet/eth.c +++ b/net/ethernet/eth.c | |||
| @@ -390,7 +390,8 @@ EXPORT_SYMBOL(ether_setup); | |||
| 390 | struct net_device *alloc_etherdev_mqs(int sizeof_priv, unsigned int txqs, | 390 | struct net_device *alloc_etherdev_mqs(int sizeof_priv, unsigned int txqs, |
| 391 | unsigned int rxqs) | 391 | unsigned int rxqs) |
| 392 | { | 392 | { |
| 393 | return alloc_netdev_mqs(sizeof_priv, "eth%d", ether_setup, txqs, rxqs); | 393 | return alloc_netdev_mqs(sizeof_priv, "eth%d", NET_NAME_UNKNOWN, |
| 394 | ether_setup, txqs, rxqs); | ||
| 394 | } | 395 | } |
| 395 | EXPORT_SYMBOL(alloc_etherdev_mqs); | 396 | EXPORT_SYMBOL(alloc_etherdev_mqs); |
| 396 | 397 | ||
diff --git a/net/hsr/Makefile b/net/hsr/Makefile index b68359f181cc..9ae972a820f4 100644 --- a/net/hsr/Makefile +++ b/net/hsr/Makefile | |||
| @@ -4,4 +4,5 @@ | |||
| 4 | 4 | ||
| 5 | obj-$(CONFIG_HSR) += hsr.o | 5 | obj-$(CONFIG_HSR) += hsr.o |
| 6 | 6 | ||
| 7 | hsr-y := hsr_main.o hsr_framereg.o hsr_device.o hsr_netlink.o | 7 | hsr-y := hsr_main.o hsr_framereg.o hsr_device.o \ |
| 8 | hsr_netlink.o hsr_slave.o hsr_forward.o | ||
diff --git a/net/hsr/hsr_device.c b/net/hsr/hsr_device.c index e5302b7f7ca9..a138d75751df 100644 --- a/net/hsr/hsr_device.c +++ b/net/hsr/hsr_device.c | |||
| @@ -1,4 +1,4 @@ | |||
| 1 | /* Copyright 2011-2013 Autronica Fire and Security AS | 1 | /* Copyright 2011-2014 Autronica Fire and Security AS |
| 2 | * | 2 | * |
| 3 | * This program is free software; you can redistribute it and/or modify it | 3 | * This program is free software; you can redistribute it and/or modify it |
| 4 | * under the terms of the GNU General Public License as published by the Free | 4 | * under the terms of the GNU General Public License as published by the Free |
| @@ -6,7 +6,7 @@ | |||
| 6 | * any later version. | 6 | * any later version. |
| 7 | * | 7 | * |
| 8 | * Author(s): | 8 | * Author(s): |
| 9 | * 2011-2013 Arvid Brodin, arvid.brodin@xdin.com | 9 | * 2011-2014 Arvid Brodin, arvid.brodin@alten.se |
| 10 | * | 10 | * |
| 11 | * This file contains device methods for creating, using and destroying | 11 | * This file contains device methods for creating, using and destroying |
| 12 | * virtual HSR devices. | 12 | * virtual HSR devices. |
| @@ -15,12 +15,13 @@ | |||
| 15 | #include <linux/netdevice.h> | 15 | #include <linux/netdevice.h> |
| 16 | #include <linux/skbuff.h> | 16 | #include <linux/skbuff.h> |
| 17 | #include <linux/etherdevice.h> | 17 | #include <linux/etherdevice.h> |
| 18 | #include <linux/if_arp.h> | ||
| 19 | #include <linux/rtnetlink.h> | 18 | #include <linux/rtnetlink.h> |
| 20 | #include <linux/pkt_sched.h> | 19 | #include <linux/pkt_sched.h> |
| 21 | #include "hsr_device.h" | 20 | #include "hsr_device.h" |
| 21 | #include "hsr_slave.h" | ||
| 22 | #include "hsr_framereg.h" | 22 | #include "hsr_framereg.h" |
| 23 | #include "hsr_main.h" | 23 | #include "hsr_main.h" |
| 24 | #include "hsr_forward.h" | ||
| 24 | 25 | ||
| 25 | 26 | ||
| 26 | static bool is_admin_up(struct net_device *dev) | 27 | static bool is_admin_up(struct net_device *dev) |
| @@ -45,75 +46,108 @@ static void __hsr_set_operstate(struct net_device *dev, int transition) | |||
| 45 | } | 46 | } |
| 46 | } | 47 | } |
| 47 | 48 | ||
| 48 | void hsr_set_operstate(struct net_device *hsr_dev, struct net_device *slave1, | 49 | static void hsr_set_operstate(struct hsr_port *master, bool has_carrier) |
| 49 | struct net_device *slave2) | ||
| 50 | { | 50 | { |
| 51 | if (!is_admin_up(hsr_dev)) { | 51 | if (!is_admin_up(master->dev)) { |
| 52 | __hsr_set_operstate(hsr_dev, IF_OPER_DOWN); | 52 | __hsr_set_operstate(master->dev, IF_OPER_DOWN); |
| 53 | return; | 53 | return; |
| 54 | } | 54 | } |
| 55 | 55 | ||
| 56 | if (is_slave_up(slave1) || is_slave_up(slave2)) | 56 | if (has_carrier) |
| 57 | __hsr_set_operstate(hsr_dev, IF_OPER_UP); | 57 | __hsr_set_operstate(master->dev, IF_OPER_UP); |
| 58 | else | 58 | else |
| 59 | __hsr_set_operstate(hsr_dev, IF_OPER_LOWERLAYERDOWN); | 59 | __hsr_set_operstate(master->dev, IF_OPER_LOWERLAYERDOWN); |
| 60 | } | 60 | } |
| 61 | 61 | ||
| 62 | void hsr_set_carrier(struct net_device *hsr_dev, struct net_device *slave1, | 62 | static bool hsr_check_carrier(struct hsr_port *master) |
| 63 | struct net_device *slave2) | ||
| 64 | { | 63 | { |
| 65 | if (is_slave_up(slave1) || is_slave_up(slave2)) | 64 | struct hsr_port *port; |
| 66 | netif_carrier_on(hsr_dev); | 65 | bool has_carrier; |
| 66 | |||
| 67 | has_carrier = false; | ||
| 68 | |||
| 69 | rcu_read_lock(); | ||
| 70 | hsr_for_each_port(master->hsr, port) | ||
| 71 | if ((port->type != HSR_PT_MASTER) && is_slave_up(port->dev)) { | ||
| 72 | has_carrier = true; | ||
| 73 | break; | ||
| 74 | } | ||
| 75 | rcu_read_unlock(); | ||
| 76 | |||
| 77 | if (has_carrier) | ||
| 78 | netif_carrier_on(master->dev); | ||
| 67 | else | 79 | else |
| 68 | netif_carrier_off(hsr_dev); | 80 | netif_carrier_off(master->dev); |
| 81 | |||
| 82 | return has_carrier; | ||
| 69 | } | 83 | } |
| 70 | 84 | ||
| 71 | 85 | ||
| 72 | void hsr_check_announce(struct net_device *hsr_dev, int old_operstate) | 86 | static void hsr_check_announce(struct net_device *hsr_dev, |
| 87 | unsigned char old_operstate) | ||
| 73 | { | 88 | { |
| 74 | struct hsr_priv *hsr_priv; | 89 | struct hsr_priv *hsr; |
| 75 | 90 | ||
| 76 | hsr_priv = netdev_priv(hsr_dev); | 91 | hsr = netdev_priv(hsr_dev); |
| 77 | 92 | ||
| 78 | if ((hsr_dev->operstate == IF_OPER_UP) && (old_operstate != IF_OPER_UP)) { | 93 | if ((hsr_dev->operstate == IF_OPER_UP) && (old_operstate != IF_OPER_UP)) { |
| 79 | /* Went up */ | 94 | /* Went up */ |
| 80 | hsr_priv->announce_count = 0; | 95 | hsr->announce_count = 0; |
| 81 | hsr_priv->announce_timer.expires = jiffies + | 96 | hsr->announce_timer.expires = jiffies + |
| 82 | msecs_to_jiffies(HSR_ANNOUNCE_INTERVAL); | 97 | msecs_to_jiffies(HSR_ANNOUNCE_INTERVAL); |
| 83 | add_timer(&hsr_priv->announce_timer); | 98 | add_timer(&hsr->announce_timer); |
| 84 | } | 99 | } |
| 85 | 100 | ||
| 86 | if ((hsr_dev->operstate != IF_OPER_UP) && (old_operstate == IF_OPER_UP)) | 101 | if ((hsr_dev->operstate != IF_OPER_UP) && (old_operstate == IF_OPER_UP)) |
| 87 | /* Went down */ | 102 | /* Went down */ |
| 88 | del_timer(&hsr_priv->announce_timer); | 103 | del_timer(&hsr->announce_timer); |
| 89 | } | 104 | } |
| 90 | 105 | ||
| 91 | 106 | void hsr_check_carrier_and_operstate(struct hsr_priv *hsr) | |
| 92 | int hsr_get_max_mtu(struct hsr_priv *hsr_priv) | ||
| 93 | { | 107 | { |
| 94 | int mtu_max; | 108 | struct hsr_port *master; |
| 95 | 109 | unsigned char old_operstate; | |
| 96 | if (hsr_priv->slave[0] && hsr_priv->slave[1]) | 110 | bool has_carrier; |
| 97 | mtu_max = min(hsr_priv->slave[0]->mtu, hsr_priv->slave[1]->mtu); | ||
| 98 | else if (hsr_priv->slave[0]) | ||
| 99 | mtu_max = hsr_priv->slave[0]->mtu; | ||
| 100 | else if (hsr_priv->slave[1]) | ||
| 101 | mtu_max = hsr_priv->slave[1]->mtu; | ||
| 102 | else | ||
| 103 | mtu_max = HSR_TAGLEN; | ||
| 104 | 111 | ||
| 105 | return mtu_max - HSR_TAGLEN; | 112 | master = hsr_port_get_hsr(hsr, HSR_PT_MASTER); |
| 113 | /* netif_stacked_transfer_operstate() cannot be used here since | ||
| 114 | * it doesn't set IF_OPER_LOWERLAYERDOWN (?) | ||
| 115 | */ | ||
| 116 | old_operstate = master->dev->operstate; | ||
| 117 | has_carrier = hsr_check_carrier(master); | ||
| 118 | hsr_set_operstate(master, has_carrier); | ||
| 119 | hsr_check_announce(master->dev, old_operstate); | ||
| 106 | } | 120 | } |
| 107 | 121 | ||
| 122 | int hsr_get_max_mtu(struct hsr_priv *hsr) | ||
| 123 | { | ||
| 124 | unsigned int mtu_max; | ||
| 125 | struct hsr_port *port; | ||
| 126 | |||
| 127 | mtu_max = ETH_DATA_LEN; | ||
| 128 | rcu_read_lock(); | ||
| 129 | hsr_for_each_port(hsr, port) | ||
| 130 | if (port->type != HSR_PT_MASTER) | ||
| 131 | mtu_max = min(port->dev->mtu, mtu_max); | ||
| 132 | rcu_read_unlock(); | ||
| 133 | |||
| 134 | if (mtu_max < HSR_HLEN) | ||
| 135 | return 0; | ||
| 136 | return mtu_max - HSR_HLEN; | ||
| 137 | } | ||
| 138 | |||
| 139 | |||
| 108 | static int hsr_dev_change_mtu(struct net_device *dev, int new_mtu) | 140 | static int hsr_dev_change_mtu(struct net_device *dev, int new_mtu) |
| 109 | { | 141 | { |
| 110 | struct hsr_priv *hsr_priv; | 142 | struct hsr_priv *hsr; |
| 143 | struct hsr_port *master; | ||
| 111 | 144 | ||
| 112 | hsr_priv = netdev_priv(dev); | 145 | hsr = netdev_priv(dev); |
| 146 | master = hsr_port_get_hsr(hsr, HSR_PT_MASTER); | ||
| 113 | 147 | ||
| 114 | if (new_mtu > hsr_get_max_mtu(hsr_priv)) { | 148 | if (new_mtu > hsr_get_max_mtu(hsr)) { |
| 115 | netdev_info(hsr_priv->dev, "A HSR master's MTU cannot be greater than the smallest MTU of its slaves minus the HSR Tag length (%d octets).\n", | 149 | netdev_info(master->dev, "A HSR master's MTU cannot be greater than the smallest MTU of its slaves minus the HSR Tag length (%d octets).\n", |
| 116 | HSR_TAGLEN); | 150 | HSR_HLEN); |
| 117 | return -EINVAL; | 151 | return -EINVAL; |
| 118 | } | 152 | } |
| 119 | 153 | ||
| @@ -124,164 +158,95 @@ static int hsr_dev_change_mtu(struct net_device *dev, int new_mtu) | |||
| 124 | 158 | ||
| 125 | static int hsr_dev_open(struct net_device *dev) | 159 | static int hsr_dev_open(struct net_device *dev) |
| 126 | { | 160 | { |
| 127 | struct hsr_priv *hsr_priv; | 161 | struct hsr_priv *hsr; |
| 128 | int i; | 162 | struct hsr_port *port; |
| 129 | char *slave_name; | 163 | char designation; |
| 130 | 164 | ||
| 131 | hsr_priv = netdev_priv(dev); | 165 | hsr = netdev_priv(dev); |
| 166 | designation = '\0'; | ||
| 132 | 167 | ||
| 133 | for (i = 0; i < HSR_MAX_SLAVE; i++) { | 168 | rcu_read_lock(); |
| 134 | if (hsr_priv->slave[i]) | 169 | hsr_for_each_port(hsr, port) { |
| 135 | slave_name = hsr_priv->slave[i]->name; | 170 | if (port->type == HSR_PT_MASTER) |
| 136 | else | 171 | continue; |
| 137 | slave_name = "null"; | 172 | switch (port->type) { |
| 138 | 173 | case HSR_PT_SLAVE_A: | |
| 139 | if (!is_slave_up(hsr_priv->slave[i])) | 174 | designation = 'A'; |
| 140 | netdev_warn(dev, "Slave %c (%s) is not up; please bring it up to get a working HSR network\n", | 175 | break; |
| 141 | 'A' + i, slave_name); | 176 | case HSR_PT_SLAVE_B: |
| 177 | designation = 'B'; | ||
| 178 | break; | ||
| 179 | default: | ||
| 180 | designation = '?'; | ||
| 181 | } | ||
| 182 | if (!is_slave_up(port->dev)) | ||
| 183 | netdev_warn(dev, "Slave %c (%s) is not up; please bring it up to get a fully working HSR network\n", | ||
| 184 | designation, port->dev->name); | ||
| 142 | } | 185 | } |
| 186 | rcu_read_unlock(); | ||
| 187 | |||
| 188 | if (designation == '\0') | ||
| 189 | netdev_warn(dev, "No slave devices configured\n"); | ||
| 143 | 190 | ||
| 144 | return 0; | 191 | return 0; |
| 145 | } | 192 | } |
| 146 | 193 | ||
| 194 | |||
| 147 | static int hsr_dev_close(struct net_device *dev) | 195 | static int hsr_dev_close(struct net_device *dev) |
| 148 | { | 196 | { |
| 149 | /* Nothing to do here. We could try to restore the state of the slaves | 197 | /* Nothing to do here. */ |
| 150 | * to what they were before being changed by the hsr master dev's state, | ||
| 151 | * but they might have been changed manually in the mean time too, so | ||
| 152 | * taking them up or down here might be confusing and is probably not a | ||
| 153 | * good idea. | ||
| 154 | */ | ||
| 155 | return 0; | 198 | return 0; |
| 156 | } | 199 | } |
| 157 | 200 | ||
| 158 | 201 | ||
| 159 | static void hsr_fill_tag(struct hsr_ethhdr *hsr_ethhdr, struct hsr_priv *hsr_priv) | 202 | static netdev_features_t hsr_features_recompute(struct hsr_priv *hsr, |
| 203 | netdev_features_t features) | ||
| 160 | { | 204 | { |
| 161 | unsigned long irqflags; | 205 | netdev_features_t mask; |
| 206 | struct hsr_port *port; | ||
| 162 | 207 | ||
| 163 | /* IEC 62439-1:2010, p 48, says the 4-bit "path" field can take values | 208 | mask = features; |
| 164 | * between 0001-1001 ("ring identifier", for regular HSR frames), | ||
| 165 | * or 1111 ("HSR management", supervision frames). Unfortunately, the | ||
| 166 | * spec writers forgot to explain what a "ring identifier" is, or | ||
| 167 | * how it is used. So we just set this to 0001 for regular frames, | ||
| 168 | * and 1111 for supervision frames. | ||
| 169 | */ | ||
| 170 | set_hsr_tag_path(&hsr_ethhdr->hsr_tag, 0x1); | ||
| 171 | 209 | ||
| 172 | /* IEC 62439-1:2010, p 12: "The link service data unit in an Ethernet | 210 | /* Mask out all features that, if supported by one device, should be |
| 173 | * frame is the content of the frame located between the Length/Type | 211 | * enabled for all devices (see NETIF_F_ONE_FOR_ALL). |
| 174 | * field and the Frame Check Sequence." | ||
| 175 | * | 212 | * |
| 176 | * IEC 62439-3, p 48, specifies the "original LPDU" to include the | 213 | * Anything that's off in mask will not be enabled - so only things |
| 177 | * original "LT" field (what "LT" means is not explained anywhere as | 214 | * that were in features originally, and also is in NETIF_F_ONE_FOR_ALL, |
| 178 | * far as I can see - perhaps "Length/Type"?). So LSDU_size might | 215 | * may become enabled. |
| 179 | * equal original length + 2. | ||
| 180 | * Also, the fact that this field is not used anywhere (might be used | ||
| 181 | * by a RedBox connecting HSR and PRP nets?) means I cannot test its | ||
| 182 | * correctness. Instead of guessing, I set this to 0 here, to make any | ||
| 183 | * problems immediately apparent. Anyone using this driver with PRP/HSR | ||
| 184 | * RedBoxes might need to fix this... | ||
| 185 | */ | 216 | */ |
| 186 | set_hsr_tag_LSDU_size(&hsr_ethhdr->hsr_tag, 0); | 217 | features &= ~NETIF_F_ONE_FOR_ALL; |
| 187 | 218 | hsr_for_each_port(hsr, port) | |
| 188 | spin_lock_irqsave(&hsr_priv->seqnr_lock, irqflags); | 219 | features = netdev_increment_features(features, |
| 189 | hsr_ethhdr->hsr_tag.sequence_nr = htons(hsr_priv->sequence_nr); | 220 | port->dev->features, |
| 190 | hsr_priv->sequence_nr++; | 221 | mask); |
| 191 | spin_unlock_irqrestore(&hsr_priv->seqnr_lock, irqflags); | ||
| 192 | 222 | ||
| 193 | hsr_ethhdr->hsr_tag.encap_proto = hsr_ethhdr->ethhdr.h_proto; | 223 | return features; |
| 194 | |||
| 195 | hsr_ethhdr->ethhdr.h_proto = htons(ETH_P_PRP); | ||
| 196 | } | 224 | } |
| 197 | 225 | ||
| 198 | static int slave_xmit(struct sk_buff *skb, struct hsr_priv *hsr_priv, | 226 | static netdev_features_t hsr_fix_features(struct net_device *dev, |
| 199 | enum hsr_dev_idx dev_idx) | 227 | netdev_features_t features) |
| 200 | { | 228 | { |
| 201 | struct hsr_ethhdr *hsr_ethhdr; | 229 | struct hsr_priv *hsr = netdev_priv(dev); |
| 202 | |||
| 203 | hsr_ethhdr = (struct hsr_ethhdr *) skb->data; | ||
| 204 | 230 | ||
| 205 | skb->dev = hsr_priv->slave[dev_idx]; | 231 | return hsr_features_recompute(hsr, features); |
| 206 | |||
| 207 | hsr_addr_subst_dest(hsr_priv, &hsr_ethhdr->ethhdr, dev_idx); | ||
| 208 | |||
| 209 | /* Address substitution (IEC62439-3 pp 26, 50): replace mac | ||
| 210 | * address of outgoing frame with that of the outgoing slave's. | ||
| 211 | */ | ||
| 212 | ether_addr_copy(hsr_ethhdr->ethhdr.h_source, skb->dev->dev_addr); | ||
| 213 | |||
| 214 | return dev_queue_xmit(skb); | ||
| 215 | } | 232 | } |
| 216 | 233 | ||
| 217 | 234 | ||
| 218 | static int hsr_dev_xmit(struct sk_buff *skb, struct net_device *dev) | 235 | static int hsr_dev_xmit(struct sk_buff *skb, struct net_device *dev) |
| 219 | { | 236 | { |
| 220 | struct hsr_priv *hsr_priv; | 237 | struct hsr_priv *hsr = netdev_priv(dev); |
| 221 | struct hsr_ethhdr *hsr_ethhdr; | 238 | struct hsr_port *master; |
| 222 | struct sk_buff *skb2; | ||
| 223 | int res1, res2; | ||
| 224 | |||
| 225 | hsr_priv = netdev_priv(dev); | ||
| 226 | hsr_ethhdr = (struct hsr_ethhdr *) skb->data; | ||
| 227 | |||
| 228 | if ((skb->protocol != htons(ETH_P_PRP)) || | ||
| 229 | (hsr_ethhdr->ethhdr.h_proto != htons(ETH_P_PRP))) { | ||
| 230 | hsr_fill_tag(hsr_ethhdr, hsr_priv); | ||
| 231 | skb->protocol = htons(ETH_P_PRP); | ||
| 232 | } | ||
| 233 | |||
| 234 | skb2 = pskb_copy(skb, GFP_ATOMIC); | ||
| 235 | |||
| 236 | res1 = NET_XMIT_DROP; | ||
| 237 | if (likely(hsr_priv->slave[HSR_DEV_SLAVE_A])) | ||
| 238 | res1 = slave_xmit(skb, hsr_priv, HSR_DEV_SLAVE_A); | ||
| 239 | 239 | ||
| 240 | res2 = NET_XMIT_DROP; | 240 | master = hsr_port_get_hsr(hsr, HSR_PT_MASTER); |
| 241 | if (likely(skb2 && hsr_priv->slave[HSR_DEV_SLAVE_B])) | 241 | skb->dev = master->dev; |
| 242 | res2 = slave_xmit(skb2, hsr_priv, HSR_DEV_SLAVE_B); | 242 | hsr_forward_skb(skb, master); |
| 243 | |||
| 244 | if (likely(res1 == NET_XMIT_SUCCESS || res1 == NET_XMIT_CN || | ||
| 245 | res2 == NET_XMIT_SUCCESS || res2 == NET_XMIT_CN)) { | ||
| 246 | hsr_priv->dev->stats.tx_packets++; | ||
| 247 | hsr_priv->dev->stats.tx_bytes += skb->len; | ||
| 248 | } else { | ||
| 249 | hsr_priv->dev->stats.tx_dropped++; | ||
| 250 | } | ||
| 251 | 243 | ||
| 252 | return NETDEV_TX_OK; | 244 | return NETDEV_TX_OK; |
| 253 | } | 245 | } |
| 254 | 246 | ||
| 255 | 247 | ||
| 256 | static int hsr_header_create(struct sk_buff *skb, struct net_device *dev, | ||
| 257 | unsigned short type, const void *daddr, | ||
| 258 | const void *saddr, unsigned int len) | ||
| 259 | { | ||
| 260 | int res; | ||
| 261 | |||
| 262 | /* Make room for the HSR tag now. We will fill it in later (in | ||
| 263 | * hsr_dev_xmit) | ||
| 264 | */ | ||
| 265 | if (skb_headroom(skb) < HSR_TAGLEN + ETH_HLEN) | ||
| 266 | return -ENOBUFS; | ||
| 267 | skb_push(skb, HSR_TAGLEN); | ||
| 268 | |||
| 269 | /* To allow VLAN/HSR combos we should probably use | ||
| 270 | * res = dev_hard_header(skb, dev, type, daddr, saddr, len + HSR_TAGLEN); | ||
| 271 | * here instead. It would require other changes too, though - e.g. | ||
| 272 | * separate headers for each slave etc... | ||
| 273 | */ | ||
| 274 | res = eth_header(skb, dev, type, daddr, saddr, len + HSR_TAGLEN); | ||
| 275 | if (res <= 0) | ||
| 276 | return res; | ||
| 277 | skb_reset_mac_header(skb); | ||
| 278 | |||
| 279 | return res + HSR_TAGLEN; | ||
| 280 | } | ||
| 281 | |||
| 282 | |||
| 283 | static const struct header_ops hsr_header_ops = { | 248 | static const struct header_ops hsr_header_ops = { |
| 284 | .create = hsr_header_create, | 249 | .create = eth_header, |
| 285 | .parse = eth_header_parse, | 250 | .parse = eth_header_parse, |
| 286 | }; | 251 | }; |
| 287 | 252 | ||
| @@ -291,67 +256,63 @@ static const struct header_ops hsr_header_ops = { | |||
| 291 | */ | 256 | */ |
| 292 | static int hsr_pad(int size) | 257 | static int hsr_pad(int size) |
| 293 | { | 258 | { |
| 294 | const int min_size = ETH_ZLEN - HSR_TAGLEN - ETH_HLEN; | 259 | const int min_size = ETH_ZLEN - HSR_HLEN - ETH_HLEN; |
| 295 | 260 | ||
| 296 | if (size >= min_size) | 261 | if (size >= min_size) |
| 297 | return size; | 262 | return size; |
| 298 | return min_size; | 263 | return min_size; |
| 299 | } | 264 | } |
| 300 | 265 | ||
| 301 | static void send_hsr_supervision_frame(struct net_device *hsr_dev, u8 type) | 266 | static void send_hsr_supervision_frame(struct hsr_port *master, u8 type) |
| 302 | { | 267 | { |
| 303 | struct hsr_priv *hsr_priv; | ||
| 304 | struct sk_buff *skb; | 268 | struct sk_buff *skb; |
| 305 | int hlen, tlen; | 269 | int hlen, tlen; |
| 306 | struct hsr_sup_tag *hsr_stag; | 270 | struct hsr_sup_tag *hsr_stag; |
| 307 | struct hsr_sup_payload *hsr_sp; | 271 | struct hsr_sup_payload *hsr_sp; |
| 308 | unsigned long irqflags; | 272 | unsigned long irqflags; |
| 309 | 273 | ||
| 310 | hlen = LL_RESERVED_SPACE(hsr_dev); | 274 | hlen = LL_RESERVED_SPACE(master->dev); |
| 311 | tlen = hsr_dev->needed_tailroom; | 275 | tlen = master->dev->needed_tailroom; |
| 312 | skb = alloc_skb(hsr_pad(sizeof(struct hsr_sup_payload)) + hlen + tlen, | 276 | skb = alloc_skb(hsr_pad(sizeof(struct hsr_sup_payload)) + hlen + tlen, |
| 313 | GFP_ATOMIC); | 277 | GFP_ATOMIC); |
| 314 | 278 | ||
| 315 | if (skb == NULL) | 279 | if (skb == NULL) |
| 316 | return; | 280 | return; |
| 317 | 281 | ||
| 318 | hsr_priv = netdev_priv(hsr_dev); | ||
| 319 | |||
| 320 | skb_reserve(skb, hlen); | 282 | skb_reserve(skb, hlen); |
| 321 | 283 | ||
| 322 | skb->dev = hsr_dev; | 284 | skb->dev = master->dev; |
| 323 | skb->protocol = htons(ETH_P_PRP); | 285 | skb->protocol = htons(ETH_P_PRP); |
| 324 | skb->priority = TC_PRIO_CONTROL; | 286 | skb->priority = TC_PRIO_CONTROL; |
| 325 | 287 | ||
| 326 | if (dev_hard_header(skb, skb->dev, ETH_P_PRP, | 288 | if (dev_hard_header(skb, skb->dev, ETH_P_PRP, |
| 327 | hsr_priv->sup_multicast_addr, | 289 | master->hsr->sup_multicast_addr, |
| 328 | skb->dev->dev_addr, skb->len) < 0) | 290 | skb->dev->dev_addr, skb->len) <= 0) |
| 329 | goto out; | 291 | goto out; |
| 292 | skb_reset_mac_header(skb); | ||
| 330 | 293 | ||
| 331 | skb_pull(skb, sizeof(struct ethhdr)); | 294 | hsr_stag = (typeof(hsr_stag)) skb_put(skb, sizeof(*hsr_stag)); |
| 332 | hsr_stag = (typeof(hsr_stag)) skb->data; | ||
| 333 | 295 | ||
| 334 | set_hsr_stag_path(hsr_stag, 0xf); | 296 | set_hsr_stag_path(hsr_stag, 0xf); |
| 335 | set_hsr_stag_HSR_Ver(hsr_stag, 0); | 297 | set_hsr_stag_HSR_Ver(hsr_stag, 0); |
| 336 | 298 | ||
| 337 | spin_lock_irqsave(&hsr_priv->seqnr_lock, irqflags); | 299 | spin_lock_irqsave(&master->hsr->seqnr_lock, irqflags); |
| 338 | hsr_stag->sequence_nr = htons(hsr_priv->sequence_nr); | 300 | hsr_stag->sequence_nr = htons(master->hsr->sequence_nr); |
| 339 | hsr_priv->sequence_nr++; | 301 | master->hsr->sequence_nr++; |
| 340 | spin_unlock_irqrestore(&hsr_priv->seqnr_lock, irqflags); | 302 | spin_unlock_irqrestore(&master->hsr->seqnr_lock, irqflags); |
| 341 | 303 | ||
| 342 | hsr_stag->HSR_TLV_Type = type; | 304 | hsr_stag->HSR_TLV_Type = type; |
| 343 | hsr_stag->HSR_TLV_Length = 12; | 305 | hsr_stag->HSR_TLV_Length = 12; |
| 344 | 306 | ||
| 345 | skb_push(skb, sizeof(struct ethhdr)); | ||
| 346 | |||
| 347 | /* Payload: MacAddressA */ | 307 | /* Payload: MacAddressA */ |
| 348 | hsr_sp = (typeof(hsr_sp)) skb_put(skb, sizeof(*hsr_sp)); | 308 | hsr_sp = (typeof(hsr_sp)) skb_put(skb, sizeof(*hsr_sp)); |
| 349 | ether_addr_copy(hsr_sp->MacAddressA, hsr_dev->dev_addr); | 309 | ether_addr_copy(hsr_sp->MacAddressA, master->dev->dev_addr); |
| 350 | 310 | ||
| 351 | dev_queue_xmit(skb); | 311 | hsr_forward_skb(skb, master); |
| 352 | return; | 312 | return; |
| 353 | 313 | ||
| 354 | out: | 314 | out: |
| 315 | WARN_ON_ONCE("HSR: Could not send supervision frame\n"); | ||
| 355 | kfree_skb(skb); | 316 | kfree_skb(skb); |
| 356 | } | 317 | } |
| 357 | 318 | ||
| @@ -360,59 +321,32 @@ out: | |||
| 360 | */ | 321 | */ |
| 361 | static void hsr_announce(unsigned long data) | 322 | static void hsr_announce(unsigned long data) |
| 362 | { | 323 | { |
| 363 | struct hsr_priv *hsr_priv; | 324 | struct hsr_priv *hsr; |
| 325 | struct hsr_port *master; | ||
| 364 | 326 | ||
| 365 | hsr_priv = (struct hsr_priv *) data; | 327 | hsr = (struct hsr_priv *) data; |
| 366 | 328 | ||
| 367 | if (hsr_priv->announce_count < 3) { | 329 | rcu_read_lock(); |
| 368 | send_hsr_supervision_frame(hsr_priv->dev, HSR_TLV_ANNOUNCE); | 330 | master = hsr_port_get_hsr(hsr, HSR_PT_MASTER); |
| 369 | hsr_priv->announce_count++; | 331 | |
| 332 | if (hsr->announce_count < 3) { | ||
| 333 | send_hsr_supervision_frame(master, HSR_TLV_ANNOUNCE); | ||
| 334 | hsr->announce_count++; | ||
| 370 | } else { | 335 | } else { |
| 371 | send_hsr_supervision_frame(hsr_priv->dev, HSR_TLV_LIFE_CHECK); | 336 | send_hsr_supervision_frame(master, HSR_TLV_LIFE_CHECK); |
| 372 | } | 337 | } |
| 373 | 338 | ||
| 374 | if (hsr_priv->announce_count < 3) | 339 | if (hsr->announce_count < 3) |
| 375 | hsr_priv->announce_timer.expires = jiffies + | 340 | hsr->announce_timer.expires = jiffies + |
| 376 | msecs_to_jiffies(HSR_ANNOUNCE_INTERVAL); | 341 | msecs_to_jiffies(HSR_ANNOUNCE_INTERVAL); |
| 377 | else | 342 | else |
| 378 | hsr_priv->announce_timer.expires = jiffies + | 343 | hsr->announce_timer.expires = jiffies + |
| 379 | msecs_to_jiffies(HSR_LIFE_CHECK_INTERVAL); | 344 | msecs_to_jiffies(HSR_LIFE_CHECK_INTERVAL); |
| 380 | 345 | ||
| 381 | if (is_admin_up(hsr_priv->dev)) | 346 | if (is_admin_up(master->dev)) |
| 382 | add_timer(&hsr_priv->announce_timer); | 347 | add_timer(&hsr->announce_timer); |
| 383 | } | ||
| 384 | |||
| 385 | |||
| 386 | static void restore_slaves(struct net_device *hsr_dev) | ||
| 387 | { | ||
| 388 | struct hsr_priv *hsr_priv; | ||
| 389 | int i; | ||
| 390 | int res; | ||
| 391 | |||
| 392 | hsr_priv = netdev_priv(hsr_dev); | ||
| 393 | |||
| 394 | rtnl_lock(); | ||
| 395 | |||
| 396 | /* Restore promiscuity */ | ||
| 397 | for (i = 0; i < HSR_MAX_SLAVE; i++) { | ||
| 398 | if (!hsr_priv->slave[i]) | ||
| 399 | continue; | ||
| 400 | res = dev_set_promiscuity(hsr_priv->slave[i], -1); | ||
| 401 | if (res) | ||
| 402 | netdev_info(hsr_dev, | ||
| 403 | "Cannot restore slave promiscuity (%s, %d)\n", | ||
| 404 | hsr_priv->slave[i]->name, res); | ||
| 405 | } | ||
| 406 | |||
| 407 | rtnl_unlock(); | ||
| 408 | } | ||
| 409 | |||
| 410 | static void reclaim_hsr_dev(struct rcu_head *rh) | ||
| 411 | { | ||
| 412 | struct hsr_priv *hsr_priv; | ||
| 413 | 348 | ||
| 414 | hsr_priv = container_of(rh, struct hsr_priv, rcu_head); | 349 | rcu_read_unlock(); |
| 415 | free_netdev(hsr_priv->dev); | ||
| 416 | } | 350 | } |
| 417 | 351 | ||
| 418 | 352 | ||
| @@ -421,14 +355,18 @@ static void reclaim_hsr_dev(struct rcu_head *rh) | |||
| 421 | */ | 355 | */ |
| 422 | static void hsr_dev_destroy(struct net_device *hsr_dev) | 356 | static void hsr_dev_destroy(struct net_device *hsr_dev) |
| 423 | { | 357 | { |
| 424 | struct hsr_priv *hsr_priv; | 358 | struct hsr_priv *hsr; |
| 359 | struct hsr_port *port; | ||
| 425 | 360 | ||
| 426 | hsr_priv = netdev_priv(hsr_dev); | 361 | hsr = netdev_priv(hsr_dev); |
| 362 | hsr_for_each_port(hsr, port) | ||
| 363 | hsr_del_port(port); | ||
| 427 | 364 | ||
| 428 | del_timer(&hsr_priv->announce_timer); | 365 | del_timer_sync(&hsr->prune_timer); |
| 429 | unregister_hsr_master(hsr_priv); /* calls list_del_rcu on hsr_priv */ | 366 | del_timer_sync(&hsr->announce_timer); |
| 430 | restore_slaves(hsr_dev); | 367 | |
| 431 | call_rcu(&hsr_priv->rcu_head, reclaim_hsr_dev); /* reclaim hsr_priv */ | 368 | synchronize_rcu(); |
| 369 | free_netdev(hsr_dev); | ||
| 432 | } | 370 | } |
| 433 | 371 | ||
| 434 | static const struct net_device_ops hsr_device_ops = { | 372 | static const struct net_device_ops hsr_device_ops = { |
| @@ -436,62 +374,51 @@ static const struct net_device_ops hsr_device_ops = { | |||
| 436 | .ndo_open = hsr_dev_open, | 374 | .ndo_open = hsr_dev_open, |
| 437 | .ndo_stop = hsr_dev_close, | 375 | .ndo_stop = hsr_dev_close, |
| 438 | .ndo_start_xmit = hsr_dev_xmit, | 376 | .ndo_start_xmit = hsr_dev_xmit, |
| 377 | .ndo_fix_features = hsr_fix_features, | ||
| 439 | }; | 378 | }; |
| 440 | 379 | ||
| 380 | static struct device_type hsr_type = { | ||
| 381 | .name = "hsr", | ||
| 382 | }; | ||
| 441 | 383 | ||
| 442 | void hsr_dev_setup(struct net_device *dev) | 384 | void hsr_dev_setup(struct net_device *dev) |
| 443 | { | 385 | { |
| 444 | random_ether_addr(dev->dev_addr); | 386 | random_ether_addr(dev->dev_addr); |
| 445 | 387 | ||
| 446 | ether_setup(dev); | 388 | ether_setup(dev); |
| 447 | dev->header_ops = &hsr_header_ops; | 389 | dev->header_ops = &hsr_header_ops; |
| 448 | dev->netdev_ops = &hsr_device_ops; | 390 | dev->netdev_ops = &hsr_device_ops; |
| 449 | dev->tx_queue_len = 0; | 391 | SET_NETDEV_DEVTYPE(dev, &hsr_type); |
| 392 | dev->tx_queue_len = 0; | ||
| 450 | 393 | ||
| 451 | dev->destructor = hsr_dev_destroy; | 394 | dev->destructor = hsr_dev_destroy; |
| 395 | |||
| 396 | dev->hw_features = NETIF_F_SG | NETIF_F_FRAGLIST | NETIF_F_HIGHDMA | | ||
| 397 | NETIF_F_GSO_MASK | NETIF_F_HW_CSUM | | ||
| 398 | NETIF_F_HW_VLAN_CTAG_TX; | ||
| 399 | |||
| 400 | dev->features = dev->hw_features; | ||
| 401 | |||
| 402 | /* Prevent recursive tx locking */ | ||
| 403 | dev->features |= NETIF_F_LLTX; | ||
| 404 | /* VLAN on top of HSR needs testing and probably some work on | ||
| 405 | * hsr_header_create() etc. | ||
| 406 | */ | ||
| 407 | dev->features |= NETIF_F_VLAN_CHALLENGED; | ||
| 408 | /* Not sure about this. Taken from bridge code. netdev_features.h says | ||
| 409 | * it means "Does not change network namespaces". | ||
| 410 | */ | ||
| 411 | dev->features |= NETIF_F_NETNS_LOCAL; | ||
| 452 | } | 412 | } |
| 453 | 413 | ||
| 454 | 414 | ||
| 455 | /* Return true if dev is a HSR master; return false otherwise. | 415 | /* Return true if dev is a HSR master; return false otherwise. |
| 456 | */ | 416 | */ |
| 457 | bool is_hsr_master(struct net_device *dev) | 417 | inline bool is_hsr_master(struct net_device *dev) |
| 458 | { | 418 | { |
| 459 | return (dev->netdev_ops->ndo_start_xmit == hsr_dev_xmit); | 419 | return (dev->netdev_ops->ndo_start_xmit == hsr_dev_xmit); |
| 460 | } | 420 | } |
| 461 | 421 | ||
| 462 | static int check_slave_ok(struct net_device *dev) | ||
| 463 | { | ||
| 464 | /* Don't allow HSR on non-ethernet like devices */ | ||
| 465 | if ((dev->flags & IFF_LOOPBACK) || (dev->type != ARPHRD_ETHER) || | ||
| 466 | (dev->addr_len != ETH_ALEN)) { | ||
| 467 | netdev_info(dev, "Cannot use loopback or non-ethernet device as HSR slave.\n"); | ||
| 468 | return -EINVAL; | ||
| 469 | } | ||
| 470 | |||
| 471 | /* Don't allow enslaving hsr devices */ | ||
| 472 | if (is_hsr_master(dev)) { | ||
| 473 | netdev_info(dev, "Cannot create trees of HSR devices.\n"); | ||
| 474 | return -EINVAL; | ||
| 475 | } | ||
| 476 | |||
| 477 | if (is_hsr_slave(dev)) { | ||
| 478 | netdev_info(dev, "This device is already a HSR slave.\n"); | ||
| 479 | return -EINVAL; | ||
| 480 | } | ||
| 481 | |||
| 482 | if (dev->priv_flags & IFF_802_1Q_VLAN) { | ||
| 483 | netdev_info(dev, "HSR on top of VLAN is not yet supported in this driver.\n"); | ||
| 484 | return -EINVAL; | ||
| 485 | } | ||
| 486 | |||
| 487 | /* HSR over bonded devices has not been tested, but I'm not sure it | ||
| 488 | * won't work... | ||
| 489 | */ | ||
| 490 | |||
| 491 | return 0; | ||
| 492 | } | ||
| 493 | |||
| 494 | |||
| 495 | /* Default multicast address for HSR Supervision frames */ | 422 | /* Default multicast address for HSR Supervision frames */ |
| 496 | static const unsigned char def_multicast_addr[ETH_ALEN] __aligned(2) = { | 423 | static const unsigned char def_multicast_addr[ETH_ALEN] __aligned(2) = { |
| 497 | 0x01, 0x15, 0x4e, 0x00, 0x01, 0x00 | 424 | 0x01, 0x15, 0x4e, 0x00, 0x01, 0x00 |
| @@ -500,97 +427,74 @@ static const unsigned char def_multicast_addr[ETH_ALEN] __aligned(2) = { | |||
| 500 | int hsr_dev_finalize(struct net_device *hsr_dev, struct net_device *slave[2], | 427 | int hsr_dev_finalize(struct net_device *hsr_dev, struct net_device *slave[2], |
| 501 | unsigned char multicast_spec) | 428 | unsigned char multicast_spec) |
| 502 | { | 429 | { |
| 503 | struct hsr_priv *hsr_priv; | 430 | struct hsr_priv *hsr; |
| 504 | int i; | 431 | struct hsr_port *port; |
| 505 | int res; | 432 | int res; |
| 506 | 433 | ||
| 507 | hsr_priv = netdev_priv(hsr_dev); | 434 | hsr = netdev_priv(hsr_dev); |
| 508 | hsr_priv->dev = hsr_dev; | 435 | INIT_LIST_HEAD(&hsr->ports); |
| 509 | INIT_LIST_HEAD(&hsr_priv->node_db); | 436 | INIT_LIST_HEAD(&hsr->node_db); |
| 510 | INIT_LIST_HEAD(&hsr_priv->self_node_db); | 437 | INIT_LIST_HEAD(&hsr->self_node_db); |
| 511 | for (i = 0; i < HSR_MAX_SLAVE; i++) | ||
| 512 | hsr_priv->slave[i] = slave[i]; | ||
| 513 | |||
| 514 | spin_lock_init(&hsr_priv->seqnr_lock); | ||
| 515 | /* Overflow soon to find bugs easier: */ | ||
| 516 | hsr_priv->sequence_nr = USHRT_MAX - 1024; | ||
| 517 | |||
| 518 | init_timer(&hsr_priv->announce_timer); | ||
| 519 | hsr_priv->announce_timer.function = hsr_announce; | ||
| 520 | hsr_priv->announce_timer.data = (unsigned long) hsr_priv; | ||
| 521 | 438 | ||
| 522 | ether_addr_copy(hsr_priv->sup_multicast_addr, def_multicast_addr); | 439 | ether_addr_copy(hsr_dev->dev_addr, slave[0]->dev_addr); |
| 523 | hsr_priv->sup_multicast_addr[ETH_ALEN - 1] = multicast_spec; | ||
| 524 | 440 | ||
| 525 | /* FIXME: should I modify the value of these? | 441 | /* Make sure we recognize frames from ourselves in hsr_rcv() */ |
| 526 | * | 442 | res = hsr_create_self_node(&hsr->self_node_db, hsr_dev->dev_addr, |
| 527 | * - hsr_dev->flags - i.e. | 443 | slave[1]->dev_addr); |
| 528 | * IFF_MASTER/SLAVE? | 444 | if (res < 0) |
| 529 | * - hsr_dev->priv_flags - i.e. | 445 | return res; |
| 530 | * IFF_EBRIDGE? | ||
| 531 | * IFF_TX_SKB_SHARING? | ||
| 532 | * IFF_HSR_MASTER/SLAVE? | ||
| 533 | */ | ||
| 534 | 446 | ||
| 535 | for (i = 0; i < HSR_MAX_SLAVE; i++) { | 447 | spin_lock_init(&hsr->seqnr_lock); |
| 536 | res = check_slave_ok(slave[i]); | 448 | /* Overflow soon to find bugs easier: */ |
| 537 | if (res) | 449 | hsr->sequence_nr = HSR_SEQNR_START; |
| 538 | return res; | ||
| 539 | } | ||
| 540 | 450 | ||
| 541 | hsr_dev->features = slave[0]->features & slave[1]->features; | 451 | init_timer(&hsr->announce_timer); |
| 542 | /* Prevent recursive tx locking */ | 452 | hsr->announce_timer.function = hsr_announce; |
| 543 | hsr_dev->features |= NETIF_F_LLTX; | 453 | hsr->announce_timer.data = (unsigned long) hsr; |
| 544 | /* VLAN on top of HSR needs testing and probably some work on | ||
| 545 | * hsr_header_create() etc. | ||
| 546 | */ | ||
| 547 | hsr_dev->features |= NETIF_F_VLAN_CHALLENGED; | ||
| 548 | 454 | ||
| 549 | /* Set hsr_dev's MAC address to that of mac_slave1 */ | 455 | init_timer(&hsr->prune_timer); |
| 550 | ether_addr_copy(hsr_dev->dev_addr, hsr_priv->slave[0]->dev_addr); | 456 | hsr->prune_timer.function = hsr_prune_nodes; |
| 457 | hsr->prune_timer.data = (unsigned long) hsr; | ||
| 551 | 458 | ||
| 552 | /* Set required header length */ | 459 | ether_addr_copy(hsr->sup_multicast_addr, def_multicast_addr); |
| 553 | for (i = 0; i < HSR_MAX_SLAVE; i++) { | 460 | hsr->sup_multicast_addr[ETH_ALEN - 1] = multicast_spec; |
| 554 | if (slave[i]->hard_header_len + HSR_TAGLEN > | ||
| 555 | hsr_dev->hard_header_len) | ||
| 556 | hsr_dev->hard_header_len = | ||
| 557 | slave[i]->hard_header_len + HSR_TAGLEN; | ||
| 558 | } | ||
| 559 | 461 | ||
| 560 | /* MTU */ | 462 | /* FIXME: should I modify the value of these? |
| 561 | for (i = 0; i < HSR_MAX_SLAVE; i++) | 463 | * |
| 562 | if (slave[i]->mtu - HSR_TAGLEN < hsr_dev->mtu) | 464 | * - hsr_dev->flags - i.e. |
| 563 | hsr_dev->mtu = slave[i]->mtu - HSR_TAGLEN; | 465 | * IFF_MASTER/SLAVE? |
| 466 | * - hsr_dev->priv_flags - i.e. | ||
| 467 | * IFF_EBRIDGE? | ||
| 468 | * IFF_TX_SKB_SHARING? | ||
| 469 | * IFF_HSR_MASTER/SLAVE? | ||
| 470 | */ | ||
| 564 | 471 | ||
| 565 | /* Make sure the 1st call to netif_carrier_on() gets through */ | 472 | /* Make sure the 1st call to netif_carrier_on() gets through */ |
| 566 | netif_carrier_off(hsr_dev); | 473 | netif_carrier_off(hsr_dev); |
| 567 | 474 | ||
| 568 | /* Promiscuity */ | 475 | res = hsr_add_port(hsr, hsr_dev, HSR_PT_MASTER); |
| 569 | for (i = 0; i < HSR_MAX_SLAVE; i++) { | 476 | if (res) |
| 570 | res = dev_set_promiscuity(slave[i], 1); | 477 | return res; |
| 571 | if (res) { | ||
| 572 | netdev_info(hsr_dev, "Cannot set slave promiscuity (%s, %d)\n", | ||
| 573 | slave[i]->name, res); | ||
| 574 | goto fail; | ||
| 575 | } | ||
| 576 | } | ||
| 577 | 478 | ||
| 578 | /* Make sure we recognize frames from ourselves in hsr_rcv() */ | 479 | res = register_netdevice(hsr_dev); |
| 579 | res = hsr_create_self_node(&hsr_priv->self_node_db, | 480 | if (res) |
| 580 | hsr_dev->dev_addr, | ||
| 581 | hsr_priv->slave[1]->dev_addr); | ||
| 582 | if (res < 0) | ||
| 583 | goto fail; | 481 | goto fail; |
| 584 | 482 | ||
| 585 | res = register_netdevice(hsr_dev); | 483 | res = hsr_add_port(hsr, slave[0], HSR_PT_SLAVE_A); |
| 484 | if (res) | ||
| 485 | goto fail; | ||
| 486 | res = hsr_add_port(hsr, slave[1], HSR_PT_SLAVE_B); | ||
| 586 | if (res) | 487 | if (res) |
| 587 | goto fail; | 488 | goto fail; |
| 588 | 489 | ||
| 589 | register_hsr_master(hsr_priv); | 490 | hsr->prune_timer.expires = jiffies + msecs_to_jiffies(PRUNE_PERIOD); |
| 491 | add_timer(&hsr->prune_timer); | ||
| 590 | 492 | ||
| 591 | return 0; | 493 | return 0; |
| 592 | 494 | ||
| 593 | fail: | 495 | fail: |
| 594 | restore_slaves(hsr_dev); | 496 | hsr_for_each_port(hsr, port) |
| 497 | hsr_del_port(port); | ||
| 498 | |||
| 595 | return res; | 499 | return res; |
| 596 | } | 500 | } |
diff --git a/net/hsr/hsr_device.h b/net/hsr/hsr_device.h index 2c7148e73914..108a5d59d2a6 100644 --- a/net/hsr/hsr_device.h +++ b/net/hsr/hsr_device.h | |||
| @@ -1,4 +1,4 @@ | |||
| 1 | /* Copyright 2011-2013 Autronica Fire and Security AS | 1 | /* Copyright 2011-2014 Autronica Fire and Security AS |
| 2 | * | 2 | * |
| 3 | * This program is free software; you can redistribute it and/or modify it | 3 | * This program is free software; you can redistribute it and/or modify it |
| 4 | * under the terms of the GNU General Public License as published by the Free | 4 | * under the terms of the GNU General Public License as published by the Free |
| @@ -6,7 +6,7 @@ | |||
| 6 | * any later version. | 6 | * any later version. |
| 7 | * | 7 | * |
| 8 | * Author(s): | 8 | * Author(s): |
| 9 | * 2011-2013 Arvid Brodin, arvid.brodin@xdin.com | 9 | * 2011-2014 Arvid Brodin, arvid.brodin@alten.se |
| 10 | */ | 10 | */ |
| 11 | 11 | ||
| 12 | #ifndef __HSR_DEVICE_H | 12 | #ifndef __HSR_DEVICE_H |
| @@ -18,12 +18,8 @@ | |||
| 18 | void hsr_dev_setup(struct net_device *dev); | 18 | void hsr_dev_setup(struct net_device *dev); |
| 19 | int hsr_dev_finalize(struct net_device *hsr_dev, struct net_device *slave[2], | 19 | int hsr_dev_finalize(struct net_device *hsr_dev, struct net_device *slave[2], |
| 20 | unsigned char multicast_spec); | 20 | unsigned char multicast_spec); |
| 21 | void hsr_set_operstate(struct net_device *hsr_dev, struct net_device *slave1, | 21 | void hsr_check_carrier_and_operstate(struct hsr_priv *hsr); |
| 22 | struct net_device *slave2); | ||
| 23 | void hsr_set_carrier(struct net_device *hsr_dev, struct net_device *slave1, | ||
| 24 | struct net_device *slave2); | ||
| 25 | void hsr_check_announce(struct net_device *hsr_dev, int old_operstate); | ||
| 26 | bool is_hsr_master(struct net_device *dev); | 22 | bool is_hsr_master(struct net_device *dev); |
| 27 | int hsr_get_max_mtu(struct hsr_priv *hsr_priv); | 23 | int hsr_get_max_mtu(struct hsr_priv *hsr); |
| 28 | 24 | ||
| 29 | #endif /* __HSR_DEVICE_H */ | 25 | #endif /* __HSR_DEVICE_H */ |
diff --git a/net/hsr/hsr_forward.c b/net/hsr/hsr_forward.c new file mode 100644 index 000000000000..7871ed6d3825 --- /dev/null +++ b/net/hsr/hsr_forward.c | |||
| @@ -0,0 +1,368 @@ | |||
| 1 | /* Copyright 2011-2014 Autronica Fire and Security AS | ||
| 2 | * | ||
| 3 | * This program is free software; you can redistribute it and/or modify it | ||
| 4 | * under the terms of the GNU General Public License as published by the Free | ||
| 5 | * Software Foundation; either version 2 of the License, or (at your option) | ||
| 6 | * any later version. | ||
| 7 | * | ||
| 8 | * Author(s): | ||
| 9 | * 2011-2014 Arvid Brodin, arvid.brodin@alten.se | ||
| 10 | */ | ||
| 11 | |||
| 12 | #include "hsr_forward.h" | ||
| 13 | #include <linux/types.h> | ||
| 14 | #include <linux/skbuff.h> | ||
| 15 | #include <linux/etherdevice.h> | ||
| 16 | #include <linux/if_vlan.h> | ||
| 17 | #include "hsr_main.h" | ||
| 18 | #include "hsr_framereg.h" | ||
| 19 | |||
| 20 | |||
| 21 | struct hsr_node; | ||
| 22 | |||
| 23 | struct hsr_frame_info { | ||
| 24 | struct sk_buff *skb_std; | ||
| 25 | struct sk_buff *skb_hsr; | ||
| 26 | struct hsr_port *port_rcv; | ||
| 27 | struct hsr_node *node_src; | ||
| 28 | u16 sequence_nr; | ||
| 29 | bool is_supervision; | ||
| 30 | bool is_vlan; | ||
| 31 | bool is_local_dest; | ||
| 32 | bool is_local_exclusive; | ||
| 33 | }; | ||
| 34 | |||
| 35 | |||
| 36 | /* The uses I can see for these HSR supervision frames are: | ||
| 37 | * 1) Use the frames that are sent after node initialization ("HSR_TLV.Type = | ||
| 38 | * 22") to reset any sequence_nr counters belonging to that node. Useful if | ||
| 39 | * the other node's counter has been reset for some reason. | ||
| 40 | * -- | ||
| 41 | * Or not - resetting the counter and bridging the frame would create a | ||
| 42 | * loop, unfortunately. | ||
| 43 | * | ||
| 44 | * 2) Use the LifeCheck frames to detect ring breaks. I.e. if no LifeCheck | ||
| 45 | * frame is received from a particular node, we know something is wrong. | ||
| 46 | * We just register these (as with normal frames) and throw them away. | ||
| 47 | * | ||
| 48 | * 3) Allow different MAC addresses for the two slave interfaces, using the | ||
| 49 | * MacAddressA field. | ||
| 50 | */ | ||
| 51 | static bool is_supervision_frame(struct hsr_priv *hsr, struct sk_buff *skb) | ||
| 52 | { | ||
| 53 | struct hsr_ethhdr_sp *hdr; | ||
| 54 | |||
| 55 | WARN_ON_ONCE(!skb_mac_header_was_set(skb)); | ||
| 56 | hdr = (struct hsr_ethhdr_sp *) skb_mac_header(skb); | ||
| 57 | |||
| 58 | if (!ether_addr_equal(hdr->ethhdr.h_dest, | ||
| 59 | hsr->sup_multicast_addr)) | ||
| 60 | return false; | ||
| 61 | |||
| 62 | if (get_hsr_stag_path(&hdr->hsr_sup) != 0x0f) | ||
| 63 | return false; | ||
| 64 | if ((hdr->hsr_sup.HSR_TLV_Type != HSR_TLV_ANNOUNCE) && | ||
| 65 | (hdr->hsr_sup.HSR_TLV_Type != HSR_TLV_LIFE_CHECK)) | ||
| 66 | return false; | ||
| 67 | if (hdr->hsr_sup.HSR_TLV_Length != 12) | ||
| 68 | return false; | ||
| 69 | |||
| 70 | return true; | ||
| 71 | } | ||
| 72 | |||
| 73 | |||
| 74 | static struct sk_buff *create_stripped_skb(struct sk_buff *skb_in, | ||
| 75 | struct hsr_frame_info *frame) | ||
| 76 | { | ||
| 77 | struct sk_buff *skb; | ||
| 78 | int copylen; | ||
| 79 | unsigned char *dst, *src; | ||
| 80 | |||
| 81 | skb_pull(skb_in, HSR_HLEN); | ||
| 82 | skb = __pskb_copy(skb_in, skb_headroom(skb_in) - HSR_HLEN, GFP_ATOMIC); | ||
| 83 | skb_push(skb_in, HSR_HLEN); | ||
| 84 | if (skb == NULL) | ||
| 85 | return NULL; | ||
| 86 | |||
| 87 | skb_reset_mac_header(skb); | ||
| 88 | |||
| 89 | if (skb->ip_summed == CHECKSUM_PARTIAL) | ||
| 90 | skb->csum_start -= HSR_HLEN; | ||
| 91 | |||
| 92 | copylen = 2*ETH_ALEN; | ||
| 93 | if (frame->is_vlan) | ||
| 94 | copylen += VLAN_HLEN; | ||
| 95 | src = skb_mac_header(skb_in); | ||
| 96 | dst = skb_mac_header(skb); | ||
| 97 | memcpy(dst, src, copylen); | ||
| 98 | |||
| 99 | skb->protocol = eth_hdr(skb)->h_proto; | ||
| 100 | return skb; | ||
| 101 | } | ||
| 102 | |||
| 103 | static struct sk_buff *frame_get_stripped_skb(struct hsr_frame_info *frame, | ||
| 104 | struct hsr_port *port) | ||
| 105 | { | ||
| 106 | if (!frame->skb_std) | ||
| 107 | frame->skb_std = create_stripped_skb(frame->skb_hsr, frame); | ||
| 108 | return skb_clone(frame->skb_std, GFP_ATOMIC); | ||
| 109 | } | ||
| 110 | |||
| 111 | |||
| 112 | static void hsr_fill_tag(struct sk_buff *skb, struct hsr_frame_info *frame, | ||
| 113 | struct hsr_port *port) | ||
| 114 | { | ||
| 115 | struct hsr_ethhdr *hsr_ethhdr; | ||
| 116 | int lane_id; | ||
| 117 | int lsdu_size; | ||
| 118 | |||
| 119 | if (port->type == HSR_PT_SLAVE_A) | ||
| 120 | lane_id = 0; | ||
| 121 | else | ||
| 122 | lane_id = 1; | ||
| 123 | |||
| 124 | lsdu_size = skb->len - 14; | ||
| 125 | if (frame->is_vlan) | ||
| 126 | lsdu_size -= 4; | ||
| 127 | |||
| 128 | hsr_ethhdr = (struct hsr_ethhdr *) skb_mac_header(skb); | ||
| 129 | |||
| 130 | set_hsr_tag_path(&hsr_ethhdr->hsr_tag, lane_id); | ||
| 131 | set_hsr_tag_LSDU_size(&hsr_ethhdr->hsr_tag, lsdu_size); | ||
| 132 | hsr_ethhdr->hsr_tag.sequence_nr = htons(frame->sequence_nr); | ||
| 133 | hsr_ethhdr->hsr_tag.encap_proto = hsr_ethhdr->ethhdr.h_proto; | ||
| 134 | hsr_ethhdr->ethhdr.h_proto = htons(ETH_P_PRP); | ||
| 135 | } | ||
| 136 | |||
| 137 | static struct sk_buff *create_tagged_skb(struct sk_buff *skb_o, | ||
| 138 | struct hsr_frame_info *frame, | ||
| 139 | struct hsr_port *port) | ||
| 140 | { | ||
| 141 | int movelen; | ||
| 142 | unsigned char *dst, *src; | ||
| 143 | struct sk_buff *skb; | ||
| 144 | |||
| 145 | /* Create the new skb with enough headroom to fit the HSR tag */ | ||
| 146 | skb = __pskb_copy(skb_o, skb_headroom(skb_o) + HSR_HLEN, GFP_ATOMIC); | ||
| 147 | if (skb == NULL) | ||
| 148 | return NULL; | ||
| 149 | skb_reset_mac_header(skb); | ||
| 150 | |||
| 151 | if (skb->ip_summed == CHECKSUM_PARTIAL) | ||
| 152 | skb->csum_start += HSR_HLEN; | ||
| 153 | |||
| 154 | movelen = ETH_HLEN; | ||
| 155 | if (frame->is_vlan) | ||
| 156 | movelen += VLAN_HLEN; | ||
| 157 | |||
| 158 | src = skb_mac_header(skb); | ||
| 159 | dst = skb_push(skb, HSR_HLEN); | ||
| 160 | memmove(dst, src, movelen); | ||
| 161 | skb_reset_mac_header(skb); | ||
| 162 | |||
| 163 | hsr_fill_tag(skb, frame, port); | ||
| 164 | |||
| 165 | return skb; | ||
| 166 | } | ||
| 167 | |||
| 168 | /* If the original frame was an HSR tagged frame, just clone it to be sent | ||
| 169 | * unchanged. Otherwise, create a private frame especially tagged for 'port'. | ||
| 170 | */ | ||
| 171 | static struct sk_buff *frame_get_tagged_skb(struct hsr_frame_info *frame, | ||
| 172 | struct hsr_port *port) | ||
| 173 | { | ||
| 174 | if (frame->skb_hsr) | ||
| 175 | return skb_clone(frame->skb_hsr, GFP_ATOMIC); | ||
| 176 | |||
| 177 | if ((port->type != HSR_PT_SLAVE_A) && (port->type != HSR_PT_SLAVE_B)) { | ||
| 178 | WARN_ONCE(1, "HSR: Bug: trying to create a tagged frame for a non-ring port"); | ||
| 179 | return NULL; | ||
| 180 | } | ||
| 181 | |||
| 182 | return create_tagged_skb(frame->skb_std, frame, port); | ||
| 183 | } | ||
| 184 | |||
| 185 | |||
| 186 | static void hsr_deliver_master(struct sk_buff *skb, struct net_device *dev, | ||
| 187 | struct hsr_node *node_src) | ||
| 188 | { | ||
| 189 | bool was_multicast_frame; | ||
| 190 | int res; | ||
| 191 | |||
| 192 | was_multicast_frame = (skb->pkt_type == PACKET_MULTICAST); | ||
| 193 | hsr_addr_subst_source(node_src, skb); | ||
| 194 | skb_pull(skb, ETH_HLEN); | ||
| 195 | res = netif_rx(skb); | ||
| 196 | if (res == NET_RX_DROP) { | ||
| 197 | dev->stats.rx_dropped++; | ||
| 198 | } else { | ||
| 199 | dev->stats.rx_packets++; | ||
| 200 | dev->stats.rx_bytes += skb->len; | ||
| 201 | if (was_multicast_frame) | ||
| 202 | dev->stats.multicast++; | ||
| 203 | } | ||
| 204 | } | ||
| 205 | |||
| 206 | static int hsr_xmit(struct sk_buff *skb, struct hsr_port *port, | ||
| 207 | struct hsr_frame_info *frame) | ||
| 208 | { | ||
| 209 | if (frame->port_rcv->type == HSR_PT_MASTER) { | ||
| 210 | hsr_addr_subst_dest(frame->node_src, skb, port); | ||
| 211 | |||
| 212 | /* Address substitution (IEC62439-3 pp 26, 50): replace mac | ||
| 213 | * address of outgoing frame with that of the outgoing slave's. | ||
| 214 | */ | ||
| 215 | ether_addr_copy(eth_hdr(skb)->h_source, port->dev->dev_addr); | ||
| 216 | } | ||
| 217 | return dev_queue_xmit(skb); | ||
| 218 | } | ||
| 219 | |||
| 220 | |||
| 221 | /* Forward the frame through all devices except: | ||
| 222 | * - Back through the receiving device | ||
| 223 | * - If it's a HSR frame: through a device where it has passed before | ||
| 224 | * - To the local HSR master only if the frame is directly addressed to it, or | ||
| 225 | * a non-supervision multicast or broadcast frame. | ||
| 226 | * | ||
| 227 | * HSR slave devices should insert a HSR tag into the frame, or forward the | ||
| 228 | * frame unchanged if it's already tagged. Interlink devices should strip HSR | ||
| 229 | * tags if they're of the non-HSR type (but only after duplicate discard). The | ||
| 230 | * master device always strips HSR tags. | ||
| 231 | */ | ||
| 232 | static void hsr_forward_do(struct hsr_frame_info *frame) | ||
| 233 | { | ||
| 234 | struct hsr_port *port; | ||
| 235 | struct sk_buff *skb; | ||
| 236 | |||
| 237 | hsr_for_each_port(frame->port_rcv->hsr, port) { | ||
| 238 | /* Don't send frame back the way it came */ | ||
| 239 | if (port == frame->port_rcv) | ||
| 240 | continue; | ||
| 241 | |||
| 242 | /* Don't deliver locally unless we should */ | ||
| 243 | if ((port->type == HSR_PT_MASTER) && !frame->is_local_dest) | ||
| 244 | continue; | ||
| 245 | |||
| 246 | /* Deliver frames directly addressed to us to master only */ | ||
| 247 | if ((port->type != HSR_PT_MASTER) && frame->is_local_exclusive) | ||
| 248 | continue; | ||
| 249 | |||
| 250 | /* Don't send frame over port where it has been sent before */ | ||
| 251 | if (hsr_register_frame_out(port, frame->node_src, | ||
| 252 | frame->sequence_nr)) | ||
| 253 | continue; | ||
| 254 | |||
| 255 | if (frame->is_supervision && (port->type == HSR_PT_MASTER)) { | ||
| 256 | hsr_handle_sup_frame(frame->skb_hsr, | ||
| 257 | frame->node_src, | ||
| 258 | frame->port_rcv); | ||
| 259 | continue; | ||
| 260 | } | ||
| 261 | |||
| 262 | if (port->type != HSR_PT_MASTER) | ||
| 263 | skb = frame_get_tagged_skb(frame, port); | ||
| 264 | else | ||
| 265 | skb = frame_get_stripped_skb(frame, port); | ||
| 266 | if (skb == NULL) { | ||
| 267 | /* FIXME: Record the dropped frame? */ | ||
| 268 | continue; | ||
| 269 | } | ||
| 270 | |||
| 271 | skb->dev = port->dev; | ||
| 272 | if (port->type == HSR_PT_MASTER) | ||
| 273 | hsr_deliver_master(skb, port->dev, frame->node_src); | ||
| 274 | else | ||
| 275 | hsr_xmit(skb, port, frame); | ||
| 276 | } | ||
| 277 | } | ||
| 278 | |||
| 279 | |||
| 280 | static void check_local_dest(struct hsr_priv *hsr, struct sk_buff *skb, | ||
| 281 | struct hsr_frame_info *frame) | ||
| 282 | { | ||
| 283 | struct net_device *master_dev; | ||
| 284 | |||
| 285 | master_dev = hsr_port_get_hsr(hsr, HSR_PT_MASTER)->dev; | ||
| 286 | |||
| 287 | if (hsr_addr_is_self(hsr, eth_hdr(skb)->h_dest)) { | ||
| 288 | frame->is_local_exclusive = true; | ||
| 289 | skb->pkt_type = PACKET_HOST; | ||
| 290 | } else { | ||
| 291 | frame->is_local_exclusive = false; | ||
| 292 | } | ||
| 293 | |||
| 294 | if ((skb->pkt_type == PACKET_HOST) || | ||
| 295 | (skb->pkt_type == PACKET_MULTICAST) || | ||
| 296 | (skb->pkt_type == PACKET_BROADCAST)) { | ||
| 297 | frame->is_local_dest = true; | ||
| 298 | } else { | ||
| 299 | frame->is_local_dest = false; | ||
| 300 | } | ||
| 301 | } | ||
| 302 | |||
| 303 | |||
| 304 | static int hsr_fill_frame_info(struct hsr_frame_info *frame, | ||
| 305 | struct sk_buff *skb, struct hsr_port *port) | ||
| 306 | { | ||
| 307 | struct ethhdr *ethhdr; | ||
| 308 | unsigned long irqflags; | ||
| 309 | |||
| 310 | frame->is_supervision = is_supervision_frame(port->hsr, skb); | ||
| 311 | frame->node_src = hsr_get_node(&port->hsr->node_db, skb, | ||
| 312 | frame->is_supervision); | ||
| 313 | if (frame->node_src == NULL) | ||
| 314 | return -1; /* Unknown node and !is_supervision, or no mem */ | ||
| 315 | |||
| 316 | ethhdr = (struct ethhdr *) skb_mac_header(skb); | ||
| 317 | frame->is_vlan = false; | ||
| 318 | if (ethhdr->h_proto == htons(ETH_P_8021Q)) { | ||
| 319 | frame->is_vlan = true; | ||
| 320 | /* FIXME: */ | ||
| 321 | WARN_ONCE(1, "HSR: VLAN not yet supported"); | ||
| 322 | } | ||
| 323 | if (ethhdr->h_proto == htons(ETH_P_PRP)) { | ||
| 324 | frame->skb_std = NULL; | ||
| 325 | frame->skb_hsr = skb; | ||
| 326 | frame->sequence_nr = hsr_get_skb_sequence_nr(skb); | ||
| 327 | } else { | ||
| 328 | frame->skb_std = skb; | ||
| 329 | frame->skb_hsr = NULL; | ||
| 330 | /* Sequence nr for the master node */ | ||
| 331 | spin_lock_irqsave(&port->hsr->seqnr_lock, irqflags); | ||
| 332 | frame->sequence_nr = port->hsr->sequence_nr; | ||
| 333 | port->hsr->sequence_nr++; | ||
| 334 | spin_unlock_irqrestore(&port->hsr->seqnr_lock, irqflags); | ||
| 335 | } | ||
| 336 | |||
| 337 | frame->port_rcv = port; | ||
| 338 | check_local_dest(port->hsr, skb, frame); | ||
| 339 | |||
| 340 | return 0; | ||
| 341 | } | ||
| 342 | |||
| 343 | /* Must be called holding rcu read lock (because of the port parameter) */ | ||
| 344 | void hsr_forward_skb(struct sk_buff *skb, struct hsr_port *port) | ||
| 345 | { | ||
| 346 | struct hsr_frame_info frame; | ||
| 347 | |||
| 348 | if (skb_mac_header(skb) != skb->data) { | ||
| 349 | WARN_ONCE(1, "%s:%d: Malformed frame (port_src %s)\n", | ||
| 350 | __FILE__, __LINE__, port->dev->name); | ||
| 351 | goto out_drop; | ||
| 352 | } | ||
| 353 | |||
| 354 | if (hsr_fill_frame_info(&frame, skb, port) < 0) | ||
| 355 | goto out_drop; | ||
| 356 | hsr_register_frame_in(frame.node_src, port, frame.sequence_nr); | ||
| 357 | hsr_forward_do(&frame); | ||
| 358 | |||
| 359 | if (frame.skb_hsr != NULL) | ||
| 360 | kfree_skb(frame.skb_hsr); | ||
| 361 | if (frame.skb_std != NULL) | ||
| 362 | kfree_skb(frame.skb_std); | ||
| 363 | return; | ||
| 364 | |||
| 365 | out_drop: | ||
| 366 | port->dev->stats.tx_dropped++; | ||
| 367 | kfree_skb(skb); | ||
| 368 | } | ||
diff --git a/net/hsr/hsr_forward.h b/net/hsr/hsr_forward.h new file mode 100644 index 000000000000..5c5bc4b6b75f --- /dev/null +++ b/net/hsr/hsr_forward.h | |||
| @@ -0,0 +1,20 @@ | |||
| 1 | /* Copyright 2011-2014 Autronica Fire and Security AS | ||
| 2 | * | ||
| 3 | * This program is free software; you can redistribute it and/or modify it | ||
| 4 | * under the terms of the GNU General Public License as published by the Free | ||
| 5 | * Software Foundation; either version 2 of the License, or (at your option) | ||
| 6 | * any later version. | ||
| 7 | * | ||
| 8 | * Author(s): | ||
| 9 | * 2011-2014 Arvid Brodin, arvid.brodin@alten.se | ||
| 10 | */ | ||
| 11 | |||
| 12 | #ifndef __HSR_FORWARD_H | ||
| 13 | #define __HSR_FORWARD_H | ||
| 14 | |||
| 15 | #include <linux/netdevice.h> | ||
| 16 | #include "hsr_main.h" | ||
| 17 | |||
| 18 | void hsr_forward_skb(struct sk_buff *skb, struct hsr_port *port); | ||
| 19 | |||
| 20 | #endif /* __HSR_FORWARD_H */ | ||
diff --git a/net/hsr/hsr_framereg.c b/net/hsr/hsr_framereg.c index 83e58449366a..bace124d14ef 100644 --- a/net/hsr/hsr_framereg.c +++ b/net/hsr/hsr_framereg.c | |||
| @@ -1,4 +1,4 @@ | |||
| 1 | /* Copyright 2011-2013 Autronica Fire and Security AS | 1 | /* Copyright 2011-2014 Autronica Fire and Security AS |
| 2 | * | 2 | * |
| 3 | * This program is free software; you can redistribute it and/or modify it | 3 | * This program is free software; you can redistribute it and/or modify it |
| 4 | * under the terms of the GNU General Public License as published by the Free | 4 | * under the terms of the GNU General Public License as published by the Free |
| @@ -6,7 +6,7 @@ | |||
| 6 | * any later version. | 6 | * any later version. |
| 7 | * | 7 | * |
| 8 | * Author(s): | 8 | * Author(s): |
| 9 | * 2011-2013 Arvid Brodin, arvid.brodin@xdin.com | 9 | * 2011-2014 Arvid Brodin, arvid.brodin@alten.se |
| 10 | * | 10 | * |
| 11 | * The HSR spec says never to forward the same frame twice on the same | 11 | * The HSR spec says never to forward the same frame twice on the same |
| 12 | * interface. A frame is identified by its source MAC address and its HSR | 12 | * interface. A frame is identified by its source MAC address and its HSR |
| @@ -23,71 +23,68 @@ | |||
| 23 | #include "hsr_netlink.h" | 23 | #include "hsr_netlink.h" |
| 24 | 24 | ||
| 25 | 25 | ||
| 26 | struct node_entry { | 26 | struct hsr_node { |
| 27 | struct list_head mac_list; | 27 | struct list_head mac_list; |
| 28 | unsigned char MacAddressA[ETH_ALEN]; | 28 | unsigned char MacAddressA[ETH_ALEN]; |
| 29 | unsigned char MacAddressB[ETH_ALEN]; | 29 | unsigned char MacAddressB[ETH_ALEN]; |
| 30 | enum hsr_dev_idx AddrB_if; /* The local slave through which AddrB | 30 | /* Local slave through which AddrB frames are received from this node */ |
| 31 | * frames are received from this node | 31 | enum hsr_port_type AddrB_port; |
| 32 | */ | 32 | unsigned long time_in[HSR_PT_PORTS]; |
| 33 | unsigned long time_in[HSR_MAX_SLAVE]; | 33 | bool time_in_stale[HSR_PT_PORTS]; |
| 34 | bool time_in_stale[HSR_MAX_SLAVE]; | 34 | u16 seq_out[HSR_PT_PORTS]; |
| 35 | u16 seq_out[HSR_MAX_DEV]; | 35 | struct rcu_head rcu_head; |
| 36 | struct rcu_head rcu_head; | ||
| 37 | }; | 36 | }; |
| 38 | 37 | ||
| 39 | /* TODO: use hash lists for mac addresses (linux/jhash.h)? */ | ||
| 40 | 38 | ||
| 39 | /* TODO: use hash lists for mac addresses (linux/jhash.h)? */ | ||
| 41 | 40 | ||
| 42 | 41 | ||
| 43 | /* Search for mac entry. Caller must hold rcu read lock. | 42 | /* seq_nr_after(a, b) - return true if a is after (higher in sequence than) b, |
| 43 | * false otherwise. | ||
| 44 | */ | 44 | */ |
| 45 | static struct node_entry *find_node_by_AddrA(struct list_head *node_db, | 45 | static bool seq_nr_after(u16 a, u16 b) |
| 46 | const unsigned char addr[ETH_ALEN]) | ||
| 47 | { | 46 | { |
| 48 | struct node_entry *node; | 47 | /* Remove inconsistency where |
| 49 | 48 | * seq_nr_after(a, b) == seq_nr_before(a, b) | |
| 50 | list_for_each_entry_rcu(node, node_db, mac_list) { | 49 | */ |
| 51 | if (ether_addr_equal(node->MacAddressA, addr)) | 50 | if ((int) b - a == 32768) |
| 52 | return node; | 51 | return false; |
| 53 | } | ||
| 54 | 52 | ||
| 55 | return NULL; | 53 | return (((s16) (b - a)) < 0); |
| 56 | } | 54 | } |
| 55 | #define seq_nr_before(a, b) seq_nr_after((b), (a)) | ||
| 56 | #define seq_nr_after_or_eq(a, b) (!seq_nr_before((a), (b))) | ||
| 57 | #define seq_nr_before_or_eq(a, b) (!seq_nr_after((a), (b))) | ||
| 57 | 58 | ||
| 58 | 59 | ||
| 59 | /* Search for mac entry. Caller must hold rcu read lock. | 60 | bool hsr_addr_is_self(struct hsr_priv *hsr, unsigned char *addr) |
| 60 | */ | ||
| 61 | static struct node_entry *find_node_by_AddrB(struct list_head *node_db, | ||
| 62 | const unsigned char addr[ETH_ALEN]) | ||
| 63 | { | 61 | { |
| 64 | struct node_entry *node; | 62 | struct hsr_node *node; |
| 65 | 63 | ||
| 66 | list_for_each_entry_rcu(node, node_db, mac_list) { | 64 | node = list_first_or_null_rcu(&hsr->self_node_db, struct hsr_node, |
| 67 | if (ether_addr_equal(node->MacAddressB, addr)) | 65 | mac_list); |
| 68 | return node; | 66 | if (!node) { |
| 67 | WARN_ONCE(1, "HSR: No self node\n"); | ||
| 68 | return false; | ||
| 69 | } | 69 | } |
| 70 | 70 | ||
| 71 | return NULL; | 71 | if (ether_addr_equal(addr, node->MacAddressA)) |
| 72 | } | 72 | return true; |
| 73 | if (ether_addr_equal(addr, node->MacAddressB)) | ||
| 74 | return true; | ||
| 73 | 75 | ||
| 76 | return false; | ||
| 77 | } | ||
| 74 | 78 | ||
| 75 | /* Search for mac entry. Caller must hold rcu read lock. | 79 | /* Search for mac entry. Caller must hold rcu read lock. |
| 76 | */ | 80 | */ |
| 77 | struct node_entry *hsr_find_node(struct list_head *node_db, struct sk_buff *skb) | 81 | static struct hsr_node *find_node_by_AddrA(struct list_head *node_db, |
| 82 | const unsigned char addr[ETH_ALEN]) | ||
| 78 | { | 83 | { |
| 79 | struct node_entry *node; | 84 | struct hsr_node *node; |
| 80 | struct ethhdr *ethhdr; | ||
| 81 | |||
| 82 | if (!skb_mac_header_was_set(skb)) | ||
| 83 | return NULL; | ||
| 84 | |||
| 85 | ethhdr = (struct ethhdr *) skb_mac_header(skb); | ||
| 86 | 85 | ||
| 87 | list_for_each_entry_rcu(node, node_db, mac_list) { | 86 | list_for_each_entry_rcu(node, node_db, mac_list) { |
| 88 | if (ether_addr_equal(node->MacAddressA, ethhdr->h_source)) | 87 | if (ether_addr_equal(node->MacAddressA, addr)) |
| 89 | return node; | ||
| 90 | if (ether_addr_equal(node->MacAddressB, ethhdr->h_source)) | ||
| 91 | return node; | 88 | return node; |
| 92 | } | 89 | } |
| 93 | 90 | ||
| @@ -102,7 +99,7 @@ int hsr_create_self_node(struct list_head *self_node_db, | |||
| 102 | unsigned char addr_a[ETH_ALEN], | 99 | unsigned char addr_a[ETH_ALEN], |
| 103 | unsigned char addr_b[ETH_ALEN]) | 100 | unsigned char addr_b[ETH_ALEN]) |
| 104 | { | 101 | { |
| 105 | struct node_entry *node, *oldnode; | 102 | struct hsr_node *node, *oldnode; |
| 106 | 103 | ||
| 107 | node = kmalloc(sizeof(*node), GFP_KERNEL); | 104 | node = kmalloc(sizeof(*node), GFP_KERNEL); |
| 108 | if (!node) | 105 | if (!node) |
| @@ -113,7 +110,7 @@ int hsr_create_self_node(struct list_head *self_node_db, | |||
| 113 | 110 | ||
| 114 | rcu_read_lock(); | 111 | rcu_read_lock(); |
| 115 | oldnode = list_first_or_null_rcu(self_node_db, | 112 | oldnode = list_first_or_null_rcu(self_node_db, |
| 116 | struct node_entry, mac_list); | 113 | struct hsr_node, mac_list); |
| 117 | if (oldnode) { | 114 | if (oldnode) { |
| 118 | list_replace_rcu(&oldnode->mac_list, &node->mac_list); | 115 | list_replace_rcu(&oldnode->mac_list, &node->mac_list); |
| 119 | rcu_read_unlock(); | 116 | rcu_read_unlock(); |
| @@ -128,135 +125,144 @@ int hsr_create_self_node(struct list_head *self_node_db, | |||
| 128 | } | 125 | } |
| 129 | 126 | ||
| 130 | 127 | ||
| 131 | /* Add/merge node to the database of nodes. 'skb' must contain an HSR | 128 | /* Allocate an hsr_node and add it to node_db. 'addr' is the node's AddressA; |
| 132 | * supervision frame. | 129 | * seq_out is used to initialize filtering of outgoing duplicate frames |
| 133 | * - If the supervision header's MacAddressA field is not yet in the database, | 130 | * originating from the newly added node. |
| 134 | * this frame is from an hitherto unknown node - add it to the database. | ||
| 135 | * - If the sender's MAC address is not the same as its MacAddressA address, | ||
| 136 | * the node is using PICS_SUBS (address substitution). Record the sender's | ||
| 137 | * address as the node's MacAddressB. | ||
| 138 | * | ||
| 139 | * This function needs to work even if the sender node has changed one of its | ||
| 140 | * slaves' MAC addresses. In this case, there are four different cases described | ||
| 141 | * by (Addr-changed, received-from) pairs as follows. Note that changing the | ||
| 142 | * SlaveA address is equal to changing the node's own address: | ||
| 143 | * | ||
| 144 | * - (AddrB, SlaveB): The new AddrB will be recorded by PICS_SUBS code since | ||
| 145 | * node == NULL. | ||
| 146 | * - (AddrB, SlaveA): Will work as usual (the AddrB change won't be detected | ||
| 147 | * from this frame). | ||
| 148 | * | ||
| 149 | * - (AddrA, SlaveB): The old node will be found. We need to detect this and | ||
| 150 | * remove the node. | ||
| 151 | * - (AddrA, SlaveA): A new node will be registered (non-PICS_SUBS at first). | ||
| 152 | * The old one will be pruned after HSR_NODE_FORGET_TIME. | ||
| 153 | * | ||
| 154 | * We also need to detect if the sender's SlaveA and SlaveB cables have been | ||
| 155 | * swapped. | ||
| 156 | */ | 131 | */ |
| 157 | struct node_entry *hsr_merge_node(struct hsr_priv *hsr_priv, | 132 | struct hsr_node *hsr_add_node(struct list_head *node_db, unsigned char addr[], |
| 158 | struct node_entry *node, | 133 | u16 seq_out) |
| 159 | struct sk_buff *skb, | ||
| 160 | enum hsr_dev_idx dev_idx) | ||
| 161 | { | 134 | { |
| 162 | struct hsr_sup_payload *hsr_sp; | 135 | struct hsr_node *node; |
| 163 | struct hsr_ethhdr_sp *hsr_ethsup; | ||
| 164 | int i; | ||
| 165 | unsigned long now; | 136 | unsigned long now; |
| 166 | 137 | int i; | |
| 167 | hsr_ethsup = (struct hsr_ethhdr_sp *) skb_mac_header(skb); | ||
| 168 | hsr_sp = (struct hsr_sup_payload *) skb->data; | ||
| 169 | |||
| 170 | if (node && !ether_addr_equal(node->MacAddressA, hsr_sp->MacAddressA)) { | ||
| 171 | /* Node has changed its AddrA, frame was received from SlaveB */ | ||
| 172 | list_del_rcu(&node->mac_list); | ||
| 173 | kfree_rcu(node, rcu_head); | ||
| 174 | node = NULL; | ||
| 175 | } | ||
| 176 | |||
| 177 | if (node && (dev_idx == node->AddrB_if) && | ||
| 178 | !ether_addr_equal(node->MacAddressB, hsr_ethsup->ethhdr.h_source)) { | ||
| 179 | /* Cables have been swapped */ | ||
| 180 | list_del_rcu(&node->mac_list); | ||
| 181 | kfree_rcu(node, rcu_head); | ||
| 182 | node = NULL; | ||
| 183 | } | ||
| 184 | |||
| 185 | if (node && (dev_idx != node->AddrB_if) && | ||
| 186 | (node->AddrB_if != HSR_DEV_NONE) && | ||
| 187 | !ether_addr_equal(node->MacAddressA, hsr_ethsup->ethhdr.h_source)) { | ||
| 188 | /* Cables have been swapped */ | ||
| 189 | list_del_rcu(&node->mac_list); | ||
| 190 | kfree_rcu(node, rcu_head); | ||
| 191 | node = NULL; | ||
| 192 | } | ||
| 193 | |||
| 194 | if (node) | ||
| 195 | return node; | ||
| 196 | |||
| 197 | node = find_node_by_AddrA(&hsr_priv->node_db, hsr_sp->MacAddressA); | ||
| 198 | if (node) { | ||
| 199 | /* Node is known, but frame was received from an unknown | ||
| 200 | * address. Node is PICS_SUBS capable; merge its AddrB. | ||
| 201 | */ | ||
| 202 | ether_addr_copy(node->MacAddressB, hsr_ethsup->ethhdr.h_source); | ||
| 203 | node->AddrB_if = dev_idx; | ||
| 204 | return node; | ||
| 205 | } | ||
| 206 | 138 | ||
| 207 | node = kzalloc(sizeof(*node), GFP_ATOMIC); | 139 | node = kzalloc(sizeof(*node), GFP_ATOMIC); |
| 208 | if (!node) | 140 | if (!node) |
| 209 | return NULL; | 141 | return NULL; |
| 210 | 142 | ||
| 211 | ether_addr_copy(node->MacAddressA, hsr_sp->MacAddressA); | 143 | ether_addr_copy(node->MacAddressA, addr); |
| 212 | ether_addr_copy(node->MacAddressB, hsr_ethsup->ethhdr.h_source); | ||
| 213 | if (!ether_addr_equal(hsr_sp->MacAddressA, hsr_ethsup->ethhdr.h_source)) | ||
| 214 | node->AddrB_if = dev_idx; | ||
| 215 | else | ||
| 216 | node->AddrB_if = HSR_DEV_NONE; | ||
| 217 | 144 | ||
| 218 | /* We are only interested in time diffs here, so use current jiffies | 145 | /* We are only interested in time diffs here, so use current jiffies |
| 219 | * as initialization. (0 could trigger an spurious ring error warning). | 146 | * as initialization. (0 could trigger an spurious ring error warning). |
| 220 | */ | 147 | */ |
| 221 | now = jiffies; | 148 | now = jiffies; |
| 222 | for (i = 0; i < HSR_MAX_SLAVE; i++) | 149 | for (i = 0; i < HSR_PT_PORTS; i++) |
| 223 | node->time_in[i] = now; | 150 | node->time_in[i] = now; |
| 224 | for (i = 0; i < HSR_MAX_DEV; i++) | 151 | for (i = 0; i < HSR_PT_PORTS; i++) |
| 225 | node->seq_out[i] = ntohs(hsr_ethsup->hsr_sup.sequence_nr) - 1; | 152 | node->seq_out[i] = seq_out; |
| 226 | 153 | ||
| 227 | list_add_tail_rcu(&node->mac_list, &hsr_priv->node_db); | 154 | list_add_tail_rcu(&node->mac_list, node_db); |
| 228 | 155 | ||
| 229 | return node; | 156 | return node; |
| 230 | } | 157 | } |
| 231 | 158 | ||
| 159 | /* Get the hsr_node from which 'skb' was sent. | ||
| 160 | */ | ||
| 161 | struct hsr_node *hsr_get_node(struct list_head *node_db, struct sk_buff *skb, | ||
| 162 | bool is_sup) | ||
| 163 | { | ||
| 164 | struct hsr_node *node; | ||
| 165 | struct ethhdr *ethhdr; | ||
| 166 | u16 seq_out; | ||
| 167 | |||
| 168 | if (!skb_mac_header_was_set(skb)) | ||
| 169 | return NULL; | ||
| 170 | |||
| 171 | ethhdr = (struct ethhdr *) skb_mac_header(skb); | ||
| 172 | |||
| 173 | list_for_each_entry_rcu(node, node_db, mac_list) { | ||
| 174 | if (ether_addr_equal(node->MacAddressA, ethhdr->h_source)) | ||
| 175 | return node; | ||
| 176 | if (ether_addr_equal(node->MacAddressB, ethhdr->h_source)) | ||
| 177 | return node; | ||
| 178 | } | ||
| 179 | |||
| 180 | if (!is_sup) | ||
| 181 | return NULL; /* Only supervision frame may create node entry */ | ||
| 182 | |||
| 183 | if (ethhdr->h_proto == htons(ETH_P_PRP)) { | ||
| 184 | /* Use the existing sequence_nr from the tag as starting point | ||
| 185 | * for filtering duplicate frames. | ||
| 186 | */ | ||
| 187 | seq_out = hsr_get_skb_sequence_nr(skb) - 1; | ||
| 188 | } else { | ||
| 189 | WARN_ONCE(1, "%s: Non-HSR frame\n", __func__); | ||
| 190 | seq_out = 0; | ||
| 191 | } | ||
| 192 | |||
| 193 | return hsr_add_node(node_db, ethhdr->h_source, seq_out); | ||
| 194 | } | ||
| 195 | |||
| 196 | /* Use the Supervision frame's info about an eventual MacAddressB for merging | ||
| 197 | * nodes that has previously had their MacAddressB registered as a separate | ||
| 198 | * node. | ||
| 199 | */ | ||
| 200 | void hsr_handle_sup_frame(struct sk_buff *skb, struct hsr_node *node_curr, | ||
| 201 | struct hsr_port *port_rcv) | ||
| 202 | { | ||
| 203 | struct hsr_node *node_real; | ||
| 204 | struct hsr_sup_payload *hsr_sp; | ||
| 205 | struct list_head *node_db; | ||
| 206 | int i; | ||
| 207 | |||
| 208 | skb_pull(skb, sizeof(struct hsr_ethhdr_sp)); | ||
| 209 | hsr_sp = (struct hsr_sup_payload *) skb->data; | ||
| 210 | |||
| 211 | if (ether_addr_equal(eth_hdr(skb)->h_source, hsr_sp->MacAddressA)) | ||
| 212 | /* Not sent from MacAddressB of a PICS_SUBS capable node */ | ||
| 213 | goto done; | ||
| 214 | |||
| 215 | /* Merge node_curr (registered on MacAddressB) into node_real */ | ||
| 216 | node_db = &port_rcv->hsr->node_db; | ||
| 217 | node_real = find_node_by_AddrA(node_db, hsr_sp->MacAddressA); | ||
| 218 | if (!node_real) | ||
| 219 | /* No frame received from AddrA of this node yet */ | ||
| 220 | node_real = hsr_add_node(node_db, hsr_sp->MacAddressA, | ||
| 221 | HSR_SEQNR_START - 1); | ||
| 222 | if (!node_real) | ||
| 223 | goto done; /* No mem */ | ||
| 224 | if (node_real == node_curr) | ||
| 225 | /* Node has already been merged */ | ||
| 226 | goto done; | ||
| 227 | |||
| 228 | ether_addr_copy(node_real->MacAddressB, eth_hdr(skb)->h_source); | ||
| 229 | for (i = 0; i < HSR_PT_PORTS; i++) { | ||
| 230 | if (!node_curr->time_in_stale[i] && | ||
| 231 | time_after(node_curr->time_in[i], node_real->time_in[i])) { | ||
| 232 | node_real->time_in[i] = node_curr->time_in[i]; | ||
| 233 | node_real->time_in_stale[i] = node_curr->time_in_stale[i]; | ||
| 234 | } | ||
| 235 | if (seq_nr_after(node_curr->seq_out[i], node_real->seq_out[i])) | ||
| 236 | node_real->seq_out[i] = node_curr->seq_out[i]; | ||
| 237 | } | ||
| 238 | node_real->AddrB_port = port_rcv->type; | ||
| 239 | |||
| 240 | list_del_rcu(&node_curr->mac_list); | ||
| 241 | kfree_rcu(node_curr, rcu_head); | ||
| 242 | |||
| 243 | done: | ||
| 244 | skb_push(skb, sizeof(struct hsr_ethhdr_sp)); | ||
| 245 | } | ||
| 246 | |||
| 232 | 247 | ||
| 233 | /* 'skb' is a frame meant for this host, that is to be passed to upper layers. | 248 | /* 'skb' is a frame meant for this host, that is to be passed to upper layers. |
| 234 | * | 249 | * |
| 235 | * If the frame was sent by a node's B interface, replace the sender | 250 | * If the frame was sent by a node's B interface, replace the source |
| 236 | * address with that node's "official" address (MacAddressA) so that upper | 251 | * address with that node's "official" address (MacAddressA) so that upper |
| 237 | * layers recognize where it came from. | 252 | * layers recognize where it came from. |
| 238 | */ | 253 | */ |
| 239 | void hsr_addr_subst_source(struct hsr_priv *hsr_priv, struct sk_buff *skb) | 254 | void hsr_addr_subst_source(struct hsr_node *node, struct sk_buff *skb) |
| 240 | { | 255 | { |
| 241 | struct ethhdr *ethhdr; | ||
| 242 | struct node_entry *node; | ||
| 243 | |||
| 244 | if (!skb_mac_header_was_set(skb)) { | 256 | if (!skb_mac_header_was_set(skb)) { |
| 245 | WARN_ONCE(1, "%s: Mac header not set\n", __func__); | 257 | WARN_ONCE(1, "%s: Mac header not set\n", __func__); |
| 246 | return; | 258 | return; |
| 247 | } | 259 | } |
| 248 | ethhdr = (struct ethhdr *) skb_mac_header(skb); | ||
| 249 | 260 | ||
| 250 | rcu_read_lock(); | 261 | memcpy(ð_hdr(skb)->h_source, node->MacAddressA, ETH_ALEN); |
| 251 | node = find_node_by_AddrB(&hsr_priv->node_db, ethhdr->h_source); | ||
| 252 | if (node) | ||
| 253 | ether_addr_copy(ethhdr->h_source, node->MacAddressA); | ||
| 254 | rcu_read_unlock(); | ||
| 255 | } | 262 | } |
| 256 | 263 | ||
| 257 | |||
| 258 | /* 'skb' is a frame meant for another host. | 264 | /* 'skb' is a frame meant for another host. |
| 259 | * 'hsr_dev_idx' is the HSR index of the outgoing device | 265 | * 'port' is the outgoing interface |
| 260 | * | 266 | * |
| 261 | * Substitute the target (dest) MAC address if necessary, so the it matches the | 267 | * Substitute the target (dest) MAC address if necessary, so the it matches the |
| 262 | * recipient interface MAC address, regardless of whether that is the | 268 | * recipient interface MAC address, regardless of whether that is the |
| @@ -264,47 +270,44 @@ void hsr_addr_subst_source(struct hsr_priv *hsr_priv, struct sk_buff *skb) | |||
| 264 | * This is needed to keep the packets flowing through switches that learn on | 270 | * This is needed to keep the packets flowing through switches that learn on |
| 265 | * which "side" the different interfaces are. | 271 | * which "side" the different interfaces are. |
| 266 | */ | 272 | */ |
| 267 | void hsr_addr_subst_dest(struct hsr_priv *hsr_priv, struct ethhdr *ethhdr, | 273 | void hsr_addr_subst_dest(struct hsr_node *node_src, struct sk_buff *skb, |
| 268 | enum hsr_dev_idx dev_idx) | 274 | struct hsr_port *port) |
| 269 | { | 275 | { |
| 270 | struct node_entry *node; | 276 | struct hsr_node *node_dst; |
| 271 | 277 | ||
| 272 | rcu_read_lock(); | 278 | if (!skb_mac_header_was_set(skb)) { |
| 273 | node = find_node_by_AddrA(&hsr_priv->node_db, ethhdr->h_dest); | 279 | WARN_ONCE(1, "%s: Mac header not set\n", __func__); |
| 274 | if (node && (node->AddrB_if == dev_idx)) | 280 | return; |
| 275 | ether_addr_copy(ethhdr->h_dest, node->MacAddressB); | 281 | } |
| 276 | rcu_read_unlock(); | ||
| 277 | } | ||
| 278 | 282 | ||
| 283 | if (!is_unicast_ether_addr(eth_hdr(skb)->h_dest)) | ||
| 284 | return; | ||
| 279 | 285 | ||
| 280 | /* seq_nr_after(a, b) - return true if a is after (higher in sequence than) b, | 286 | node_dst = find_node_by_AddrA(&port->hsr->node_db, eth_hdr(skb)->h_dest); |
| 281 | * false otherwise. | 287 | if (!node_dst) { |
| 282 | */ | 288 | WARN_ONCE(1, "%s: Unknown node\n", __func__); |
| 283 | static bool seq_nr_after(u16 a, u16 b) | 289 | return; |
| 284 | { | 290 | } |
| 285 | /* Remove inconsistency where | 291 | if (port->type != node_dst->AddrB_port) |
| 286 | * seq_nr_after(a, b) == seq_nr_before(a, b) | 292 | return; |
| 287 | */ | ||
| 288 | if ((int) b - a == 32768) | ||
| 289 | return false; | ||
| 290 | 293 | ||
| 291 | return (((s16) (b - a)) < 0); | 294 | ether_addr_copy(eth_hdr(skb)->h_dest, node_dst->MacAddressB); |
| 292 | } | 295 | } |
| 293 | #define seq_nr_before(a, b) seq_nr_after((b), (a)) | ||
| 294 | #define seq_nr_after_or_eq(a, b) (!seq_nr_before((a), (b))) | ||
| 295 | #define seq_nr_before_or_eq(a, b) (!seq_nr_after((a), (b))) | ||
| 296 | 296 | ||
| 297 | 297 | ||
| 298 | void hsr_register_frame_in(struct node_entry *node, enum hsr_dev_idx dev_idx) | 298 | void hsr_register_frame_in(struct hsr_node *node, struct hsr_port *port, |
| 299 | u16 sequence_nr) | ||
| 299 | { | 300 | { |
| 300 | if ((dev_idx < 0) || (dev_idx >= HSR_MAX_SLAVE)) { | 301 | /* Don't register incoming frames without a valid sequence number. This |
| 301 | WARN_ONCE(1, "%s: Invalid dev_idx (%d)\n", __func__, dev_idx); | 302 | * ensures entries of restarted nodes gets pruned so that they can |
| 303 | * re-register and resume communications. | ||
| 304 | */ | ||
| 305 | if (seq_nr_before(sequence_nr, node->seq_out[port->type])) | ||
| 302 | return; | 306 | return; |
| 303 | } | ||
| 304 | node->time_in[dev_idx] = jiffies; | ||
| 305 | node->time_in_stale[dev_idx] = false; | ||
| 306 | } | ||
| 307 | 307 | ||
| 308 | node->time_in[port->type] = jiffies; | ||
| 309 | node->time_in_stale[port->type] = false; | ||
| 310 | } | ||
| 308 | 311 | ||
| 309 | /* 'skb' is a HSR Ethernet frame (with a HSR tag inserted), with a valid | 312 | /* 'skb' is a HSR Ethernet frame (with a HSR tag inserted), with a valid |
| 310 | * ethhdr->h_source address and skb->mac_header set. | 313 | * ethhdr->h_source address and skb->mac_header set. |
| @@ -314,102 +317,87 @@ void hsr_register_frame_in(struct node_entry *node, enum hsr_dev_idx dev_idx) | |||
| 314 | * 0 otherwise, or | 317 | * 0 otherwise, or |
| 315 | * negative error code on error | 318 | * negative error code on error |
| 316 | */ | 319 | */ |
| 317 | int hsr_register_frame_out(struct node_entry *node, enum hsr_dev_idx dev_idx, | 320 | int hsr_register_frame_out(struct hsr_port *port, struct hsr_node *node, |
| 318 | struct sk_buff *skb) | 321 | u16 sequence_nr) |
| 319 | { | 322 | { |
| 320 | struct hsr_ethhdr *hsr_ethhdr; | 323 | if (seq_nr_before_or_eq(sequence_nr, node->seq_out[port->type])) |
| 321 | u16 sequence_nr; | ||
| 322 | |||
| 323 | if ((dev_idx < 0) || (dev_idx >= HSR_MAX_DEV)) { | ||
| 324 | WARN_ONCE(1, "%s: Invalid dev_idx (%d)\n", __func__, dev_idx); | ||
| 325 | return -EINVAL; | ||
| 326 | } | ||
| 327 | if (!skb_mac_header_was_set(skb)) { | ||
| 328 | WARN_ONCE(1, "%s: Mac header not set\n", __func__); | ||
| 329 | return -EINVAL; | ||
| 330 | } | ||
| 331 | hsr_ethhdr = (struct hsr_ethhdr *) skb_mac_header(skb); | ||
| 332 | |||
| 333 | sequence_nr = ntohs(hsr_ethhdr->hsr_tag.sequence_nr); | ||
| 334 | if (seq_nr_before_or_eq(sequence_nr, node->seq_out[dev_idx])) | ||
| 335 | return 1; | 324 | return 1; |
| 336 | 325 | ||
| 337 | node->seq_out[dev_idx] = sequence_nr; | 326 | node->seq_out[port->type] = sequence_nr; |
| 338 | return 0; | 327 | return 0; |
| 339 | } | 328 | } |
| 340 | 329 | ||
| 341 | 330 | ||
| 342 | 331 | static struct hsr_port *get_late_port(struct hsr_priv *hsr, | |
| 343 | static bool is_late(struct node_entry *node, enum hsr_dev_idx dev_idx) | 332 | struct hsr_node *node) |
| 344 | { | 333 | { |
| 345 | enum hsr_dev_idx other; | 334 | if (node->time_in_stale[HSR_PT_SLAVE_A]) |
| 346 | 335 | return hsr_port_get_hsr(hsr, HSR_PT_SLAVE_A); | |
| 347 | if (node->time_in_stale[dev_idx]) | 336 | if (node->time_in_stale[HSR_PT_SLAVE_B]) |
| 348 | return true; | 337 | return hsr_port_get_hsr(hsr, HSR_PT_SLAVE_B); |
| 349 | 338 | ||
| 350 | if (dev_idx == HSR_DEV_SLAVE_A) | 339 | if (time_after(node->time_in[HSR_PT_SLAVE_B], |
| 351 | other = HSR_DEV_SLAVE_B; | 340 | node->time_in[HSR_PT_SLAVE_A] + |
| 352 | else | 341 | msecs_to_jiffies(MAX_SLAVE_DIFF))) |
| 353 | other = HSR_DEV_SLAVE_A; | 342 | return hsr_port_get_hsr(hsr, HSR_PT_SLAVE_A); |
| 354 | 343 | if (time_after(node->time_in[HSR_PT_SLAVE_A], | |
| 355 | if (node->time_in_stale[other]) | 344 | node->time_in[HSR_PT_SLAVE_B] + |
| 356 | return false; | 345 | msecs_to_jiffies(MAX_SLAVE_DIFF))) |
| 346 | return hsr_port_get_hsr(hsr, HSR_PT_SLAVE_B); | ||
| 357 | 347 | ||
| 358 | if (time_after(node->time_in[other], node->time_in[dev_idx] + | 348 | return NULL; |
| 359 | msecs_to_jiffies(MAX_SLAVE_DIFF))) | ||
| 360 | return true; | ||
| 361 | |||
| 362 | return false; | ||
| 363 | } | 349 | } |
| 364 | 350 | ||
| 365 | 351 | ||
| 366 | /* Remove stale sequence_nr records. Called by timer every | 352 | /* Remove stale sequence_nr records. Called by timer every |
| 367 | * HSR_LIFE_CHECK_INTERVAL (two seconds or so). | 353 | * HSR_LIFE_CHECK_INTERVAL (two seconds or so). |
| 368 | */ | 354 | */ |
| 369 | void hsr_prune_nodes(struct hsr_priv *hsr_priv) | 355 | void hsr_prune_nodes(unsigned long data) |
| 370 | { | 356 | { |
| 371 | struct node_entry *node; | 357 | struct hsr_priv *hsr; |
| 358 | struct hsr_node *node; | ||
| 359 | struct hsr_port *port; | ||
| 372 | unsigned long timestamp; | 360 | unsigned long timestamp; |
| 373 | unsigned long time_a, time_b; | 361 | unsigned long time_a, time_b; |
| 374 | 362 | ||
| 363 | hsr = (struct hsr_priv *) data; | ||
| 364 | |||
| 375 | rcu_read_lock(); | 365 | rcu_read_lock(); |
| 376 | list_for_each_entry_rcu(node, &hsr_priv->node_db, mac_list) { | 366 | list_for_each_entry_rcu(node, &hsr->node_db, mac_list) { |
| 377 | /* Shorthand */ | 367 | /* Shorthand */ |
| 378 | time_a = node->time_in[HSR_DEV_SLAVE_A]; | 368 | time_a = node->time_in[HSR_PT_SLAVE_A]; |
| 379 | time_b = node->time_in[HSR_DEV_SLAVE_B]; | 369 | time_b = node->time_in[HSR_PT_SLAVE_B]; |
| 380 | 370 | ||
| 381 | /* Check for timestamps old enough to risk wrap-around */ | 371 | /* Check for timestamps old enough to risk wrap-around */ |
| 382 | if (time_after(jiffies, time_a + MAX_JIFFY_OFFSET/2)) | 372 | if (time_after(jiffies, time_a + MAX_JIFFY_OFFSET/2)) |
| 383 | node->time_in_stale[HSR_DEV_SLAVE_A] = true; | 373 | node->time_in_stale[HSR_PT_SLAVE_A] = true; |
| 384 | if (time_after(jiffies, time_b + MAX_JIFFY_OFFSET/2)) | 374 | if (time_after(jiffies, time_b + MAX_JIFFY_OFFSET/2)) |
| 385 | node->time_in_stale[HSR_DEV_SLAVE_B] = true; | 375 | node->time_in_stale[HSR_PT_SLAVE_B] = true; |
| 386 | 376 | ||
| 387 | /* Get age of newest frame from node. | 377 | /* Get age of newest frame from node. |
| 388 | * At least one time_in is OK here; nodes get pruned long | 378 | * At least one time_in is OK here; nodes get pruned long |
| 389 | * before both time_ins can get stale | 379 | * before both time_ins can get stale |
| 390 | */ | 380 | */ |
| 391 | timestamp = time_a; | 381 | timestamp = time_a; |
| 392 | if (node->time_in_stale[HSR_DEV_SLAVE_A] || | 382 | if (node->time_in_stale[HSR_PT_SLAVE_A] || |
| 393 | (!node->time_in_stale[HSR_DEV_SLAVE_B] && | 383 | (!node->time_in_stale[HSR_PT_SLAVE_B] && |
| 394 | time_after(time_b, time_a))) | 384 | time_after(time_b, time_a))) |
| 395 | timestamp = time_b; | 385 | timestamp = time_b; |
| 396 | 386 | ||
| 397 | /* Warn of ring error only as long as we get frames at all */ | 387 | /* Warn of ring error only as long as we get frames at all */ |
| 398 | if (time_is_after_jiffies(timestamp + | 388 | if (time_is_after_jiffies(timestamp + |
| 399 | msecs_to_jiffies(1.5*MAX_SLAVE_DIFF))) { | 389 | msecs_to_jiffies(1.5*MAX_SLAVE_DIFF))) { |
| 400 | 390 | rcu_read_lock(); | |
| 401 | if (is_late(node, HSR_DEV_SLAVE_A)) | 391 | port = get_late_port(hsr, node); |
| 402 | hsr_nl_ringerror(hsr_priv, node->MacAddressA, | 392 | if (port != NULL) |
| 403 | HSR_DEV_SLAVE_A); | 393 | hsr_nl_ringerror(hsr, node->MacAddressA, port); |
| 404 | else if (is_late(node, HSR_DEV_SLAVE_B)) | 394 | rcu_read_unlock(); |
| 405 | hsr_nl_ringerror(hsr_priv, node->MacAddressA, | ||
| 406 | HSR_DEV_SLAVE_B); | ||
| 407 | } | 395 | } |
| 408 | 396 | ||
| 409 | /* Prune old entries */ | 397 | /* Prune old entries */ |
| 410 | if (time_is_before_jiffies(timestamp + | 398 | if (time_is_before_jiffies(timestamp + |
| 411 | msecs_to_jiffies(HSR_NODE_FORGET_TIME))) { | 399 | msecs_to_jiffies(HSR_NODE_FORGET_TIME))) { |
| 412 | hsr_nl_nodedown(hsr_priv, node->MacAddressA); | 400 | hsr_nl_nodedown(hsr, node->MacAddressA); |
| 413 | list_del_rcu(&node->mac_list); | 401 | list_del_rcu(&node->mac_list); |
| 414 | /* Note that we need to free this entry later: */ | 402 | /* Note that we need to free this entry later: */ |
| 415 | kfree_rcu(node, rcu_head); | 403 | kfree_rcu(node, rcu_head); |
| @@ -419,21 +407,21 @@ void hsr_prune_nodes(struct hsr_priv *hsr_priv) | |||
| 419 | } | 407 | } |
| 420 | 408 | ||
| 421 | 409 | ||
| 422 | void *hsr_get_next_node(struct hsr_priv *hsr_priv, void *_pos, | 410 | void *hsr_get_next_node(struct hsr_priv *hsr, void *_pos, |
| 423 | unsigned char addr[ETH_ALEN]) | 411 | unsigned char addr[ETH_ALEN]) |
| 424 | { | 412 | { |
| 425 | struct node_entry *node; | 413 | struct hsr_node *node; |
| 426 | 414 | ||
| 427 | if (!_pos) { | 415 | if (!_pos) { |
| 428 | node = list_first_or_null_rcu(&hsr_priv->node_db, | 416 | node = list_first_or_null_rcu(&hsr->node_db, |
| 429 | struct node_entry, mac_list); | 417 | struct hsr_node, mac_list); |
| 430 | if (node) | 418 | if (node) |
| 431 | ether_addr_copy(addr, node->MacAddressA); | 419 | ether_addr_copy(addr, node->MacAddressA); |
| 432 | return node; | 420 | return node; |
| 433 | } | 421 | } |
| 434 | 422 | ||
| 435 | node = _pos; | 423 | node = _pos; |
| 436 | list_for_each_entry_continue_rcu(node, &hsr_priv->node_db, mac_list) { | 424 | list_for_each_entry_continue_rcu(node, &hsr->node_db, mac_list) { |
| 437 | ether_addr_copy(addr, node->MacAddressA); | 425 | ether_addr_copy(addr, node->MacAddressA); |
| 438 | return node; | 426 | return node; |
| 439 | } | 427 | } |
| @@ -442,7 +430,7 @@ void *hsr_get_next_node(struct hsr_priv *hsr_priv, void *_pos, | |||
| 442 | } | 430 | } |
| 443 | 431 | ||
| 444 | 432 | ||
| 445 | int hsr_get_node_data(struct hsr_priv *hsr_priv, | 433 | int hsr_get_node_data(struct hsr_priv *hsr, |
| 446 | const unsigned char *addr, | 434 | const unsigned char *addr, |
| 447 | unsigned char addr_b[ETH_ALEN], | 435 | unsigned char addr_b[ETH_ALEN], |
| 448 | unsigned int *addr_b_ifindex, | 436 | unsigned int *addr_b_ifindex, |
| @@ -451,12 +439,13 @@ int hsr_get_node_data(struct hsr_priv *hsr_priv, | |||
| 451 | int *if2_age, | 439 | int *if2_age, |
| 452 | u16 *if2_seq) | 440 | u16 *if2_seq) |
| 453 | { | 441 | { |
| 454 | struct node_entry *node; | 442 | struct hsr_node *node; |
| 443 | struct hsr_port *port; | ||
| 455 | unsigned long tdiff; | 444 | unsigned long tdiff; |
| 456 | 445 | ||
| 457 | 446 | ||
| 458 | rcu_read_lock(); | 447 | rcu_read_lock(); |
| 459 | node = find_node_by_AddrA(&hsr_priv->node_db, addr); | 448 | node = find_node_by_AddrA(&hsr->node_db, addr); |
| 460 | if (!node) { | 449 | if (!node) { |
| 461 | rcu_read_unlock(); | 450 | rcu_read_unlock(); |
| 462 | return -ENOENT; /* No such entry */ | 451 | return -ENOENT; /* No such entry */ |
| @@ -464,8 +453,8 @@ int hsr_get_node_data(struct hsr_priv *hsr_priv, | |||
| 464 | 453 | ||
| 465 | ether_addr_copy(addr_b, node->MacAddressB); | 454 | ether_addr_copy(addr_b, node->MacAddressB); |
| 466 | 455 | ||
| 467 | tdiff = jiffies - node->time_in[HSR_DEV_SLAVE_A]; | 456 | tdiff = jiffies - node->time_in[HSR_PT_SLAVE_A]; |
| 468 | if (node->time_in_stale[HSR_DEV_SLAVE_A]) | 457 | if (node->time_in_stale[HSR_PT_SLAVE_A]) |
| 469 | *if1_age = INT_MAX; | 458 | *if1_age = INT_MAX; |
| 470 | #if HZ <= MSEC_PER_SEC | 459 | #if HZ <= MSEC_PER_SEC |
| 471 | else if (tdiff > msecs_to_jiffies(INT_MAX)) | 460 | else if (tdiff > msecs_to_jiffies(INT_MAX)) |
| @@ -474,8 +463,8 @@ int hsr_get_node_data(struct hsr_priv *hsr_priv, | |||
| 474 | else | 463 | else |
| 475 | *if1_age = jiffies_to_msecs(tdiff); | 464 | *if1_age = jiffies_to_msecs(tdiff); |
| 476 | 465 | ||
| 477 | tdiff = jiffies - node->time_in[HSR_DEV_SLAVE_B]; | 466 | tdiff = jiffies - node->time_in[HSR_PT_SLAVE_B]; |
| 478 | if (node->time_in_stale[HSR_DEV_SLAVE_B]) | 467 | if (node->time_in_stale[HSR_PT_SLAVE_B]) |
| 479 | *if2_age = INT_MAX; | 468 | *if2_age = INT_MAX; |
| 480 | #if HZ <= MSEC_PER_SEC | 469 | #if HZ <= MSEC_PER_SEC |
| 481 | else if (tdiff > msecs_to_jiffies(INT_MAX)) | 470 | else if (tdiff > msecs_to_jiffies(INT_MAX)) |
| @@ -485,13 +474,15 @@ int hsr_get_node_data(struct hsr_priv *hsr_priv, | |||
| 485 | *if2_age = jiffies_to_msecs(tdiff); | 474 | *if2_age = jiffies_to_msecs(tdiff); |
| 486 | 475 | ||
| 487 | /* Present sequence numbers as if they were incoming on interface */ | 476 | /* Present sequence numbers as if they were incoming on interface */ |
| 488 | *if1_seq = node->seq_out[HSR_DEV_SLAVE_B]; | 477 | *if1_seq = node->seq_out[HSR_PT_SLAVE_B]; |
| 489 | *if2_seq = node->seq_out[HSR_DEV_SLAVE_A]; | 478 | *if2_seq = node->seq_out[HSR_PT_SLAVE_A]; |
| 490 | 479 | ||
| 491 | if ((node->AddrB_if != HSR_DEV_NONE) && hsr_priv->slave[node->AddrB_if]) | 480 | if (node->AddrB_port != HSR_PT_NONE) { |
| 492 | *addr_b_ifindex = hsr_priv->slave[node->AddrB_if]->ifindex; | 481 | port = hsr_port_get_hsr(hsr, node->AddrB_port); |
| 493 | else | 482 | *addr_b_ifindex = port->dev->ifindex; |
| 483 | } else { | ||
| 494 | *addr_b_ifindex = -1; | 484 | *addr_b_ifindex = -1; |
| 485 | } | ||
| 495 | 486 | ||
| 496 | rcu_read_unlock(); | 487 | rcu_read_unlock(); |
| 497 | 488 | ||
diff --git a/net/hsr/hsr_framereg.h b/net/hsr/hsr_framereg.h index e6c4022030ad..438b40f98f5a 100644 --- a/net/hsr/hsr_framereg.h +++ b/net/hsr/hsr_framereg.h | |||
| @@ -1,4 +1,4 @@ | |||
| 1 | /* Copyright 2011-2013 Autronica Fire and Security AS | 1 | /* Copyright 2011-2014 Autronica Fire and Security AS |
| 2 | * | 2 | * |
| 3 | * This program is free software; you can redistribute it and/or modify it | 3 | * This program is free software; you can redistribute it and/or modify it |
| 4 | * under the terms of the GNU General Public License as published by the Free | 4 | * under the terms of the GNU General Public License as published by the Free |
| @@ -6,42 +6,43 @@ | |||
| 6 | * any later version. | 6 | * any later version. |
| 7 | * | 7 | * |
| 8 | * Author(s): | 8 | * Author(s): |
| 9 | * 2011-2013 Arvid Brodin, arvid.brodin@xdin.com | 9 | * 2011-2014 Arvid Brodin, arvid.brodin@alten.se |
| 10 | */ | 10 | */ |
| 11 | 11 | ||
| 12 | #ifndef _HSR_FRAMEREG_H | 12 | #ifndef __HSR_FRAMEREG_H |
| 13 | #define _HSR_FRAMEREG_H | 13 | #define __HSR_FRAMEREG_H |
| 14 | 14 | ||
| 15 | #include "hsr_main.h" | 15 | #include "hsr_main.h" |
| 16 | 16 | ||
| 17 | struct node_entry; | 17 | struct hsr_node; |
| 18 | 18 | ||
| 19 | struct node_entry *hsr_find_node(struct list_head *node_db, struct sk_buff *skb); | 19 | struct hsr_node *hsr_add_node(struct list_head *node_db, unsigned char addr[], |
| 20 | u16 seq_out); | ||
| 21 | struct hsr_node *hsr_get_node(struct list_head *node_db, struct sk_buff *skb, | ||
| 22 | bool is_sup); | ||
| 23 | void hsr_handle_sup_frame(struct sk_buff *skb, struct hsr_node *node_curr, | ||
| 24 | struct hsr_port *port); | ||
| 25 | bool hsr_addr_is_self(struct hsr_priv *hsr, unsigned char *addr); | ||
| 20 | 26 | ||
| 21 | struct node_entry *hsr_merge_node(struct hsr_priv *hsr_priv, | 27 | void hsr_addr_subst_source(struct hsr_node *node, struct sk_buff *skb); |
| 22 | struct node_entry *node, | 28 | void hsr_addr_subst_dest(struct hsr_node *node_src, struct sk_buff *skb, |
| 23 | struct sk_buff *skb, | 29 | struct hsr_port *port); |
| 24 | enum hsr_dev_idx dev_idx); | ||
| 25 | 30 | ||
| 26 | void hsr_addr_subst_source(struct hsr_priv *hsr_priv, struct sk_buff *skb); | 31 | void hsr_register_frame_in(struct hsr_node *node, struct hsr_port *port, |
| 27 | void hsr_addr_subst_dest(struct hsr_priv *hsr_priv, struct ethhdr *ethhdr, | 32 | u16 sequence_nr); |
| 28 | enum hsr_dev_idx dev_idx); | 33 | int hsr_register_frame_out(struct hsr_port *port, struct hsr_node *node, |
| 34 | u16 sequence_nr); | ||
| 29 | 35 | ||
| 30 | void hsr_register_frame_in(struct node_entry *node, enum hsr_dev_idx dev_idx); | 36 | void hsr_prune_nodes(unsigned long data); |
| 31 | |||
| 32 | int hsr_register_frame_out(struct node_entry *node, enum hsr_dev_idx dev_idx, | ||
| 33 | struct sk_buff *skb); | ||
| 34 | |||
| 35 | void hsr_prune_nodes(struct hsr_priv *hsr_priv); | ||
| 36 | 37 | ||
| 37 | int hsr_create_self_node(struct list_head *self_node_db, | 38 | int hsr_create_self_node(struct list_head *self_node_db, |
| 38 | unsigned char addr_a[ETH_ALEN], | 39 | unsigned char addr_a[ETH_ALEN], |
| 39 | unsigned char addr_b[ETH_ALEN]); | 40 | unsigned char addr_b[ETH_ALEN]); |
| 40 | 41 | ||
| 41 | void *hsr_get_next_node(struct hsr_priv *hsr_priv, void *_pos, | 42 | void *hsr_get_next_node(struct hsr_priv *hsr, void *_pos, |
| 42 | unsigned char addr[ETH_ALEN]); | 43 | unsigned char addr[ETH_ALEN]); |
| 43 | 44 | ||
| 44 | int hsr_get_node_data(struct hsr_priv *hsr_priv, | 45 | int hsr_get_node_data(struct hsr_priv *hsr, |
| 45 | const unsigned char *addr, | 46 | const unsigned char *addr, |
| 46 | unsigned char addr_b[ETH_ALEN], | 47 | unsigned char addr_b[ETH_ALEN], |
| 47 | unsigned int *addr_b_ifindex, | 48 | unsigned int *addr_b_ifindex, |
| @@ -50,4 +51,4 @@ int hsr_get_node_data(struct hsr_priv *hsr_priv, | |||
| 50 | int *if2_age, | 51 | int *if2_age, |
| 51 | u16 *if2_seq); | 52 | u16 *if2_seq); |
| 52 | 53 | ||
| 53 | #endif /* _HSR_FRAMEREG_H */ | 54 | #endif /* __HSR_FRAMEREG_H */ |
diff --git a/net/hsr/hsr_main.c b/net/hsr/hsr_main.c index 3fee5218a691..779d28b65417 100644 --- a/net/hsr/hsr_main.c +++ b/net/hsr/hsr_main.c | |||
| @@ -1,4 +1,4 @@ | |||
| 1 | /* Copyright 2011-2013 Autronica Fire and Security AS | 1 | /* Copyright 2011-2014 Autronica Fire and Security AS |
| 2 | * | 2 | * |
| 3 | * This program is free software; you can redistribute it and/or modify it | 3 | * This program is free software; you can redistribute it and/or modify it |
| 4 | * under the terms of the GNU General Public License as published by the Free | 4 | * under the terms of the GNU General Public License as published by the Free |
| @@ -6,11 +6,7 @@ | |||
| 6 | * any later version. | 6 | * any later version. |
| 7 | * | 7 | * |
| 8 | * Author(s): | 8 | * Author(s): |
| 9 | * 2011-2013 Arvid Brodin, arvid.brodin@xdin.com | 9 | * 2011-2014 Arvid Brodin, arvid.brodin@alten.se |
| 10 | * | ||
| 11 | * In addition to routines for registering and unregistering HSR support, this | ||
| 12 | * file also contains the receive routine that handles all incoming frames with | ||
| 13 | * Ethertype (protocol) ETH_P_PRP (HSRv0), and network device event handling. | ||
| 14 | */ | 10 | */ |
| 15 | 11 | ||
| 16 | #include <linux/netdevice.h> | 12 | #include <linux/netdevice.h> |
| @@ -21,154 +17,71 @@ | |||
| 21 | #include "hsr_device.h" | 17 | #include "hsr_device.h" |
| 22 | #include "hsr_netlink.h" | 18 | #include "hsr_netlink.h" |
| 23 | #include "hsr_framereg.h" | 19 | #include "hsr_framereg.h" |
| 24 | 20 | #include "hsr_slave.h" | |
| 25 | |||
| 26 | /* List of all registered virtual HSR devices */ | ||
| 27 | static LIST_HEAD(hsr_list); | ||
| 28 | |||
| 29 | void register_hsr_master(struct hsr_priv *hsr_priv) | ||
| 30 | { | ||
| 31 | list_add_tail_rcu(&hsr_priv->hsr_list, &hsr_list); | ||
| 32 | } | ||
| 33 | |||
| 34 | void unregister_hsr_master(struct hsr_priv *hsr_priv) | ||
| 35 | { | ||
| 36 | struct hsr_priv *hsr_priv_it; | ||
| 37 | |||
| 38 | list_for_each_entry(hsr_priv_it, &hsr_list, hsr_list) | ||
| 39 | if (hsr_priv_it == hsr_priv) { | ||
| 40 | list_del_rcu(&hsr_priv_it->hsr_list); | ||
| 41 | return; | ||
| 42 | } | ||
| 43 | } | ||
| 44 | |||
| 45 | bool is_hsr_slave(struct net_device *dev) | ||
| 46 | { | ||
| 47 | struct hsr_priv *hsr_priv_it; | ||
| 48 | |||
| 49 | list_for_each_entry_rcu(hsr_priv_it, &hsr_list, hsr_list) { | ||
| 50 | if (dev == hsr_priv_it->slave[0]) | ||
| 51 | return true; | ||
| 52 | if (dev == hsr_priv_it->slave[1]) | ||
| 53 | return true; | ||
| 54 | } | ||
| 55 | |||
| 56 | return false; | ||
| 57 | } | ||
| 58 | |||
| 59 | |||
| 60 | /* If dev is a HSR slave device, return the virtual master device. Return NULL | ||
| 61 | * otherwise. | ||
| 62 | */ | ||
| 63 | static struct hsr_priv *get_hsr_master(struct net_device *dev) | ||
| 64 | { | ||
| 65 | struct hsr_priv *hsr_priv; | ||
| 66 | |||
| 67 | rcu_read_lock(); | ||
| 68 | list_for_each_entry_rcu(hsr_priv, &hsr_list, hsr_list) | ||
| 69 | if ((dev == hsr_priv->slave[0]) || | ||
| 70 | (dev == hsr_priv->slave[1])) { | ||
| 71 | rcu_read_unlock(); | ||
| 72 | return hsr_priv; | ||
| 73 | } | ||
| 74 | |||
| 75 | rcu_read_unlock(); | ||
| 76 | return NULL; | ||
| 77 | } | ||
| 78 | |||
| 79 | |||
| 80 | /* If dev is a HSR slave device, return the other slave device. Return NULL | ||
| 81 | * otherwise. | ||
| 82 | */ | ||
| 83 | static struct net_device *get_other_slave(struct hsr_priv *hsr_priv, | ||
| 84 | struct net_device *dev) | ||
| 85 | { | ||
| 86 | if (dev == hsr_priv->slave[0]) | ||
| 87 | return hsr_priv->slave[1]; | ||
| 88 | if (dev == hsr_priv->slave[1]) | ||
| 89 | return hsr_priv->slave[0]; | ||
| 90 | |||
| 91 | return NULL; | ||
| 92 | } | ||
| 93 | 21 | ||
| 94 | 22 | ||
| 95 | static int hsr_netdev_notify(struct notifier_block *nb, unsigned long event, | 23 | static int hsr_netdev_notify(struct notifier_block *nb, unsigned long event, |
| 96 | void *ptr) | 24 | void *ptr) |
| 97 | { | 25 | { |
| 98 | struct net_device *slave, *other_slave; | 26 | struct net_device *dev; |
| 99 | struct hsr_priv *hsr_priv; | 27 | struct hsr_port *port, *master; |
| 100 | int old_operstate; | 28 | struct hsr_priv *hsr; |
| 101 | int mtu_max; | 29 | int mtu_max; |
| 102 | int res; | 30 | int res; |
| 103 | struct net_device *dev; | ||
| 104 | 31 | ||
| 105 | dev = netdev_notifier_info_to_dev(ptr); | 32 | dev = netdev_notifier_info_to_dev(ptr); |
| 106 | 33 | port = hsr_port_get_rtnl(dev); | |
| 107 | hsr_priv = get_hsr_master(dev); | 34 | if (port == NULL) { |
| 108 | if (hsr_priv) { | ||
| 109 | /* dev is a slave device */ | ||
| 110 | slave = dev; | ||
| 111 | other_slave = get_other_slave(hsr_priv, slave); | ||
| 112 | } else { | ||
| 113 | if (!is_hsr_master(dev)) | 35 | if (!is_hsr_master(dev)) |
| 114 | return NOTIFY_DONE; | 36 | return NOTIFY_DONE; /* Not an HSR device */ |
| 115 | hsr_priv = netdev_priv(dev); | 37 | hsr = netdev_priv(dev); |
| 116 | slave = hsr_priv->slave[0]; | 38 | port = hsr_port_get_hsr(hsr, HSR_PT_MASTER); |
| 117 | other_slave = hsr_priv->slave[1]; | 39 | } else { |
| 40 | hsr = port->hsr; | ||
| 118 | } | 41 | } |
| 119 | 42 | ||
| 120 | switch (event) { | 43 | switch (event) { |
| 121 | case NETDEV_UP: /* Administrative state DOWN */ | 44 | case NETDEV_UP: /* Administrative state DOWN */ |
| 122 | case NETDEV_DOWN: /* Administrative state UP */ | 45 | case NETDEV_DOWN: /* Administrative state UP */ |
| 123 | case NETDEV_CHANGE: /* Link (carrier) state changes */ | 46 | case NETDEV_CHANGE: /* Link (carrier) state changes */ |
| 124 | old_operstate = hsr_priv->dev->operstate; | 47 | hsr_check_carrier_and_operstate(hsr); |
| 125 | hsr_set_carrier(hsr_priv->dev, slave, other_slave); | ||
| 126 | /* netif_stacked_transfer_operstate() cannot be used here since | ||
| 127 | * it doesn't set IF_OPER_LOWERLAYERDOWN (?) | ||
| 128 | */ | ||
| 129 | hsr_set_operstate(hsr_priv->dev, slave, other_slave); | ||
| 130 | hsr_check_announce(hsr_priv->dev, old_operstate); | ||
| 131 | break; | 48 | break; |
| 132 | case NETDEV_CHANGEADDR: | 49 | case NETDEV_CHANGEADDR: |
| 133 | 50 | if (port->type == HSR_PT_MASTER) { | |
| 134 | /* This should not happen since there's no ndo_set_mac_address() | 51 | /* This should not happen since there's no |
| 135 | * for HSR devices - i.e. not supported. | 52 | * ndo_set_mac_address() for HSR devices - i.e. not |
| 136 | */ | 53 | * supported. |
| 137 | if (dev == hsr_priv->dev) | 54 | */ |
| 138 | break; | 55 | break; |
| 56 | } | ||
| 139 | 57 | ||
| 140 | if (dev == hsr_priv->slave[0]) | 58 | master = hsr_port_get_hsr(hsr, HSR_PT_MASTER); |
| 141 | ether_addr_copy(hsr_priv->dev->dev_addr, | 59 | |
| 142 | hsr_priv->slave[0]->dev_addr); | 60 | if (port->type == HSR_PT_SLAVE_A) { |
| 61 | ether_addr_copy(master->dev->dev_addr, dev->dev_addr); | ||
| 62 | call_netdevice_notifiers(NETDEV_CHANGEADDR, master->dev); | ||
| 63 | } | ||
| 143 | 64 | ||
| 144 | /* Make sure we recognize frames from ourselves in hsr_rcv() */ | 65 | /* Make sure we recognize frames from ourselves in hsr_rcv() */ |
| 145 | res = hsr_create_self_node(&hsr_priv->self_node_db, | 66 | port = hsr_port_get_hsr(hsr, HSR_PT_SLAVE_B); |
| 146 | hsr_priv->dev->dev_addr, | 67 | res = hsr_create_self_node(&hsr->self_node_db, |
| 147 | hsr_priv->slave[1] ? | 68 | master->dev->dev_addr, |
| 148 | hsr_priv->slave[1]->dev_addr : | 69 | port ? |
| 149 | hsr_priv->dev->dev_addr); | 70 | port->dev->dev_addr : |
| 71 | master->dev->dev_addr); | ||
| 150 | if (res) | 72 | if (res) |
| 151 | netdev_warn(hsr_priv->dev, | 73 | netdev_warn(master->dev, |
| 152 | "Could not update HSR node address.\n"); | 74 | "Could not update HSR node address.\n"); |
| 153 | |||
| 154 | if (dev == hsr_priv->slave[0]) | ||
| 155 | call_netdevice_notifiers(NETDEV_CHANGEADDR, hsr_priv->dev); | ||
| 156 | break; | 75 | break; |
| 157 | case NETDEV_CHANGEMTU: | 76 | case NETDEV_CHANGEMTU: |
| 158 | if (dev == hsr_priv->dev) | 77 | if (port->type == HSR_PT_MASTER) |
| 159 | break; /* Handled in ndo_change_mtu() */ | 78 | break; /* Handled in ndo_change_mtu() */ |
| 160 | mtu_max = hsr_get_max_mtu(hsr_priv); | 79 | mtu_max = hsr_get_max_mtu(port->hsr); |
| 161 | if (hsr_priv->dev->mtu > mtu_max) | 80 | master = hsr_port_get_hsr(port->hsr, HSR_PT_MASTER); |
| 162 | dev_set_mtu(hsr_priv->dev, mtu_max); | 81 | master->dev->mtu = mtu_max; |
| 163 | break; | 82 | break; |
| 164 | case NETDEV_UNREGISTER: | 83 | case NETDEV_UNREGISTER: |
| 165 | if (dev == hsr_priv->slave[0]) | 84 | hsr_del_port(port); |
| 166 | hsr_priv->slave[0] = NULL; | ||
| 167 | if (dev == hsr_priv->slave[1]) | ||
| 168 | hsr_priv->slave[1] = NULL; | ||
| 169 | |||
| 170 | /* There should really be a way to set a new slave device... */ | ||
| 171 | |||
| 172 | break; | 85 | break; |
| 173 | case NETDEV_PRE_TYPE_CHANGE: | 86 | case NETDEV_PRE_TYPE_CHANGE: |
| 174 | /* HSR works only on Ethernet devices. Refuse slave to change | 87 | /* HSR works only on Ethernet devices. Refuse slave to change |
| @@ -181,255 +94,16 @@ static int hsr_netdev_notify(struct notifier_block *nb, unsigned long event, | |||
| 181 | } | 94 | } |
| 182 | 95 | ||
| 183 | 96 | ||
| 184 | static struct timer_list prune_timer; | 97 | struct hsr_port *hsr_port_get_hsr(struct hsr_priv *hsr, enum hsr_port_type pt) |
| 185 | |||
| 186 | static void prune_nodes_all(unsigned long data) | ||
| 187 | { | ||
| 188 | struct hsr_priv *hsr_priv; | ||
| 189 | |||
| 190 | rcu_read_lock(); | ||
| 191 | list_for_each_entry_rcu(hsr_priv, &hsr_list, hsr_list) | ||
| 192 | hsr_prune_nodes(hsr_priv); | ||
| 193 | rcu_read_unlock(); | ||
| 194 | |||
| 195 | prune_timer.expires = jiffies + msecs_to_jiffies(PRUNE_PERIOD); | ||
| 196 | add_timer(&prune_timer); | ||
| 197 | } | ||
| 198 | |||
| 199 | |||
| 200 | static struct sk_buff *hsr_pull_tag(struct sk_buff *skb) | ||
| 201 | { | 98 | { |
| 202 | struct hsr_tag *hsr_tag; | 99 | struct hsr_port *port; |
| 203 | struct sk_buff *skb2; | ||
| 204 | |||
| 205 | skb2 = skb_share_check(skb, GFP_ATOMIC); | ||
| 206 | if (unlikely(!skb2)) | ||
| 207 | goto err_free; | ||
| 208 | skb = skb2; | ||
| 209 | |||
| 210 | if (unlikely(!pskb_may_pull(skb, HSR_TAGLEN))) | ||
| 211 | goto err_free; | ||
| 212 | 100 | ||
| 213 | hsr_tag = (struct hsr_tag *) skb->data; | 101 | hsr_for_each_port(hsr, port) |
| 214 | skb->protocol = hsr_tag->encap_proto; | 102 | if (port->type == pt) |
| 215 | skb_pull(skb, HSR_TAGLEN); | 103 | return port; |
| 216 | |||
| 217 | return skb; | ||
| 218 | |||
| 219 | err_free: | ||
| 220 | kfree_skb(skb); | ||
| 221 | return NULL; | 104 | return NULL; |
| 222 | } | 105 | } |
| 223 | 106 | ||
| 224 | |||
| 225 | /* The uses I can see for these HSR supervision frames are: | ||
| 226 | * 1) Use the frames that are sent after node initialization ("HSR_TLV.Type = | ||
| 227 | * 22") to reset any sequence_nr counters belonging to that node. Useful if | ||
| 228 | * the other node's counter has been reset for some reason. | ||
| 229 | * -- | ||
| 230 | * Or not - resetting the counter and bridging the frame would create a | ||
| 231 | * loop, unfortunately. | ||
| 232 | * | ||
| 233 | * 2) Use the LifeCheck frames to detect ring breaks. I.e. if no LifeCheck | ||
| 234 | * frame is received from a particular node, we know something is wrong. | ||
| 235 | * We just register these (as with normal frames) and throw them away. | ||
| 236 | * | ||
| 237 | * 3) Allow different MAC addresses for the two slave interfaces, using the | ||
| 238 | * MacAddressA field. | ||
| 239 | */ | ||
| 240 | static bool is_supervision_frame(struct hsr_priv *hsr_priv, struct sk_buff *skb) | ||
| 241 | { | ||
| 242 | struct hsr_sup_tag *hsr_stag; | ||
| 243 | |||
| 244 | if (!ether_addr_equal(eth_hdr(skb)->h_dest, | ||
| 245 | hsr_priv->sup_multicast_addr)) | ||
| 246 | return false; | ||
| 247 | |||
| 248 | hsr_stag = (struct hsr_sup_tag *) skb->data; | ||
| 249 | if (get_hsr_stag_path(hsr_stag) != 0x0f) | ||
| 250 | return false; | ||
| 251 | if ((hsr_stag->HSR_TLV_Type != HSR_TLV_ANNOUNCE) && | ||
| 252 | (hsr_stag->HSR_TLV_Type != HSR_TLV_LIFE_CHECK)) | ||
| 253 | return false; | ||
| 254 | if (hsr_stag->HSR_TLV_Length != 12) | ||
| 255 | return false; | ||
| 256 | |||
| 257 | return true; | ||
| 258 | } | ||
| 259 | |||
| 260 | |||
| 261 | /* Implementation somewhat according to IEC-62439-3, p. 43 | ||
| 262 | */ | ||
| 263 | static int hsr_rcv(struct sk_buff *skb, struct net_device *dev, | ||
| 264 | struct packet_type *pt, struct net_device *orig_dev) | ||
| 265 | { | ||
| 266 | struct hsr_priv *hsr_priv; | ||
| 267 | struct net_device *other_slave; | ||
| 268 | struct node_entry *node; | ||
| 269 | bool deliver_to_self; | ||
| 270 | struct sk_buff *skb_deliver; | ||
| 271 | enum hsr_dev_idx dev_in_idx, dev_other_idx; | ||
| 272 | bool dup_out; | ||
| 273 | int ret; | ||
| 274 | |||
| 275 | hsr_priv = get_hsr_master(dev); | ||
| 276 | |||
| 277 | if (!hsr_priv) { | ||
| 278 | /* Non-HSR-slave device 'dev' is connected to a HSR network */ | ||
| 279 | kfree_skb(skb); | ||
| 280 | dev->stats.rx_errors++; | ||
| 281 | return NET_RX_SUCCESS; | ||
| 282 | } | ||
| 283 | |||
| 284 | if (dev == hsr_priv->slave[0]) { | ||
| 285 | dev_in_idx = HSR_DEV_SLAVE_A; | ||
| 286 | dev_other_idx = HSR_DEV_SLAVE_B; | ||
| 287 | } else { | ||
| 288 | dev_in_idx = HSR_DEV_SLAVE_B; | ||
| 289 | dev_other_idx = HSR_DEV_SLAVE_A; | ||
| 290 | } | ||
| 291 | |||
| 292 | node = hsr_find_node(&hsr_priv->self_node_db, skb); | ||
| 293 | if (node) { | ||
| 294 | /* Always kill frames sent by ourselves */ | ||
| 295 | kfree_skb(skb); | ||
| 296 | return NET_RX_SUCCESS; | ||
| 297 | } | ||
| 298 | |||
| 299 | /* Is this frame a candidate for local reception? */ | ||
| 300 | deliver_to_self = false; | ||
| 301 | if ((skb->pkt_type == PACKET_HOST) || | ||
| 302 | (skb->pkt_type == PACKET_MULTICAST) || | ||
| 303 | (skb->pkt_type == PACKET_BROADCAST)) | ||
| 304 | deliver_to_self = true; | ||
| 305 | else if (ether_addr_equal(eth_hdr(skb)->h_dest, | ||
| 306 | hsr_priv->dev->dev_addr)) { | ||
| 307 | skb->pkt_type = PACKET_HOST; | ||
| 308 | deliver_to_self = true; | ||
| 309 | } | ||
| 310 | |||
| 311 | |||
| 312 | rcu_read_lock(); /* node_db */ | ||
| 313 | node = hsr_find_node(&hsr_priv->node_db, skb); | ||
| 314 | |||
| 315 | if (is_supervision_frame(hsr_priv, skb)) { | ||
| 316 | skb_pull(skb, sizeof(struct hsr_sup_tag)); | ||
| 317 | node = hsr_merge_node(hsr_priv, node, skb, dev_in_idx); | ||
| 318 | if (!node) { | ||
| 319 | rcu_read_unlock(); /* node_db */ | ||
| 320 | kfree_skb(skb); | ||
| 321 | hsr_priv->dev->stats.rx_dropped++; | ||
| 322 | return NET_RX_DROP; | ||
| 323 | } | ||
| 324 | skb_push(skb, sizeof(struct hsr_sup_tag)); | ||
| 325 | deliver_to_self = false; | ||
| 326 | } | ||
| 327 | |||
| 328 | if (!node) { | ||
| 329 | /* Source node unknown; this might be a HSR frame from | ||
| 330 | * another net (different multicast address). Ignore it. | ||
| 331 | */ | ||
| 332 | rcu_read_unlock(); /* node_db */ | ||
| 333 | kfree_skb(skb); | ||
| 334 | return NET_RX_SUCCESS; | ||
| 335 | } | ||
| 336 | |||
| 337 | /* Register ALL incoming frames as outgoing through the other interface. | ||
| 338 | * This allows us to register frames as incoming only if they are valid | ||
| 339 | * for the receiving interface, without using a specific counter for | ||
| 340 | * incoming frames. | ||
| 341 | */ | ||
| 342 | dup_out = hsr_register_frame_out(node, dev_other_idx, skb); | ||
| 343 | if (!dup_out) | ||
| 344 | hsr_register_frame_in(node, dev_in_idx); | ||
| 345 | |||
| 346 | /* Forward this frame? */ | ||
| 347 | if (!dup_out && (skb->pkt_type != PACKET_HOST)) | ||
| 348 | other_slave = get_other_slave(hsr_priv, dev); | ||
| 349 | else | ||
| 350 | other_slave = NULL; | ||
| 351 | |||
| 352 | if (hsr_register_frame_out(node, HSR_DEV_MASTER, skb)) | ||
| 353 | deliver_to_self = false; | ||
| 354 | |||
| 355 | rcu_read_unlock(); /* node_db */ | ||
| 356 | |||
| 357 | if (!deliver_to_self && !other_slave) { | ||
| 358 | kfree_skb(skb); | ||
| 359 | /* Circulated frame; silently remove it. */ | ||
| 360 | return NET_RX_SUCCESS; | ||
| 361 | } | ||
| 362 | |||
| 363 | skb_deliver = skb; | ||
| 364 | if (deliver_to_self && other_slave) { | ||
| 365 | /* skb_clone() is not enough since we will strip the hsr tag | ||
| 366 | * and do address substitution below | ||
| 367 | */ | ||
| 368 | skb_deliver = pskb_copy(skb, GFP_ATOMIC); | ||
| 369 | if (!skb_deliver) { | ||
| 370 | deliver_to_self = false; | ||
| 371 | hsr_priv->dev->stats.rx_dropped++; | ||
| 372 | } | ||
| 373 | } | ||
| 374 | |||
| 375 | if (deliver_to_self) { | ||
| 376 | bool multicast_frame; | ||
| 377 | |||
| 378 | skb_deliver = hsr_pull_tag(skb_deliver); | ||
| 379 | if (!skb_deliver) { | ||
| 380 | hsr_priv->dev->stats.rx_dropped++; | ||
| 381 | goto forward; | ||
| 382 | } | ||
| 383 | #if !defined(CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS) | ||
| 384 | /* Move everything in the header that is after the HSR tag, | ||
| 385 | * to work around alignment problems caused by the 6-byte HSR | ||
| 386 | * tag. In practice, this removes/overwrites the HSR tag in | ||
| 387 | * the header and restores a "standard" packet. | ||
| 388 | */ | ||
| 389 | memmove(skb_deliver->data - HSR_TAGLEN, skb_deliver->data, | ||
| 390 | skb_headlen(skb_deliver)); | ||
| 391 | |||
| 392 | /* Adjust skb members so they correspond with the move above. | ||
| 393 | * This cannot possibly underflow skb->data since hsr_pull_tag() | ||
| 394 | * above succeeded. | ||
| 395 | * At this point in the protocol stack, the transport and | ||
| 396 | * network headers have not been set yet, and we haven't touched | ||
| 397 | * the mac header nor the head. So we only need to adjust data | ||
| 398 | * and tail: | ||
| 399 | */ | ||
| 400 | skb_deliver->data -= HSR_TAGLEN; | ||
| 401 | skb_deliver->tail -= HSR_TAGLEN; | ||
| 402 | #endif | ||
| 403 | skb_deliver->dev = hsr_priv->dev; | ||
| 404 | hsr_addr_subst_source(hsr_priv, skb_deliver); | ||
| 405 | multicast_frame = (skb_deliver->pkt_type == PACKET_MULTICAST); | ||
| 406 | ret = netif_rx(skb_deliver); | ||
| 407 | if (ret == NET_RX_DROP) { | ||
| 408 | hsr_priv->dev->stats.rx_dropped++; | ||
| 409 | } else { | ||
| 410 | hsr_priv->dev->stats.rx_packets++; | ||
| 411 | hsr_priv->dev->stats.rx_bytes += skb->len; | ||
| 412 | if (multicast_frame) | ||
| 413 | hsr_priv->dev->stats.multicast++; | ||
| 414 | } | ||
| 415 | } | ||
| 416 | |||
| 417 | forward: | ||
| 418 | if (other_slave) { | ||
| 419 | skb_push(skb, ETH_HLEN); | ||
| 420 | skb->dev = other_slave; | ||
| 421 | dev_queue_xmit(skb); | ||
| 422 | } | ||
| 423 | |||
| 424 | return NET_RX_SUCCESS; | ||
| 425 | } | ||
| 426 | |||
| 427 | |||
| 428 | static struct packet_type hsr_pt __read_mostly = { | ||
| 429 | .type = htons(ETH_P_PRP), | ||
| 430 | .func = hsr_rcv, | ||
| 431 | }; | ||
| 432 | |||
| 433 | static struct notifier_block hsr_nb = { | 107 | static struct notifier_block hsr_nb = { |
| 434 | .notifier_call = hsr_netdev_notify, /* Slave event notifications */ | 108 | .notifier_call = hsr_netdev_notify, /* Slave event notifications */ |
| 435 | }; | 109 | }; |
| @@ -439,18 +113,9 @@ static int __init hsr_init(void) | |||
| 439 | { | 113 | { |
| 440 | int res; | 114 | int res; |
| 441 | 115 | ||
| 442 | BUILD_BUG_ON(sizeof(struct hsr_tag) != HSR_TAGLEN); | 116 | BUILD_BUG_ON(sizeof(struct hsr_tag) != HSR_HLEN); |
| 443 | |||
| 444 | dev_add_pack(&hsr_pt); | ||
| 445 | |||
| 446 | init_timer(&prune_timer); | ||
| 447 | prune_timer.function = prune_nodes_all; | ||
| 448 | prune_timer.data = 0; | ||
| 449 | prune_timer.expires = jiffies + msecs_to_jiffies(PRUNE_PERIOD); | ||
| 450 | add_timer(&prune_timer); | ||
| 451 | 117 | ||
| 452 | register_netdevice_notifier(&hsr_nb); | 118 | register_netdevice_notifier(&hsr_nb); |
| 453 | |||
| 454 | res = hsr_netlink_init(); | 119 | res = hsr_netlink_init(); |
| 455 | 120 | ||
| 456 | return res; | 121 | return res; |
| @@ -459,9 +124,7 @@ static int __init hsr_init(void) | |||
| 459 | static void __exit hsr_exit(void) | 124 | static void __exit hsr_exit(void) |
| 460 | { | 125 | { |
| 461 | unregister_netdevice_notifier(&hsr_nb); | 126 | unregister_netdevice_notifier(&hsr_nb); |
| 462 | del_timer_sync(&prune_timer); | ||
| 463 | hsr_netlink_exit(); | 127 | hsr_netlink_exit(); |
| 464 | dev_remove_pack(&hsr_pt); | ||
| 465 | } | 128 | } |
| 466 | 129 | ||
| 467 | module_init(hsr_init); | 130 | module_init(hsr_init); |
diff --git a/net/hsr/hsr_main.h b/net/hsr/hsr_main.h index 56fe060c0ab1..5a9c69962ded 100644 --- a/net/hsr/hsr_main.h +++ b/net/hsr/hsr_main.h | |||
| @@ -1,4 +1,4 @@ | |||
| 1 | /* Copyright 2011-2013 Autronica Fire and Security AS | 1 | /* Copyright 2011-2014 Autronica Fire and Security AS |
| 2 | * | 2 | * |
| 3 | * This program is free software; you can redistribute it and/or modify it | 3 | * This program is free software; you can redistribute it and/or modify it |
| 4 | * under the terms of the GNU General Public License as published by the Free | 4 | * under the terms of the GNU General Public License as published by the Free |
| @@ -6,11 +6,11 @@ | |||
| 6 | * any later version. | 6 | * any later version. |
| 7 | * | 7 | * |
| 8 | * Author(s): | 8 | * Author(s): |
| 9 | * 2011-2013 Arvid Brodin, arvid.brodin@xdin.com | 9 | * 2011-2014 Arvid Brodin, arvid.brodin@alten.se |
| 10 | */ | 10 | */ |
| 11 | 11 | ||
| 12 | #ifndef _HSR_PRIVATE_H | 12 | #ifndef __HSR_PRIVATE_H |
| 13 | #define _HSR_PRIVATE_H | 13 | #define __HSR_PRIVATE_H |
| 14 | 14 | ||
| 15 | #include <linux/netdevice.h> | 15 | #include <linux/netdevice.h> |
| 16 | #include <linux/list.h> | 16 | #include <linux/list.h> |
| @@ -29,6 +29,7 @@ | |||
| 29 | * each node differ before we notify of communication problem? | 29 | * each node differ before we notify of communication problem? |
| 30 | */ | 30 | */ |
| 31 | #define MAX_SLAVE_DIFF 3000 /* ms */ | 31 | #define MAX_SLAVE_DIFF 3000 /* ms */ |
| 32 | #define HSR_SEQNR_START (USHRT_MAX - 1024) | ||
| 32 | 33 | ||
| 33 | 34 | ||
| 34 | /* How often shall we check for broken ring and remove node entries older than | 35 | /* How often shall we check for broken ring and remove node entries older than |
| @@ -46,16 +47,16 @@ | |||
| 46 | * path, LSDU_size, sequence Nr }. But we let eth_header() create { h_dest, | 47 | * path, LSDU_size, sequence Nr }. But we let eth_header() create { h_dest, |
| 47 | * h_source, h_proto = 0x88FB }, and add { path, LSDU_size, sequence Nr, | 48 | * h_source, h_proto = 0x88FB }, and add { path, LSDU_size, sequence Nr, |
| 48 | * encapsulated protocol } instead. | 49 | * encapsulated protocol } instead. |
| 50 | * | ||
| 51 | * Field names as defined in the IEC:2010 standard for HSR. | ||
| 49 | */ | 52 | */ |
| 50 | #define HSR_TAGLEN 6 | ||
| 51 | |||
| 52 | /* Field names below as defined in the IEC:2010 standard for HSR. */ | ||
| 53 | struct hsr_tag { | 53 | struct hsr_tag { |
| 54 | __be16 path_and_LSDU_size; | 54 | __be16 path_and_LSDU_size; |
| 55 | __be16 sequence_nr; | 55 | __be16 sequence_nr; |
| 56 | __be16 encap_proto; | 56 | __be16 encap_proto; |
| 57 | } __packed; | 57 | } __packed; |
| 58 | 58 | ||
| 59 | #define HSR_HLEN 6 | ||
| 59 | 60 | ||
| 60 | /* The helper functions below assumes that 'path' occupies the 4 most | 61 | /* The helper functions below assumes that 'path' occupies the 4 most |
| 61 | * significant bits of the 16-bit field shared by 'path' and 'LSDU_size' (or | 62 | * significant bits of the 16-bit field shared by 'path' and 'LSDU_size' (or |
| @@ -136,31 +137,47 @@ struct hsr_ethhdr_sp { | |||
| 136 | } __packed; | 137 | } __packed; |
| 137 | 138 | ||
| 138 | 139 | ||
| 139 | enum hsr_dev_idx { | 140 | enum hsr_port_type { |
| 140 | HSR_DEV_NONE = -1, | 141 | HSR_PT_NONE = 0, /* Must be 0, used by framereg */ |
| 141 | HSR_DEV_SLAVE_A = 0, | 142 | HSR_PT_SLAVE_A, |
| 142 | HSR_DEV_SLAVE_B, | 143 | HSR_PT_SLAVE_B, |
| 143 | HSR_DEV_MASTER, | 144 | HSR_PT_INTERLINK, |
| 145 | HSR_PT_MASTER, | ||
| 146 | HSR_PT_PORTS, /* This must be the last item in the enum */ | ||
| 147 | }; | ||
| 148 | |||
| 149 | struct hsr_port { | ||
| 150 | struct list_head port_list; | ||
| 151 | struct net_device *dev; | ||
| 152 | struct hsr_priv *hsr; | ||
| 153 | enum hsr_port_type type; | ||
| 144 | }; | 154 | }; |
| 145 | #define HSR_MAX_SLAVE (HSR_DEV_SLAVE_B + 1) | ||
| 146 | #define HSR_MAX_DEV (HSR_DEV_MASTER + 1) | ||
| 147 | 155 | ||
| 148 | struct hsr_priv { | 156 | struct hsr_priv { |
| 149 | struct list_head hsr_list; /* List of hsr devices */ | ||
| 150 | struct rcu_head rcu_head; | 157 | struct rcu_head rcu_head; |
| 151 | struct net_device *dev; | 158 | struct list_head ports; |
| 152 | struct net_device *slave[HSR_MAX_SLAVE]; | 159 | struct list_head node_db; /* Known HSR nodes */ |
| 153 | struct list_head node_db; /* Other HSR nodes */ | ||
| 154 | struct list_head self_node_db; /* MACs of slaves */ | 160 | struct list_head self_node_db; /* MACs of slaves */ |
| 155 | struct timer_list announce_timer; /* Supervision frame dispatch */ | 161 | struct timer_list announce_timer; /* Supervision frame dispatch */ |
| 162 | struct timer_list prune_timer; | ||
| 156 | int announce_count; | 163 | int announce_count; |
| 157 | u16 sequence_nr; | 164 | u16 sequence_nr; |
| 158 | spinlock_t seqnr_lock; /* locking for sequence_nr */ | 165 | spinlock_t seqnr_lock; /* locking for sequence_nr */ |
| 159 | unsigned char sup_multicast_addr[ETH_ALEN]; | 166 | unsigned char sup_multicast_addr[ETH_ALEN]; |
| 160 | }; | 167 | }; |
| 161 | 168 | ||
| 162 | void register_hsr_master(struct hsr_priv *hsr_priv); | 169 | #define hsr_for_each_port(hsr, port) \ |
| 163 | void unregister_hsr_master(struct hsr_priv *hsr_priv); | 170 | list_for_each_entry_rcu((port), &(hsr)->ports, port_list) |
| 164 | bool is_hsr_slave(struct net_device *dev); | 171 | |
| 172 | struct hsr_port *hsr_port_get_hsr(struct hsr_priv *hsr, enum hsr_port_type pt); | ||
| 173 | |||
| 174 | /* Caller must ensure skb is a valid HSR frame */ | ||
| 175 | static inline u16 hsr_get_skb_sequence_nr(struct sk_buff *skb) | ||
| 176 | { | ||
| 177 | struct hsr_ethhdr *hsr_ethhdr; | ||
| 178 | |||
| 179 | hsr_ethhdr = (struct hsr_ethhdr *) skb_mac_header(skb); | ||
| 180 | return ntohs(hsr_ethhdr->hsr_tag.sequence_nr); | ||
| 181 | } | ||
| 165 | 182 | ||
| 166 | #endif /* _HSR_PRIVATE_H */ | 183 | #endif /* __HSR_PRIVATE_H */ |
diff --git a/net/hsr/hsr_netlink.c b/net/hsr/hsr_netlink.c index 01a5261ac7a5..a2c7e4c0ac1e 100644 --- a/net/hsr/hsr_netlink.c +++ b/net/hsr/hsr_netlink.c | |||
| @@ -1,4 +1,4 @@ | |||
| 1 | /* Copyright 2011-2013 Autronica Fire and Security AS | 1 | /* Copyright 2011-2014 Autronica Fire and Security AS |
| 2 | * | 2 | * |
| 3 | * This program is free software; you can redistribute it and/or modify it | 3 | * This program is free software; you can redistribute it and/or modify it |
| 4 | * under the terms of the GNU General Public License as published by the Free | 4 | * under the terms of the GNU General Public License as published by the Free |
| @@ -6,7 +6,7 @@ | |||
| 6 | * any later version. | 6 | * any later version. |
| 7 | * | 7 | * |
| 8 | * Author(s): | 8 | * Author(s): |
| 9 | * 2011-2013 Arvid Brodin, arvid.brodin@xdin.com | 9 | * 2011-2014 Arvid Brodin, arvid.brodin@alten.se |
| 10 | * | 10 | * |
| 11 | * Routines for handling Netlink messages for HSR. | 11 | * Routines for handling Netlink messages for HSR. |
| 12 | */ | 12 | */ |
| @@ -37,13 +37,17 @@ static int hsr_newlink(struct net *src_net, struct net_device *dev, | |||
| 37 | struct net_device *link[2]; | 37 | struct net_device *link[2]; |
| 38 | unsigned char multicast_spec; | 38 | unsigned char multicast_spec; |
| 39 | 39 | ||
| 40 | if (!data) { | ||
| 41 | netdev_info(dev, "HSR: No slave devices specified\n"); | ||
| 42 | return -EINVAL; | ||
| 43 | } | ||
| 40 | if (!data[IFLA_HSR_SLAVE1]) { | 44 | if (!data[IFLA_HSR_SLAVE1]) { |
| 41 | netdev_info(dev, "IFLA_HSR_SLAVE1 missing!\n"); | 45 | netdev_info(dev, "HSR: Slave1 device not specified\n"); |
| 42 | return -EINVAL; | 46 | return -EINVAL; |
| 43 | } | 47 | } |
| 44 | link[0] = __dev_get_by_index(src_net, nla_get_u32(data[IFLA_HSR_SLAVE1])); | 48 | link[0] = __dev_get_by_index(src_net, nla_get_u32(data[IFLA_HSR_SLAVE1])); |
| 45 | if (!data[IFLA_HSR_SLAVE2]) { | 49 | if (!data[IFLA_HSR_SLAVE2]) { |
| 46 | netdev_info(dev, "IFLA_HSR_SLAVE2 missing!\n"); | 50 | netdev_info(dev, "HSR: Slave2 device not specified\n"); |
| 47 | return -EINVAL; | 51 | return -EINVAL; |
| 48 | } | 52 | } |
| 49 | link[1] = __dev_get_by_index(src_net, nla_get_u32(data[IFLA_HSR_SLAVE2])); | 53 | link[1] = __dev_get_by_index(src_net, nla_get_u32(data[IFLA_HSR_SLAVE2])); |
| @@ -63,21 +67,33 @@ static int hsr_newlink(struct net *src_net, struct net_device *dev, | |||
| 63 | 67 | ||
| 64 | static int hsr_fill_info(struct sk_buff *skb, const struct net_device *dev) | 68 | static int hsr_fill_info(struct sk_buff *skb, const struct net_device *dev) |
| 65 | { | 69 | { |
| 66 | struct hsr_priv *hsr_priv; | 70 | struct hsr_priv *hsr; |
| 71 | struct hsr_port *port; | ||
| 72 | int res; | ||
| 67 | 73 | ||
| 68 | hsr_priv = netdev_priv(dev); | 74 | hsr = netdev_priv(dev); |
| 69 | 75 | ||
| 70 | if (hsr_priv->slave[0]) | 76 | res = 0; |
| 71 | if (nla_put_u32(skb, IFLA_HSR_SLAVE1, hsr_priv->slave[0]->ifindex)) | ||
| 72 | goto nla_put_failure; | ||
| 73 | 77 | ||
| 74 | if (hsr_priv->slave[1]) | 78 | rcu_read_lock(); |
| 75 | if (nla_put_u32(skb, IFLA_HSR_SLAVE2, hsr_priv->slave[1]->ifindex)) | 79 | port = hsr_port_get_hsr(hsr, HSR_PT_SLAVE_A); |
| 76 | goto nla_put_failure; | 80 | if (port) |
| 81 | res = nla_put_u32(skb, IFLA_HSR_SLAVE1, port->dev->ifindex); | ||
| 82 | rcu_read_unlock(); | ||
| 83 | if (res) | ||
| 84 | goto nla_put_failure; | ||
| 85 | |||
| 86 | rcu_read_lock(); | ||
| 87 | port = hsr_port_get_hsr(hsr, HSR_PT_SLAVE_B); | ||
| 88 | if (port) | ||
| 89 | res = nla_put_u32(skb, IFLA_HSR_SLAVE2, port->dev->ifindex); | ||
| 90 | rcu_read_unlock(); | ||
| 91 | if (res) | ||
| 92 | goto nla_put_failure; | ||
| 77 | 93 | ||
| 78 | if (nla_put(skb, IFLA_HSR_SUPERVISION_ADDR, ETH_ALEN, | 94 | if (nla_put(skb, IFLA_HSR_SUPERVISION_ADDR, ETH_ALEN, |
| 79 | hsr_priv->sup_multicast_addr) || | 95 | hsr->sup_multicast_addr) || |
| 80 | nla_put_u16(skb, IFLA_HSR_SEQ_NR, hsr_priv->sequence_nr)) | 96 | nla_put_u16(skb, IFLA_HSR_SEQ_NR, hsr->sequence_nr)) |
| 81 | goto nla_put_failure; | 97 | goto nla_put_failure; |
| 82 | 98 | ||
| 83 | return 0; | 99 | return 0; |
| @@ -128,13 +144,13 @@ static const struct genl_multicast_group hsr_mcgrps[] = { | |||
| 128 | * over one of the slave interfaces. This would indicate an open network ring | 144 | * over one of the slave interfaces. This would indicate an open network ring |
| 129 | * (i.e. a link has failed somewhere). | 145 | * (i.e. a link has failed somewhere). |
| 130 | */ | 146 | */ |
| 131 | void hsr_nl_ringerror(struct hsr_priv *hsr_priv, unsigned char addr[ETH_ALEN], | 147 | void hsr_nl_ringerror(struct hsr_priv *hsr, unsigned char addr[ETH_ALEN], |
| 132 | enum hsr_dev_idx dev_idx) | 148 | struct hsr_port *port) |
| 133 | { | 149 | { |
| 134 | struct sk_buff *skb; | 150 | struct sk_buff *skb; |
| 135 | void *msg_head; | 151 | void *msg_head; |
| 152 | struct hsr_port *master; | ||
| 136 | int res; | 153 | int res; |
| 137 | int ifindex; | ||
| 138 | 154 | ||
| 139 | skb = genlmsg_new(NLMSG_GOODSIZE, GFP_ATOMIC); | 155 | skb = genlmsg_new(NLMSG_GOODSIZE, GFP_ATOMIC); |
| 140 | if (!skb) | 156 | if (!skb) |
| @@ -148,11 +164,7 @@ void hsr_nl_ringerror(struct hsr_priv *hsr_priv, unsigned char addr[ETH_ALEN], | |||
| 148 | if (res < 0) | 164 | if (res < 0) |
| 149 | goto nla_put_failure; | 165 | goto nla_put_failure; |
| 150 | 166 | ||
| 151 | if (hsr_priv->slave[dev_idx]) | 167 | res = nla_put_u32(skb, HSR_A_IFINDEX, port->dev->ifindex); |
| 152 | ifindex = hsr_priv->slave[dev_idx]->ifindex; | ||
| 153 | else | ||
| 154 | ifindex = -1; | ||
| 155 | res = nla_put_u32(skb, HSR_A_IFINDEX, ifindex); | ||
| 156 | if (res < 0) | 168 | if (res < 0) |
| 157 | goto nla_put_failure; | 169 | goto nla_put_failure; |
| 158 | 170 | ||
| @@ -165,16 +177,20 @@ nla_put_failure: | |||
| 165 | kfree_skb(skb); | 177 | kfree_skb(skb); |
| 166 | 178 | ||
| 167 | fail: | 179 | fail: |
| 168 | netdev_warn(hsr_priv->dev, "Could not send HSR ring error message\n"); | 180 | rcu_read_lock(); |
| 181 | master = hsr_port_get_hsr(hsr, HSR_PT_MASTER); | ||
| 182 | netdev_warn(master->dev, "Could not send HSR ring error message\n"); | ||
| 183 | rcu_read_unlock(); | ||
| 169 | } | 184 | } |
| 170 | 185 | ||
| 171 | /* This is called when we haven't heard from the node with MAC address addr for | 186 | /* This is called when we haven't heard from the node with MAC address addr for |
| 172 | * some time (just before the node is removed from the node table/list). | 187 | * some time (just before the node is removed from the node table/list). |
| 173 | */ | 188 | */ |
| 174 | void hsr_nl_nodedown(struct hsr_priv *hsr_priv, unsigned char addr[ETH_ALEN]) | 189 | void hsr_nl_nodedown(struct hsr_priv *hsr, unsigned char addr[ETH_ALEN]) |
| 175 | { | 190 | { |
| 176 | struct sk_buff *skb; | 191 | struct sk_buff *skb; |
| 177 | void *msg_head; | 192 | void *msg_head; |
| 193 | struct hsr_port *master; | ||
| 178 | int res; | 194 | int res; |
| 179 | 195 | ||
| 180 | skb = genlmsg_new(NLMSG_GOODSIZE, GFP_ATOMIC); | 196 | skb = genlmsg_new(NLMSG_GOODSIZE, GFP_ATOMIC); |
| @@ -199,7 +215,10 @@ nla_put_failure: | |||
| 199 | kfree_skb(skb); | 215 | kfree_skb(skb); |
| 200 | 216 | ||
| 201 | fail: | 217 | fail: |
| 202 | netdev_warn(hsr_priv->dev, "Could not send HSR node down\n"); | 218 | rcu_read_lock(); |
| 219 | master = hsr_port_get_hsr(hsr, HSR_PT_MASTER); | ||
| 220 | netdev_warn(master->dev, "Could not send HSR node down\n"); | ||
| 221 | rcu_read_unlock(); | ||
| 203 | } | 222 | } |
| 204 | 223 | ||
| 205 | 224 | ||
| @@ -220,7 +239,8 @@ static int hsr_get_node_status(struct sk_buff *skb_in, struct genl_info *info) | |||
| 220 | /* For sending */ | 239 | /* For sending */ |
| 221 | struct sk_buff *skb_out; | 240 | struct sk_buff *skb_out; |
| 222 | void *msg_head; | 241 | void *msg_head; |
| 223 | struct hsr_priv *hsr_priv; | 242 | struct hsr_priv *hsr; |
| 243 | struct hsr_port *port; | ||
| 224 | unsigned char hsr_node_addr_b[ETH_ALEN]; | 244 | unsigned char hsr_node_addr_b[ETH_ALEN]; |
| 225 | int hsr_node_if1_age; | 245 | int hsr_node_if1_age; |
| 226 | u16 hsr_node_if1_seq; | 246 | u16 hsr_node_if1_seq; |
| @@ -267,8 +287,8 @@ static int hsr_get_node_status(struct sk_buff *skb_in, struct genl_info *info) | |||
| 267 | if (res < 0) | 287 | if (res < 0) |
| 268 | goto nla_put_failure; | 288 | goto nla_put_failure; |
| 269 | 289 | ||
| 270 | hsr_priv = netdev_priv(hsr_dev); | 290 | hsr = netdev_priv(hsr_dev); |
| 271 | res = hsr_get_node_data(hsr_priv, | 291 | res = hsr_get_node_data(hsr, |
| 272 | (unsigned char *) nla_data(info->attrs[HSR_A_NODE_ADDR]), | 292 | (unsigned char *) nla_data(info->attrs[HSR_A_NODE_ADDR]), |
| 273 | hsr_node_addr_b, | 293 | hsr_node_addr_b, |
| 274 | &addr_b_ifindex, | 294 | &addr_b_ifindex, |
| @@ -301,9 +321,12 @@ static int hsr_get_node_status(struct sk_buff *skb_in, struct genl_info *info) | |||
| 301 | res = nla_put_u16(skb_out, HSR_A_IF1_SEQ, hsr_node_if1_seq); | 321 | res = nla_put_u16(skb_out, HSR_A_IF1_SEQ, hsr_node_if1_seq); |
| 302 | if (res < 0) | 322 | if (res < 0) |
| 303 | goto nla_put_failure; | 323 | goto nla_put_failure; |
| 304 | if (hsr_priv->slave[0]) | 324 | rcu_read_lock(); |
| 325 | port = hsr_port_get_hsr(hsr, HSR_PT_SLAVE_A); | ||
| 326 | if (port) | ||
| 305 | res = nla_put_u32(skb_out, HSR_A_IF1_IFINDEX, | 327 | res = nla_put_u32(skb_out, HSR_A_IF1_IFINDEX, |
| 306 | hsr_priv->slave[0]->ifindex); | 328 | port->dev->ifindex); |
| 329 | rcu_read_unlock(); | ||
| 307 | if (res < 0) | 330 | if (res < 0) |
| 308 | goto nla_put_failure; | 331 | goto nla_put_failure; |
| 309 | 332 | ||
| @@ -313,9 +336,14 @@ static int hsr_get_node_status(struct sk_buff *skb_in, struct genl_info *info) | |||
| 313 | res = nla_put_u16(skb_out, HSR_A_IF2_SEQ, hsr_node_if2_seq); | 336 | res = nla_put_u16(skb_out, HSR_A_IF2_SEQ, hsr_node_if2_seq); |
| 314 | if (res < 0) | 337 | if (res < 0) |
| 315 | goto nla_put_failure; | 338 | goto nla_put_failure; |
| 316 | if (hsr_priv->slave[1]) | 339 | rcu_read_lock(); |
| 340 | port = hsr_port_get_hsr(hsr, HSR_PT_SLAVE_B); | ||
| 341 | if (port) | ||
| 317 | res = nla_put_u32(skb_out, HSR_A_IF2_IFINDEX, | 342 | res = nla_put_u32(skb_out, HSR_A_IF2_IFINDEX, |
| 318 | hsr_priv->slave[1]->ifindex); | 343 | port->dev->ifindex); |
| 344 | rcu_read_unlock(); | ||
| 345 | if (res < 0) | ||
| 346 | goto nla_put_failure; | ||
| 319 | 347 | ||
| 320 | genlmsg_end(skb_out, msg_head); | 348 | genlmsg_end(skb_out, msg_head); |
| 321 | genlmsg_unicast(genl_info_net(info), skb_out, info->snd_portid); | 349 | genlmsg_unicast(genl_info_net(info), skb_out, info->snd_portid); |
| @@ -334,7 +362,7 @@ fail: | |||
| 334 | return res; | 362 | return res; |
| 335 | } | 363 | } |
| 336 | 364 | ||
| 337 | /* Get a list of MacAddressA of all nodes known to this node (other than self). | 365 | /* Get a list of MacAddressA of all nodes known to this node (including self). |
| 338 | */ | 366 | */ |
| 339 | static int hsr_get_node_list(struct sk_buff *skb_in, struct genl_info *info) | 367 | static int hsr_get_node_list(struct sk_buff *skb_in, struct genl_info *info) |
| 340 | { | 368 | { |
| @@ -345,7 +373,7 @@ static int hsr_get_node_list(struct sk_buff *skb_in, struct genl_info *info) | |||
| 345 | /* For sending */ | 373 | /* For sending */ |
| 346 | struct sk_buff *skb_out; | 374 | struct sk_buff *skb_out; |
| 347 | void *msg_head; | 375 | void *msg_head; |
| 348 | struct hsr_priv *hsr_priv; | 376 | struct hsr_priv *hsr; |
| 349 | void *pos; | 377 | void *pos; |
| 350 | unsigned char addr[ETH_ALEN]; | 378 | unsigned char addr[ETH_ALEN]; |
| 351 | int res; | 379 | int res; |
| @@ -385,17 +413,17 @@ static int hsr_get_node_list(struct sk_buff *skb_in, struct genl_info *info) | |||
| 385 | if (res < 0) | 413 | if (res < 0) |
| 386 | goto nla_put_failure; | 414 | goto nla_put_failure; |
| 387 | 415 | ||
| 388 | hsr_priv = netdev_priv(hsr_dev); | 416 | hsr = netdev_priv(hsr_dev); |
| 389 | 417 | ||
| 390 | rcu_read_lock(); | 418 | rcu_read_lock(); |
| 391 | pos = hsr_get_next_node(hsr_priv, NULL, addr); | 419 | pos = hsr_get_next_node(hsr, NULL, addr); |
| 392 | while (pos) { | 420 | while (pos) { |
| 393 | res = nla_put(skb_out, HSR_A_NODE_ADDR, ETH_ALEN, addr); | 421 | res = nla_put(skb_out, HSR_A_NODE_ADDR, ETH_ALEN, addr); |
| 394 | if (res < 0) { | 422 | if (res < 0) { |
| 395 | rcu_read_unlock(); | 423 | rcu_read_unlock(); |
| 396 | goto nla_put_failure; | 424 | goto nla_put_failure; |
| 397 | } | 425 | } |
| 398 | pos = hsr_get_next_node(hsr_priv, pos, addr); | 426 | pos = hsr_get_next_node(hsr, pos, addr); |
| 399 | } | 427 | } |
| 400 | rcu_read_unlock(); | 428 | rcu_read_unlock(); |
| 401 | 429 | ||
diff --git a/net/hsr/hsr_netlink.h b/net/hsr/hsr_netlink.h index d4579dcc3c7d..3f6b95b5b6b8 100644 --- a/net/hsr/hsr_netlink.h +++ b/net/hsr/hsr_netlink.h | |||
| @@ -1,4 +1,4 @@ | |||
| 1 | /* Copyright 2011-2013 Autronica Fire and Security AS | 1 | /* Copyright 2011-2014 Autronica Fire and Security AS |
| 2 | * | 2 | * |
| 3 | * This program is free software; you can redistribute it and/or modify it | 3 | * This program is free software; you can redistribute it and/or modify it |
| 4 | * under the terms of the GNU General Public License as published by the Free | 4 | * under the terms of the GNU General Public License as published by the Free |
| @@ -6,7 +6,7 @@ | |||
| 6 | * any later version. | 6 | * any later version. |
| 7 | * | 7 | * |
| 8 | * Author(s): | 8 | * Author(s): |
| 9 | * 2011-2013 Arvid Brodin, arvid.brodin@xdin.com | 9 | * 2011-2014 Arvid Brodin, arvid.brodin@alten.se |
| 10 | */ | 10 | */ |
| 11 | 11 | ||
| 12 | #ifndef __HSR_NETLINK_H | 12 | #ifndef __HSR_NETLINK_H |
| @@ -17,13 +17,14 @@ | |||
| 17 | #include <uapi/linux/hsr_netlink.h> | 17 | #include <uapi/linux/hsr_netlink.h> |
| 18 | 18 | ||
| 19 | struct hsr_priv; | 19 | struct hsr_priv; |
| 20 | struct hsr_port; | ||
| 20 | 21 | ||
| 21 | int __init hsr_netlink_init(void); | 22 | int __init hsr_netlink_init(void); |
| 22 | void __exit hsr_netlink_exit(void); | 23 | void __exit hsr_netlink_exit(void); |
| 23 | 24 | ||
| 24 | void hsr_nl_ringerror(struct hsr_priv *hsr_priv, unsigned char addr[ETH_ALEN], | 25 | void hsr_nl_ringerror(struct hsr_priv *hsr, unsigned char addr[ETH_ALEN], |
| 25 | int dev_idx); | 26 | struct hsr_port *port); |
| 26 | void hsr_nl_nodedown(struct hsr_priv *hsr_priv, unsigned char addr[ETH_ALEN]); | 27 | void hsr_nl_nodedown(struct hsr_priv *hsr, unsigned char addr[ETH_ALEN]); |
| 27 | void hsr_nl_framedrop(int dropcount, int dev_idx); | 28 | void hsr_nl_framedrop(int dropcount, int dev_idx); |
| 28 | void hsr_nl_linkdown(int dev_idx); | 29 | void hsr_nl_linkdown(int dev_idx); |
| 29 | 30 | ||
diff --git a/net/hsr/hsr_slave.c b/net/hsr/hsr_slave.c new file mode 100644 index 000000000000..a348dcbcd683 --- /dev/null +++ b/net/hsr/hsr_slave.c | |||
| @@ -0,0 +1,196 @@ | |||
| 1 | /* Copyright 2011-2014 Autronica Fire and Security AS | ||
| 2 | * | ||
| 3 | * This program is free software; you can redistribute it and/or modify it | ||
| 4 | * under the terms of the GNU General Public License as published by the Free | ||
| 5 | * Software Foundation; either version 2 of the License, or (at your option) | ||
| 6 | * any later version. | ||
| 7 | * | ||
| 8 | * Author(s): | ||
| 9 | * 2011-2014 Arvid Brodin, arvid.brodin@alten.se | ||
| 10 | */ | ||
| 11 | |||
| 12 | #include "hsr_slave.h" | ||
| 13 | #include <linux/etherdevice.h> | ||
| 14 | #include <linux/if_arp.h> | ||
| 15 | #include "hsr_main.h" | ||
| 16 | #include "hsr_device.h" | ||
| 17 | #include "hsr_forward.h" | ||
| 18 | #include "hsr_framereg.h" | ||
| 19 | |||
| 20 | |||
| 21 | static rx_handler_result_t hsr_handle_frame(struct sk_buff **pskb) | ||
| 22 | { | ||
| 23 | struct sk_buff *skb = *pskb; | ||
| 24 | struct hsr_port *port; | ||
| 25 | |||
| 26 | if (!skb_mac_header_was_set(skb)) { | ||
| 27 | WARN_ONCE(1, "%s: skb invalid", __func__); | ||
| 28 | return RX_HANDLER_PASS; | ||
| 29 | } | ||
| 30 | |||
| 31 | rcu_read_lock(); /* hsr->node_db, hsr->ports */ | ||
| 32 | port = hsr_port_get_rcu(skb->dev); | ||
| 33 | |||
| 34 | if (hsr_addr_is_self(port->hsr, eth_hdr(skb)->h_source)) { | ||
| 35 | /* Directly kill frames sent by ourselves */ | ||
| 36 | kfree_skb(skb); | ||
| 37 | goto finish_consume; | ||
| 38 | } | ||
| 39 | |||
| 40 | if (eth_hdr(skb)->h_proto != htons(ETH_P_PRP)) | ||
| 41 | goto finish_pass; | ||
| 42 | |||
| 43 | skb_push(skb, ETH_HLEN); | ||
| 44 | |||
| 45 | hsr_forward_skb(skb, port); | ||
| 46 | |||
| 47 | finish_consume: | ||
| 48 | rcu_read_unlock(); /* hsr->node_db, hsr->ports */ | ||
| 49 | return RX_HANDLER_CONSUMED; | ||
| 50 | |||
| 51 | finish_pass: | ||
| 52 | rcu_read_unlock(); /* hsr->node_db, hsr->ports */ | ||
| 53 | return RX_HANDLER_PASS; | ||
| 54 | } | ||
| 55 | |||
| 56 | bool hsr_port_exists(const struct net_device *dev) | ||
| 57 | { | ||
| 58 | return rcu_access_pointer(dev->rx_handler) == hsr_handle_frame; | ||
| 59 | } | ||
| 60 | |||
| 61 | |||
| 62 | static int hsr_check_dev_ok(struct net_device *dev) | ||
| 63 | { | ||
| 64 | /* Don't allow HSR on non-ethernet like devices */ | ||
| 65 | if ((dev->flags & IFF_LOOPBACK) || (dev->type != ARPHRD_ETHER) || | ||
| 66 | (dev->addr_len != ETH_ALEN)) { | ||
| 67 | netdev_info(dev, "Cannot use loopback or non-ethernet device as HSR slave.\n"); | ||
| 68 | return -EINVAL; | ||
| 69 | } | ||
| 70 | |||
| 71 | /* Don't allow enslaving hsr devices */ | ||
| 72 | if (is_hsr_master(dev)) { | ||
| 73 | netdev_info(dev, "Cannot create trees of HSR devices.\n"); | ||
| 74 | return -EINVAL; | ||
| 75 | } | ||
| 76 | |||
| 77 | if (hsr_port_exists(dev)) { | ||
| 78 | netdev_info(dev, "This device is already a HSR slave.\n"); | ||
| 79 | return -EINVAL; | ||
| 80 | } | ||
| 81 | |||
| 82 | if (dev->priv_flags & IFF_802_1Q_VLAN) { | ||
| 83 | netdev_info(dev, "HSR on top of VLAN is not yet supported in this driver.\n"); | ||
| 84 | return -EINVAL; | ||
| 85 | } | ||
| 86 | |||
| 87 | if (dev->priv_flags & IFF_DONT_BRIDGE) { | ||
| 88 | netdev_info(dev, "This device does not support bridging.\n"); | ||
| 89 | return -EOPNOTSUPP; | ||
| 90 | } | ||
| 91 | |||
| 92 | /* HSR over bonded devices has not been tested, but I'm not sure it | ||
| 93 | * won't work... | ||
| 94 | */ | ||
| 95 | |||
| 96 | return 0; | ||
| 97 | } | ||
| 98 | |||
| 99 | |||
| 100 | /* Setup device to be added to the HSR bridge. */ | ||
| 101 | static int hsr_portdev_setup(struct net_device *dev, struct hsr_port *port) | ||
| 102 | { | ||
| 103 | int res; | ||
| 104 | |||
| 105 | dev_hold(dev); | ||
| 106 | res = dev_set_promiscuity(dev, 1); | ||
| 107 | if (res) | ||
| 108 | goto fail_promiscuity; | ||
| 109 | |||
| 110 | /* FIXME: | ||
| 111 | * What does net device "adjacency" mean? Should we do | ||
| 112 | * res = netdev_master_upper_dev_link(port->dev, port->hsr->dev); ? | ||
| 113 | */ | ||
| 114 | |||
| 115 | res = netdev_rx_handler_register(dev, hsr_handle_frame, port); | ||
| 116 | if (res) | ||
| 117 | goto fail_rx_handler; | ||
| 118 | dev_disable_lro(dev); | ||
| 119 | |||
| 120 | return 0; | ||
| 121 | |||
| 122 | fail_rx_handler: | ||
| 123 | dev_set_promiscuity(dev, -1); | ||
| 124 | fail_promiscuity: | ||
| 125 | dev_put(dev); | ||
| 126 | |||
| 127 | return res; | ||
| 128 | } | ||
| 129 | |||
| 130 | int hsr_add_port(struct hsr_priv *hsr, struct net_device *dev, | ||
| 131 | enum hsr_port_type type) | ||
| 132 | { | ||
| 133 | struct hsr_port *port, *master; | ||
| 134 | int res; | ||
| 135 | |||
| 136 | if (type != HSR_PT_MASTER) { | ||
| 137 | res = hsr_check_dev_ok(dev); | ||
| 138 | if (res) | ||
| 139 | return res; | ||
| 140 | } | ||
| 141 | |||
| 142 | port = hsr_port_get_hsr(hsr, type); | ||
| 143 | if (port != NULL) | ||
| 144 | return -EBUSY; /* This port already exists */ | ||
| 145 | |||
| 146 | port = kzalloc(sizeof(*port), GFP_KERNEL); | ||
| 147 | if (port == NULL) | ||
| 148 | return -ENOMEM; | ||
| 149 | |||
| 150 | if (type != HSR_PT_MASTER) { | ||
| 151 | res = hsr_portdev_setup(dev, port); | ||
| 152 | if (res) | ||
| 153 | goto fail_dev_setup; | ||
| 154 | } | ||
| 155 | |||
| 156 | port->hsr = hsr; | ||
| 157 | port->dev = dev; | ||
| 158 | port->type = type; | ||
| 159 | |||
| 160 | list_add_tail_rcu(&port->port_list, &hsr->ports); | ||
| 161 | synchronize_rcu(); | ||
| 162 | |||
| 163 | master = hsr_port_get_hsr(hsr, HSR_PT_MASTER); | ||
| 164 | netdev_update_features(master->dev); | ||
| 165 | dev_set_mtu(master->dev, hsr_get_max_mtu(hsr)); | ||
| 166 | |||
| 167 | return 0; | ||
| 168 | |||
| 169 | fail_dev_setup: | ||
| 170 | kfree(port); | ||
| 171 | return res; | ||
| 172 | } | ||
| 173 | |||
| 174 | void hsr_del_port(struct hsr_port *port) | ||
| 175 | { | ||
| 176 | struct hsr_priv *hsr; | ||
| 177 | struct hsr_port *master; | ||
| 178 | |||
| 179 | hsr = port->hsr; | ||
| 180 | master = hsr_port_get_hsr(hsr, HSR_PT_MASTER); | ||
| 181 | list_del_rcu(&port->port_list); | ||
| 182 | |||
| 183 | if (port != master) { | ||
| 184 | netdev_update_features(master->dev); | ||
| 185 | dev_set_mtu(master->dev, hsr_get_max_mtu(hsr)); | ||
| 186 | netdev_rx_handler_unregister(port->dev); | ||
| 187 | dev_set_promiscuity(port->dev, -1); | ||
| 188 | } | ||
| 189 | |||
| 190 | /* FIXME? | ||
| 191 | * netdev_upper_dev_unlink(port->dev, port->hsr->dev); | ||
| 192 | */ | ||
| 193 | |||
| 194 | synchronize_rcu(); | ||
| 195 | dev_put(port->dev); | ||
| 196 | } | ||
diff --git a/net/hsr/hsr_slave.h b/net/hsr/hsr_slave.h new file mode 100644 index 000000000000..3ccfbf71c92e --- /dev/null +++ b/net/hsr/hsr_slave.h | |||
| @@ -0,0 +1,38 @@ | |||
| 1 | /* Copyright 2011-2014 Autronica Fire and Security AS | ||
| 2 | * | ||
| 3 | * This program is free software; you can redistribute it and/or modify it | ||
| 4 | * under the terms of the GNU General Public License as published by the Free | ||
| 5 | * Software Foundation; either version 2 of the License, or (at your option) | ||
| 6 | * any later version. | ||
| 7 | * | ||
| 8 | * Author(s): | ||
| 9 | * 2011-2014 Arvid Brodin, arvid.brodin@alten.se | ||
| 10 | */ | ||
| 11 | |||
| 12 | #ifndef __HSR_SLAVE_H | ||
| 13 | #define __HSR_SLAVE_H | ||
| 14 | |||
| 15 | #include <linux/skbuff.h> | ||
| 16 | #include <linux/netdevice.h> | ||
| 17 | #include <linux/rtnetlink.h> | ||
| 18 | #include "hsr_main.h" | ||
| 19 | |||
| 20 | int hsr_add_port(struct hsr_priv *hsr, struct net_device *dev, | ||
| 21 | enum hsr_port_type pt); | ||
| 22 | void hsr_del_port(struct hsr_port *port); | ||
| 23 | bool hsr_port_exists(const struct net_device *dev); | ||
| 24 | |||
| 25 | static inline struct hsr_port *hsr_port_get_rtnl(const struct net_device *dev) | ||
| 26 | { | ||
| 27 | ASSERT_RTNL(); | ||
| 28 | return hsr_port_exists(dev) ? | ||
| 29 | rtnl_dereference(dev->rx_handler_data) : NULL; | ||
| 30 | } | ||
| 31 | |||
| 32 | static inline struct hsr_port *hsr_port_get_rcu(const struct net_device *dev) | ||
| 33 | { | ||
| 34 | return hsr_port_exists(dev) ? | ||
| 35 | rcu_dereference(dev->rx_handler_data) : NULL; | ||
| 36 | } | ||
| 37 | |||
| 38 | #endif /* __HSR_SLAVE_H */ | ||
diff --git a/net/ieee802154/6lowpan_rtnl.c b/net/ieee802154/6lowpan_rtnl.c index fe6bd7a71081..016b77ee88f0 100644 --- a/net/ieee802154/6lowpan_rtnl.c +++ b/net/ieee802154/6lowpan_rtnl.c | |||
| @@ -80,14 +80,14 @@ lowpan_dev_info *lowpan_dev_info(const struct net_device *dev) | |||
| 80 | static inline void lowpan_address_flip(u8 *src, u8 *dest) | 80 | static inline void lowpan_address_flip(u8 *src, u8 *dest) |
| 81 | { | 81 | { |
| 82 | int i; | 82 | int i; |
| 83 | |||
| 83 | for (i = 0; i < IEEE802154_ADDR_LEN; i++) | 84 | for (i = 0; i < IEEE802154_ADDR_LEN; i++) |
| 84 | (dest)[IEEE802154_ADDR_LEN - i - 1] = (src)[i]; | 85 | (dest)[IEEE802154_ADDR_LEN - i - 1] = (src)[i]; |
| 85 | } | 86 | } |
| 86 | 87 | ||
| 87 | static int lowpan_header_create(struct sk_buff *skb, | 88 | static int lowpan_header_create(struct sk_buff *skb, struct net_device *dev, |
| 88 | struct net_device *dev, | 89 | unsigned short type, const void *_daddr, |
| 89 | unsigned short type, const void *_daddr, | 90 | const void *_saddr, unsigned int len) |
| 90 | const void *_saddr, unsigned int len) | ||
| 91 | { | 91 | { |
| 92 | const u8 *saddr = _saddr; | 92 | const u8 *saddr = _saddr; |
| 93 | const u8 *daddr = _daddr; | 93 | const u8 *daddr = _daddr; |
| @@ -144,7 +144,7 @@ static int lowpan_header_create(struct sk_buff *skb, | |||
| 144 | } | 144 | } |
| 145 | 145 | ||
| 146 | static int lowpan_give_skb_to_devices(struct sk_buff *skb, | 146 | static int lowpan_give_skb_to_devices(struct sk_buff *skb, |
| 147 | struct net_device *dev) | 147 | struct net_device *dev) |
| 148 | { | 148 | { |
| 149 | struct lowpan_dev_record *entry; | 149 | struct lowpan_dev_record *entry; |
| 150 | struct sk_buff *skb_cp; | 150 | struct sk_buff *skb_cp; |
| @@ -368,24 +368,28 @@ static netdev_tx_t lowpan_xmit(struct sk_buff *skb, struct net_device *dev) | |||
| 368 | static struct wpan_phy *lowpan_get_phy(const struct net_device *dev) | 368 | static struct wpan_phy *lowpan_get_phy(const struct net_device *dev) |
| 369 | { | 369 | { |
| 370 | struct net_device *real_dev = lowpan_dev_info(dev)->real_dev; | 370 | struct net_device *real_dev = lowpan_dev_info(dev)->real_dev; |
| 371 | |||
| 371 | return ieee802154_mlme_ops(real_dev)->get_phy(real_dev); | 372 | return ieee802154_mlme_ops(real_dev)->get_phy(real_dev); |
| 372 | } | 373 | } |
| 373 | 374 | ||
| 374 | static __le16 lowpan_get_pan_id(const struct net_device *dev) | 375 | static __le16 lowpan_get_pan_id(const struct net_device *dev) |
| 375 | { | 376 | { |
| 376 | struct net_device *real_dev = lowpan_dev_info(dev)->real_dev; | 377 | struct net_device *real_dev = lowpan_dev_info(dev)->real_dev; |
| 378 | |||
| 377 | return ieee802154_mlme_ops(real_dev)->get_pan_id(real_dev); | 379 | return ieee802154_mlme_ops(real_dev)->get_pan_id(real_dev); |
| 378 | } | 380 | } |
| 379 | 381 | ||
| 380 | static __le16 lowpan_get_short_addr(const struct net_device *dev) | 382 | static __le16 lowpan_get_short_addr(const struct net_device *dev) |
| 381 | { | 383 | { |
| 382 | struct net_device *real_dev = lowpan_dev_info(dev)->real_dev; | 384 | struct net_device *real_dev = lowpan_dev_info(dev)->real_dev; |
| 385 | |||
| 383 | return ieee802154_mlme_ops(real_dev)->get_short_addr(real_dev); | 386 | return ieee802154_mlme_ops(real_dev)->get_short_addr(real_dev); |
| 384 | } | 387 | } |
| 385 | 388 | ||
| 386 | static u8 lowpan_get_dsn(const struct net_device *dev) | 389 | static u8 lowpan_get_dsn(const struct net_device *dev) |
| 387 | { | 390 | { |
| 388 | struct net_device *real_dev = lowpan_dev_info(dev)->real_dev; | 391 | struct net_device *real_dev = lowpan_dev_info(dev)->real_dev; |
| 392 | |||
| 389 | return ieee802154_mlme_ops(real_dev)->get_dsn(real_dev); | 393 | return ieee802154_mlme_ops(real_dev)->get_dsn(real_dev); |
| 390 | } | 394 | } |
| 391 | 395 | ||
| @@ -454,7 +458,7 @@ static int lowpan_validate(struct nlattr *tb[], struct nlattr *data[]) | |||
| 454 | } | 458 | } |
| 455 | 459 | ||
| 456 | static int lowpan_rcv(struct sk_buff *skb, struct net_device *dev, | 460 | static int lowpan_rcv(struct sk_buff *skb, struct net_device *dev, |
| 457 | struct packet_type *pt, struct net_device *orig_dev) | 461 | struct packet_type *pt, struct net_device *orig_dev) |
| 458 | { | 462 | { |
| 459 | struct ieee802154_hdr hdr; | 463 | struct ieee802154_hdr hdr; |
| 460 | int ret; | 464 | int ret; |
diff --git a/net/ieee802154/Kconfig b/net/ieee802154/Kconfig index 8af1330b3137..c0d4154d144f 100644 --- a/net/ieee802154/Kconfig +++ b/net/ieee802154/Kconfig | |||
| @@ -12,13 +12,6 @@ config IEEE802154 | |||
| 12 | 12 | ||
| 13 | config IEEE802154_6LOWPAN | 13 | config IEEE802154_6LOWPAN |
| 14 | tristate "6lowpan support over IEEE 802.15.4" | 14 | tristate "6lowpan support over IEEE 802.15.4" |
| 15 | depends on IEEE802154 && IPV6 | 15 | depends on IEEE802154 && 6LOWPAN |
| 16 | select 6LOWPAN_IPHC | ||
| 17 | ---help--- | 16 | ---help--- |
| 18 | IPv6 compression over IEEE 802.15.4. | 17 | IPv6 compression over IEEE 802.15.4. |
| 19 | |||
| 20 | config 6LOWPAN_IPHC | ||
| 21 | tristate | ||
| 22 | ---help--- | ||
| 23 | 6lowpan compression code which is shared between IEEE 802.15.4 and Bluetooth | ||
| 24 | stacks. | ||
diff --git a/net/ieee802154/Makefile b/net/ieee802154/Makefile index bf1b51497a41..3914b1ed4274 100644 --- a/net/ieee802154/Makefile +++ b/net/ieee802154/Makefile | |||
| @@ -1,8 +1,7 @@ | |||
| 1 | obj-$(CONFIG_IEEE802154) += ieee802154.o af_802154.o | 1 | obj-$(CONFIG_IEEE802154) += ieee802154.o af_802154.o |
| 2 | obj-$(CONFIG_IEEE802154_6LOWPAN) += 6lowpan.o | 2 | obj-$(CONFIG_IEEE802154_6LOWPAN) += ieee802154_6lowpan.o |
| 3 | obj-$(CONFIG_6LOWPAN_IPHC) += 6lowpan_iphc.o | ||
| 4 | 3 | ||
| 5 | 6lowpan-y := 6lowpan_rtnl.o reassembly.o | 4 | ieee802154_6lowpan-y := 6lowpan_rtnl.o reassembly.o |
| 6 | ieee802154-y := netlink.o nl-mac.o nl-phy.o nl_policy.o wpan-class.o \ | 5 | ieee802154-y := netlink.o nl-mac.o nl-phy.o nl_policy.o wpan-class.o \ |
| 7 | header_ops.o | 6 | header_ops.o |
| 8 | af_802154-y := af_ieee802154.o raw.o dgram.o | 7 | af_802154-y := af_ieee802154.o raw.o dgram.o |
diff --git a/net/ieee802154/af_ieee802154.c b/net/ieee802154/af_ieee802154.c index 351d9a94ec2f..29e0de63001b 100644 --- a/net/ieee802154/af_ieee802154.c +++ b/net/ieee802154/af_ieee802154.c | |||
| @@ -40,9 +40,7 @@ | |||
| 40 | 40 | ||
| 41 | #include "af802154.h" | 41 | #include "af802154.h" |
| 42 | 42 | ||
| 43 | /* | 43 | /* Utility function for families */ |
| 44 | * Utility function for families | ||
| 45 | */ | ||
| 46 | struct net_device* | 44 | struct net_device* |
| 47 | ieee802154_get_dev(struct net *net, const struct ieee802154_addr *addr) | 45 | ieee802154_get_dev(struct net *net, const struct ieee802154_addr *addr) |
| 48 | { | 46 | { |
| @@ -87,8 +85,8 @@ ieee802154_get_dev(struct net *net, const struct ieee802154_addr *addr) | |||
| 87 | rtnl_unlock(); | 85 | rtnl_unlock(); |
| 88 | break; | 86 | break; |
| 89 | default: | 87 | default: |
| 90 | pr_warning("Unsupported ieee802154 address type: %d\n", | 88 | pr_warn("Unsupported ieee802154 address type: %d\n", |
| 91 | addr->mode); | 89 | addr->mode); |
| 92 | break; | 90 | break; |
| 93 | } | 91 | } |
| 94 | 92 | ||
| @@ -106,7 +104,7 @@ static int ieee802154_sock_release(struct socket *sock) | |||
| 106 | return 0; | 104 | return 0; |
| 107 | } | 105 | } |
| 108 | static int ieee802154_sock_sendmsg(struct kiocb *iocb, struct socket *sock, | 106 | static int ieee802154_sock_sendmsg(struct kiocb *iocb, struct socket *sock, |
| 109 | struct msghdr *msg, size_t len) | 107 | struct msghdr *msg, size_t len) |
| 110 | { | 108 | { |
| 111 | struct sock *sk = sock->sk; | 109 | struct sock *sk = sock->sk; |
| 112 | 110 | ||
| @@ -114,7 +112,7 @@ static int ieee802154_sock_sendmsg(struct kiocb *iocb, struct socket *sock, | |||
| 114 | } | 112 | } |
| 115 | 113 | ||
| 116 | static int ieee802154_sock_bind(struct socket *sock, struct sockaddr *uaddr, | 114 | static int ieee802154_sock_bind(struct socket *sock, struct sockaddr *uaddr, |
| 117 | int addr_len) | 115 | int addr_len) |
| 118 | { | 116 | { |
| 119 | struct sock *sk = sock->sk; | 117 | struct sock *sk = sock->sk; |
| 120 | 118 | ||
| @@ -125,7 +123,7 @@ static int ieee802154_sock_bind(struct socket *sock, struct sockaddr *uaddr, | |||
| 125 | } | 123 | } |
| 126 | 124 | ||
| 127 | static int ieee802154_sock_connect(struct socket *sock, struct sockaddr *uaddr, | 125 | static int ieee802154_sock_connect(struct socket *sock, struct sockaddr *uaddr, |
| 128 | int addr_len, int flags) | 126 | int addr_len, int flags) |
| 129 | { | 127 | { |
| 130 | struct sock *sk = sock->sk; | 128 | struct sock *sk = sock->sk; |
| 131 | 129 | ||
| @@ -139,7 +137,7 @@ static int ieee802154_sock_connect(struct socket *sock, struct sockaddr *uaddr, | |||
| 139 | } | 137 | } |
| 140 | 138 | ||
| 141 | static int ieee802154_dev_ioctl(struct sock *sk, struct ifreq __user *arg, | 139 | static int ieee802154_dev_ioctl(struct sock *sk, struct ifreq __user *arg, |
| 142 | unsigned int cmd) | 140 | unsigned int cmd) |
| 143 | { | 141 | { |
| 144 | struct ifreq ifr; | 142 | struct ifreq ifr; |
| 145 | int ret = -ENOIOCTLCMD; | 143 | int ret = -ENOIOCTLCMD; |
| @@ -167,7 +165,7 @@ static int ieee802154_dev_ioctl(struct sock *sk, struct ifreq __user *arg, | |||
| 167 | } | 165 | } |
| 168 | 166 | ||
| 169 | static int ieee802154_sock_ioctl(struct socket *sock, unsigned int cmd, | 167 | static int ieee802154_sock_ioctl(struct socket *sock, unsigned int cmd, |
| 170 | unsigned long arg) | 168 | unsigned long arg) |
| 171 | { | 169 | { |
| 172 | struct sock *sk = sock->sk; | 170 | struct sock *sk = sock->sk; |
| 173 | 171 | ||
| @@ -238,8 +236,7 @@ static const struct proto_ops ieee802154_dgram_ops = { | |||
| 238 | }; | 236 | }; |
| 239 | 237 | ||
| 240 | 238 | ||
| 241 | /* | 239 | /* Create a socket. Initialise the socket, blank the addresses |
| 242 | * Create a socket. Initialise the socket, blank the addresses | ||
| 243 | * set the state. | 240 | * set the state. |
| 244 | */ | 241 | */ |
| 245 | static int ieee802154_create(struct net *net, struct socket *sock, | 242 | static int ieee802154_create(struct net *net, struct socket *sock, |
| @@ -301,13 +298,14 @@ static const struct net_proto_family ieee802154_family_ops = { | |||
| 301 | }; | 298 | }; |
| 302 | 299 | ||
| 303 | static int ieee802154_rcv(struct sk_buff *skb, struct net_device *dev, | 300 | static int ieee802154_rcv(struct sk_buff *skb, struct net_device *dev, |
| 304 | struct packet_type *pt, struct net_device *orig_dev) | 301 | struct packet_type *pt, struct net_device *orig_dev) |
| 305 | { | 302 | { |
| 306 | if (!netif_running(dev)) | 303 | if (!netif_running(dev)) |
| 307 | goto drop; | 304 | goto drop; |
| 308 | pr_debug("got frame, type %d, dev %p\n", dev->type, dev); | 305 | pr_debug("got frame, type %d, dev %p\n", dev->type, dev); |
| 309 | #ifdef DEBUG | 306 | #ifdef DEBUG |
| 310 | print_hex_dump_bytes("ieee802154_rcv ", DUMP_PREFIX_NONE, skb->data, skb->len); | 307 | print_hex_dump_bytes("ieee802154_rcv ", |
| 308 | DUMP_PREFIX_NONE, skb->data, skb->len); | ||
| 311 | #endif | 309 | #endif |
| 312 | 310 | ||
| 313 | if (!net_eq(dev_net(dev), &init_net)) | 311 | if (!net_eq(dev_net(dev), &init_net)) |
diff --git a/net/ieee802154/dgram.c b/net/ieee802154/dgram.c index 4f0ed8780194..ef2ad8aaef13 100644 --- a/net/ieee802154/dgram.c +++ b/net/ieee802154/dgram.c | |||
| @@ -149,8 +149,7 @@ static int dgram_ioctl(struct sock *sk, int cmd, unsigned long arg) | |||
| 149 | spin_lock_bh(&sk->sk_receive_queue.lock); | 149 | spin_lock_bh(&sk->sk_receive_queue.lock); |
| 150 | skb = skb_peek(&sk->sk_receive_queue); | 150 | skb = skb_peek(&sk->sk_receive_queue); |
| 151 | if (skb != NULL) { | 151 | if (skb != NULL) { |
| 152 | /* | 152 | /* We will only return the amount |
| 153 | * We will only return the amount | ||
| 154 | * of this packet since that is all | 153 | * of this packet since that is all |
| 155 | * that will be read. | 154 | * that will be read. |
| 156 | */ | 155 | */ |
| @@ -161,12 +160,13 @@ static int dgram_ioctl(struct sock *sk, int cmd, unsigned long arg) | |||
| 161 | } | 160 | } |
| 162 | 161 | ||
| 163 | } | 162 | } |
| 163 | |||
| 164 | return -ENOIOCTLCMD; | 164 | return -ENOIOCTLCMD; |
| 165 | } | 165 | } |
| 166 | 166 | ||
| 167 | /* FIXME: autobind */ | 167 | /* FIXME: autobind */ |
| 168 | static int dgram_connect(struct sock *sk, struct sockaddr *uaddr, | 168 | static int dgram_connect(struct sock *sk, struct sockaddr *uaddr, |
| 169 | int len) | 169 | int len) |
| 170 | { | 170 | { |
| 171 | struct sockaddr_ieee802154 *addr = (struct sockaddr_ieee802154 *)uaddr; | 171 | struct sockaddr_ieee802154 *addr = (struct sockaddr_ieee802154 *)uaddr; |
| 172 | struct dgram_sock *ro = dgram_sk(sk); | 172 | struct dgram_sock *ro = dgram_sk(sk); |
| @@ -205,7 +205,7 @@ static int dgram_disconnect(struct sock *sk, int flags) | |||
| 205 | } | 205 | } |
| 206 | 206 | ||
| 207 | static int dgram_sendmsg(struct kiocb *iocb, struct sock *sk, | 207 | static int dgram_sendmsg(struct kiocb *iocb, struct sock *sk, |
| 208 | struct msghdr *msg, size_t size) | 208 | struct msghdr *msg, size_t size) |
| 209 | { | 209 | { |
| 210 | struct net_device *dev; | 210 | struct net_device *dev; |
| 211 | unsigned int mtu; | 211 | unsigned int mtu; |
| @@ -248,8 +248,8 @@ static int dgram_sendmsg(struct kiocb *iocb, struct sock *sk, | |||
| 248 | hlen = LL_RESERVED_SPACE(dev); | 248 | hlen = LL_RESERVED_SPACE(dev); |
| 249 | tlen = dev->needed_tailroom; | 249 | tlen = dev->needed_tailroom; |
| 250 | skb = sock_alloc_send_skb(sk, hlen + tlen + size, | 250 | skb = sock_alloc_send_skb(sk, hlen + tlen + size, |
| 251 | msg->msg_flags & MSG_DONTWAIT, | 251 | msg->msg_flags & MSG_DONTWAIT, |
| 252 | &err); | 252 | &err); |
| 253 | if (!skb) | 253 | if (!skb) |
| 254 | goto out_dev; | 254 | goto out_dev; |
| 255 | 255 | ||
| @@ -262,7 +262,8 @@ static int dgram_sendmsg(struct kiocb *iocb, struct sock *sk, | |||
| 262 | cb->ackreq = ro->want_ack; | 262 | cb->ackreq = ro->want_ack; |
| 263 | 263 | ||
| 264 | if (msg->msg_name) { | 264 | if (msg->msg_name) { |
| 265 | DECLARE_SOCKADDR(struct sockaddr_ieee802154*, daddr, msg->msg_name); | 265 | DECLARE_SOCKADDR(struct sockaddr_ieee802154*, |
| 266 | daddr, msg->msg_name); | ||
| 266 | 267 | ||
| 267 | ieee802154_addr_from_sa(&dst_addr, &daddr->addr); | 268 | ieee802154_addr_from_sa(&dst_addr, &daddr->addr); |
| 268 | } else { | 269 | } else { |
| @@ -304,8 +305,8 @@ out: | |||
| 304 | } | 305 | } |
| 305 | 306 | ||
| 306 | static int dgram_recvmsg(struct kiocb *iocb, struct sock *sk, | 307 | static int dgram_recvmsg(struct kiocb *iocb, struct sock *sk, |
| 307 | struct msghdr *msg, size_t len, int noblock, int flags, | 308 | struct msghdr *msg, size_t len, int noblock, |
| 308 | int *addr_len) | 309 | int flags, int *addr_len) |
| 309 | { | 310 | { |
| 310 | size_t copied = 0; | 311 | size_t copied = 0; |
| 311 | int err = -EOPNOTSUPP; | 312 | int err = -EOPNOTSUPP; |
| @@ -398,6 +399,7 @@ int ieee802154_dgram_deliver(struct net_device *dev, struct sk_buff *skb) | |||
| 398 | dgram_sk(sk))) { | 399 | dgram_sk(sk))) { |
| 399 | if (prev) { | 400 | if (prev) { |
| 400 | struct sk_buff *clone; | 401 | struct sk_buff *clone; |
| 402 | |||
| 401 | clone = skb_clone(skb, GFP_ATOMIC); | 403 | clone = skb_clone(skb, GFP_ATOMIC); |
| 402 | if (clone) | 404 | if (clone) |
| 403 | dgram_rcv_skb(prev, clone); | 405 | dgram_rcv_skb(prev, clone); |
| @@ -407,9 +409,9 @@ int ieee802154_dgram_deliver(struct net_device *dev, struct sk_buff *skb) | |||
| 407 | } | 409 | } |
| 408 | } | 410 | } |
| 409 | 411 | ||
| 410 | if (prev) | 412 | if (prev) { |
| 411 | dgram_rcv_skb(prev, skb); | 413 | dgram_rcv_skb(prev, skb); |
| 412 | else { | 414 | } else { |
| 413 | kfree_skb(skb); | 415 | kfree_skb(skb); |
| 414 | ret = NET_RX_DROP; | 416 | ret = NET_RX_DROP; |
| 415 | } | 417 | } |
| @@ -419,7 +421,7 @@ int ieee802154_dgram_deliver(struct net_device *dev, struct sk_buff *skb) | |||
| 419 | } | 421 | } |
| 420 | 422 | ||
| 421 | static int dgram_getsockopt(struct sock *sk, int level, int optname, | 423 | static int dgram_getsockopt(struct sock *sk, int level, int optname, |
| 422 | char __user *optval, int __user *optlen) | 424 | char __user *optval, int __user *optlen) |
| 423 | { | 425 | { |
| 424 | struct dgram_sock *ro = dgram_sk(sk); | 426 | struct dgram_sock *ro = dgram_sk(sk); |
| 425 | 427 | ||
| @@ -463,7 +465,7 @@ static int dgram_getsockopt(struct sock *sk, int level, int optname, | |||
| 463 | } | 465 | } |
| 464 | 466 | ||
| 465 | static int dgram_setsockopt(struct sock *sk, int level, int optname, | 467 | static int dgram_setsockopt(struct sock *sk, int level, int optname, |
| 466 | char __user *optval, unsigned int optlen) | 468 | char __user *optval, unsigned int optlen) |
| 467 | { | 469 | { |
| 468 | struct dgram_sock *ro = dgram_sk(sk); | 470 | struct dgram_sock *ro = dgram_sk(sk); |
| 469 | struct net *net = sock_net(sk); | 471 | struct net *net = sock_net(sk); |
diff --git a/net/ieee802154/ieee802154.h b/net/ieee802154/ieee802154.h index 8b83a231299e..5d352f86979e 100644 --- a/net/ieee802154/ieee802154.h +++ b/net/ieee802154/ieee802154.h | |||
| @@ -43,7 +43,7 @@ struct genl_info; | |||
| 43 | struct sk_buff *ieee802154_nl_create(int flags, u8 req); | 43 | struct sk_buff *ieee802154_nl_create(int flags, u8 req); |
| 44 | int ieee802154_nl_mcast(struct sk_buff *msg, unsigned int group); | 44 | int ieee802154_nl_mcast(struct sk_buff *msg, unsigned int group); |
| 45 | struct sk_buff *ieee802154_nl_new_reply(struct genl_info *info, | 45 | struct sk_buff *ieee802154_nl_new_reply(struct genl_info *info, |
| 46 | int flags, u8 req); | 46 | int flags, u8 req); |
| 47 | int ieee802154_nl_reply(struct sk_buff *msg, struct genl_info *info); | 47 | int ieee802154_nl_reply(struct sk_buff *msg, struct genl_info *info); |
| 48 | 48 | ||
| 49 | extern struct genl_family nl802154_family; | 49 | extern struct genl_family nl802154_family; |
diff --git a/net/ieee802154/netlink.c b/net/ieee802154/netlink.c index 26efcf4fd2ff..9222966f5e6d 100644 --- a/net/ieee802154/netlink.c +++ b/net/ieee802154/netlink.c | |||
| @@ -52,7 +52,7 @@ struct sk_buff *ieee802154_nl_create(int flags, u8 req) | |||
| 52 | 52 | ||
| 53 | spin_lock_irqsave(&ieee802154_seq_lock, f); | 53 | spin_lock_irqsave(&ieee802154_seq_lock, f); |
| 54 | hdr = genlmsg_put(msg, 0, ieee802154_seq_num++, | 54 | hdr = genlmsg_put(msg, 0, ieee802154_seq_num++, |
| 55 | &nl802154_family, flags, req); | 55 | &nl802154_family, flags, req); |
| 56 | spin_unlock_irqrestore(&ieee802154_seq_lock, f); | 56 | spin_unlock_irqrestore(&ieee802154_seq_lock, f); |
| 57 | if (!hdr) { | 57 | if (!hdr) { |
| 58 | nlmsg_free(msg); | 58 | nlmsg_free(msg); |
| @@ -86,7 +86,7 @@ struct sk_buff *ieee802154_nl_new_reply(struct genl_info *info, | |||
| 86 | return NULL; | 86 | return NULL; |
| 87 | 87 | ||
| 88 | hdr = genlmsg_put_reply(msg, info, | 88 | hdr = genlmsg_put_reply(msg, info, |
| 89 | &nl802154_family, flags, req); | 89 | &nl802154_family, flags, req); |
| 90 | if (!hdr) { | 90 | if (!hdr) { |
| 91 | nlmsg_free(msg); | 91 | nlmsg_free(msg); |
| 92 | return NULL; | 92 | return NULL; |
diff --git a/net/ieee802154/nl-mac.c b/net/ieee802154/nl-mac.c index a3281b8bfd5b..c6bfe22bfa5e 100644 --- a/net/ieee802154/nl-mac.c +++ b/net/ieee802154/nl-mac.c | |||
| @@ -60,7 +60,8 @@ static __le16 nla_get_shortaddr(const struct nlattr *nla) | |||
| 60 | } | 60 | } |
| 61 | 61 | ||
| 62 | int ieee802154_nl_assoc_indic(struct net_device *dev, | 62 | int ieee802154_nl_assoc_indic(struct net_device *dev, |
| 63 | struct ieee802154_addr *addr, u8 cap) | 63 | struct ieee802154_addr *addr, |
| 64 | u8 cap) | ||
| 64 | { | 65 | { |
| 65 | struct sk_buff *msg; | 66 | struct sk_buff *msg; |
| 66 | 67 | ||
| @@ -93,7 +94,7 @@ nla_put_failure: | |||
| 93 | EXPORT_SYMBOL(ieee802154_nl_assoc_indic); | 94 | EXPORT_SYMBOL(ieee802154_nl_assoc_indic); |
| 94 | 95 | ||
| 95 | int ieee802154_nl_assoc_confirm(struct net_device *dev, __le16 short_addr, | 96 | int ieee802154_nl_assoc_confirm(struct net_device *dev, __le16 short_addr, |
| 96 | u8 status) | 97 | u8 status) |
| 97 | { | 98 | { |
| 98 | struct sk_buff *msg; | 99 | struct sk_buff *msg; |
| 99 | 100 | ||
| @@ -119,7 +120,8 @@ nla_put_failure: | |||
| 119 | EXPORT_SYMBOL(ieee802154_nl_assoc_confirm); | 120 | EXPORT_SYMBOL(ieee802154_nl_assoc_confirm); |
| 120 | 121 | ||
| 121 | int ieee802154_nl_disassoc_indic(struct net_device *dev, | 122 | int ieee802154_nl_disassoc_indic(struct net_device *dev, |
| 122 | struct ieee802154_addr *addr, u8 reason) | 123 | struct ieee802154_addr *addr, |
| 124 | u8 reason) | ||
| 123 | { | 125 | { |
| 124 | struct sk_buff *msg; | 126 | struct sk_buff *msg; |
| 125 | 127 | ||
| @@ -205,8 +207,9 @@ nla_put_failure: | |||
| 205 | EXPORT_SYMBOL(ieee802154_nl_beacon_indic); | 207 | EXPORT_SYMBOL(ieee802154_nl_beacon_indic); |
| 206 | 208 | ||
| 207 | int ieee802154_nl_scan_confirm(struct net_device *dev, | 209 | int ieee802154_nl_scan_confirm(struct net_device *dev, |
| 208 | u8 status, u8 scan_type, u32 unscanned, u8 page, | 210 | u8 status, u8 scan_type, |
| 209 | u8 *edl/* , struct list_head *pan_desc_list */) | 211 | u32 unscanned, u8 page, |
| 212 | u8 *edl/* , struct list_head *pan_desc_list */) | ||
| 210 | { | 213 | { |
| 211 | struct sk_buff *msg; | 214 | struct sk_buff *msg; |
| 212 | 215 | ||
| @@ -260,7 +263,7 @@ nla_put_failure: | |||
| 260 | EXPORT_SYMBOL(ieee802154_nl_start_confirm); | 263 | EXPORT_SYMBOL(ieee802154_nl_start_confirm); |
| 261 | 264 | ||
| 262 | static int ieee802154_nl_fill_iface(struct sk_buff *msg, u32 portid, | 265 | static int ieee802154_nl_fill_iface(struct sk_buff *msg, u32 portid, |
| 263 | u32 seq, int flags, struct net_device *dev) | 266 | u32 seq, int flags, struct net_device *dev) |
| 264 | { | 267 | { |
| 265 | void *hdr; | 268 | void *hdr; |
| 266 | struct wpan_phy *phy; | 269 | struct wpan_phy *phy; |
| @@ -270,7 +273,7 @@ static int ieee802154_nl_fill_iface(struct sk_buff *msg, u32 portid, | |||
| 270 | pr_debug("%s\n", __func__); | 273 | pr_debug("%s\n", __func__); |
| 271 | 274 | ||
| 272 | hdr = genlmsg_put(msg, 0, seq, &nl802154_family, flags, | 275 | hdr = genlmsg_put(msg, 0, seq, &nl802154_family, flags, |
| 273 | IEEE802154_LIST_IFACE); | 276 | IEEE802154_LIST_IFACE); |
| 274 | if (!hdr) | 277 | if (!hdr) |
| 275 | goto out; | 278 | goto out; |
| 276 | 279 | ||
| @@ -330,14 +333,16 @@ static struct net_device *ieee802154_nl_get_dev(struct genl_info *info) | |||
| 330 | 333 | ||
| 331 | if (info->attrs[IEEE802154_ATTR_DEV_NAME]) { | 334 | if (info->attrs[IEEE802154_ATTR_DEV_NAME]) { |
| 332 | char name[IFNAMSIZ + 1]; | 335 | char name[IFNAMSIZ + 1]; |
| 336 | |||
| 333 | nla_strlcpy(name, info->attrs[IEEE802154_ATTR_DEV_NAME], | 337 | nla_strlcpy(name, info->attrs[IEEE802154_ATTR_DEV_NAME], |
| 334 | sizeof(name)); | 338 | sizeof(name)); |
| 335 | dev = dev_get_by_name(&init_net, name); | 339 | dev = dev_get_by_name(&init_net, name); |
| 336 | } else if (info->attrs[IEEE802154_ATTR_DEV_INDEX]) | 340 | } else if (info->attrs[IEEE802154_ATTR_DEV_INDEX]) { |
| 337 | dev = dev_get_by_index(&init_net, | 341 | dev = dev_get_by_index(&init_net, |
| 338 | nla_get_u32(info->attrs[IEEE802154_ATTR_DEV_INDEX])); | 342 | nla_get_u32(info->attrs[IEEE802154_ATTR_DEV_INDEX])); |
| 339 | else | 343 | } else { |
| 340 | return NULL; | 344 | return NULL; |
| 345 | } | ||
| 341 | 346 | ||
| 342 | if (!dev) | 347 | if (!dev) |
| 343 | return NULL; | 348 | return NULL; |
| @@ -435,7 +440,7 @@ int ieee802154_disassociate_req(struct sk_buff *skb, struct genl_info *info) | |||
| 435 | int ret = -EOPNOTSUPP; | 440 | int ret = -EOPNOTSUPP; |
| 436 | 441 | ||
| 437 | if ((!info->attrs[IEEE802154_ATTR_DEST_HW_ADDR] && | 442 | if ((!info->attrs[IEEE802154_ATTR_DEST_HW_ADDR] && |
| 438 | !info->attrs[IEEE802154_ATTR_DEST_SHORT_ADDR]) || | 443 | !info->attrs[IEEE802154_ATTR_DEST_SHORT_ADDR]) || |
| 439 | !info->attrs[IEEE802154_ATTR_REASON]) | 444 | !info->attrs[IEEE802154_ATTR_REASON]) |
| 440 | return -EINVAL; | 445 | return -EINVAL; |
| 441 | 446 | ||
| @@ -464,8 +469,7 @@ out: | |||
| 464 | return ret; | 469 | return ret; |
| 465 | } | 470 | } |
| 466 | 471 | ||
| 467 | /* | 472 | /* PANid, channel, beacon_order = 15, superframe_order = 15, |
| 468 | * PANid, channel, beacon_order = 15, superframe_order = 15, | ||
| 469 | * PAN_coordinator, battery_life_extension = 0, | 473 | * PAN_coordinator, battery_life_extension = 0, |
| 470 | * coord_realignment = 0, security_enable = 0 | 474 | * coord_realignment = 0, security_enable = 0 |
| 471 | */ | 475 | */ |
| @@ -559,8 +563,8 @@ int ieee802154_scan_req(struct sk_buff *skb, struct genl_info *info) | |||
| 559 | page = 0; | 563 | page = 0; |
| 560 | 564 | ||
| 561 | 565 | ||
| 562 | ret = ieee802154_mlme_ops(dev)->scan_req(dev, type, channels, page, | 566 | ret = ieee802154_mlme_ops(dev)->scan_req(dev, type, channels, |
| 563 | duration); | 567 | page, duration); |
| 564 | 568 | ||
| 565 | out: | 569 | out: |
| 566 | dev_put(dev); | 570 | dev_put(dev); |
| @@ -570,7 +574,8 @@ out: | |||
| 570 | int ieee802154_list_iface(struct sk_buff *skb, struct genl_info *info) | 574 | int ieee802154_list_iface(struct sk_buff *skb, struct genl_info *info) |
| 571 | { | 575 | { |
| 572 | /* Request for interface name, index, type, IEEE address, | 576 | /* Request for interface name, index, type, IEEE address, |
| 573 | PAN Id, short address */ | 577 | * PAN Id, short address |
| 578 | */ | ||
| 574 | struct sk_buff *msg; | 579 | struct sk_buff *msg; |
| 575 | struct net_device *dev = NULL; | 580 | struct net_device *dev = NULL; |
| 576 | int rc = -ENOBUFS; | 581 | int rc = -ENOBUFS; |
| @@ -586,7 +591,7 @@ int ieee802154_list_iface(struct sk_buff *skb, struct genl_info *info) | |||
| 586 | goto out_dev; | 591 | goto out_dev; |
| 587 | 592 | ||
| 588 | rc = ieee802154_nl_fill_iface(msg, info->snd_portid, info->snd_seq, | 593 | rc = ieee802154_nl_fill_iface(msg, info->snd_portid, info->snd_seq, |
| 589 | 0, dev); | 594 | 0, dev); |
| 590 | if (rc < 0) | 595 | if (rc < 0) |
| 591 | goto out_free; | 596 | goto out_free; |
| 592 | 597 | ||
| @@ -598,7 +603,6 @@ out_free: | |||
| 598 | out_dev: | 603 | out_dev: |
| 599 | dev_put(dev); | 604 | dev_put(dev); |
| 600 | return rc; | 605 | return rc; |
| 601 | |||
| 602 | } | 606 | } |
| 603 | 607 | ||
| 604 | int ieee802154_dump_iface(struct sk_buff *skb, struct netlink_callback *cb) | 608 | int ieee802154_dump_iface(struct sk_buff *skb, struct netlink_callback *cb) |
| @@ -616,7 +620,8 @@ int ieee802154_dump_iface(struct sk_buff *skb, struct netlink_callback *cb) | |||
| 616 | goto cont; | 620 | goto cont; |
| 617 | 621 | ||
| 618 | if (ieee802154_nl_fill_iface(skb, NETLINK_CB(cb->skb).portid, | 622 | if (ieee802154_nl_fill_iface(skb, NETLINK_CB(cb->skb).portid, |
| 619 | cb->nlh->nlmsg_seq, NLM_F_MULTI, dev) < 0) | 623 | cb->nlh->nlmsg_seq, |
| 624 | NLM_F_MULTI, dev) < 0) | ||
| 620 | break; | 625 | break; |
| 621 | cont: | 626 | cont: |
| 622 | idx++; | 627 | idx++; |
| @@ -765,6 +770,7 @@ ieee802154_llsec_parse_key_id(struct genl_info *info, | |||
| 765 | case IEEE802154_SCF_KEY_SHORT_INDEX: | 770 | case IEEE802154_SCF_KEY_SHORT_INDEX: |
| 766 | { | 771 | { |
| 767 | u32 source = nla_get_u32(info->attrs[IEEE802154_ATTR_LLSEC_KEY_SOURCE_SHORT]); | 772 | u32 source = nla_get_u32(info->attrs[IEEE802154_ATTR_LLSEC_KEY_SOURCE_SHORT]); |
| 773 | |||
| 768 | desc->short_source = cpu_to_le32(source); | 774 | desc->short_source = cpu_to_le32(source); |
| 769 | break; | 775 | break; |
| 770 | } | 776 | } |
| @@ -842,7 +848,7 @@ int ieee802154_llsec_getparams(struct sk_buff *skb, struct genl_info *info) | |||
| 842 | goto out_dev; | 848 | goto out_dev; |
| 843 | 849 | ||
| 844 | hdr = genlmsg_put(msg, 0, info->snd_seq, &nl802154_family, 0, | 850 | hdr = genlmsg_put(msg, 0, info->snd_seq, &nl802154_family, 0, |
| 845 | IEEE802154_LLSEC_GETPARAMS); | 851 | IEEE802154_LLSEC_GETPARAMS); |
| 846 | if (!hdr) | 852 | if (!hdr) |
| 847 | goto out_free; | 853 | goto out_free; |
| 848 | 854 | ||
| @@ -946,7 +952,7 @@ struct llsec_dump_data { | |||
| 946 | 952 | ||
| 947 | static int | 953 | static int |
| 948 | ieee802154_llsec_dump_table(struct sk_buff *skb, struct netlink_callback *cb, | 954 | ieee802154_llsec_dump_table(struct sk_buff *skb, struct netlink_callback *cb, |
| 949 | int (*step)(struct llsec_dump_data*)) | 955 | int (*step)(struct llsec_dump_data *)) |
| 950 | { | 956 | { |
| 951 | struct net *net = sock_net(skb->sk); | 957 | struct net *net = sock_net(skb->sk); |
| 952 | struct net_device *dev; | 958 | struct net_device *dev; |
diff --git a/net/ieee802154/nl-phy.c b/net/ieee802154/nl-phy.c index 89b265aea151..972baf83411a 100644 --- a/net/ieee802154/nl-phy.c +++ b/net/ieee802154/nl-phy.c | |||
| @@ -36,7 +36,7 @@ | |||
| 36 | #include "ieee802154.h" | 36 | #include "ieee802154.h" |
| 37 | 37 | ||
| 38 | static int ieee802154_nl_fill_phy(struct sk_buff *msg, u32 portid, | 38 | static int ieee802154_nl_fill_phy(struct sk_buff *msg, u32 portid, |
| 39 | u32 seq, int flags, struct wpan_phy *phy) | 39 | u32 seq, int flags, struct wpan_phy *phy) |
| 40 | { | 40 | { |
| 41 | void *hdr; | 41 | void *hdr; |
| 42 | int i, pages = 0; | 42 | int i, pages = 0; |
| @@ -48,7 +48,7 @@ static int ieee802154_nl_fill_phy(struct sk_buff *msg, u32 portid, | |||
| 48 | return -EMSGSIZE; | 48 | return -EMSGSIZE; |
| 49 | 49 | ||
| 50 | hdr = genlmsg_put(msg, 0, seq, &nl802154_family, flags, | 50 | hdr = genlmsg_put(msg, 0, seq, &nl802154_family, flags, |
| 51 | IEEE802154_LIST_PHY); | 51 | IEEE802154_LIST_PHY); |
| 52 | if (!hdr) | 52 | if (!hdr) |
| 53 | goto out; | 53 | goto out; |
| 54 | 54 | ||
| @@ -80,7 +80,8 @@ out: | |||
| 80 | int ieee802154_list_phy(struct sk_buff *skb, struct genl_info *info) | 80 | int ieee802154_list_phy(struct sk_buff *skb, struct genl_info *info) |
| 81 | { | 81 | { |
| 82 | /* Request for interface name, index, type, IEEE address, | 82 | /* Request for interface name, index, type, IEEE address, |
| 83 | PAN Id, short address */ | 83 | * PAN Id, short address |
| 84 | */ | ||
| 84 | struct sk_buff *msg; | 85 | struct sk_buff *msg; |
| 85 | struct wpan_phy *phy; | 86 | struct wpan_phy *phy; |
| 86 | const char *name; | 87 | const char *name; |
| @@ -105,7 +106,7 @@ int ieee802154_list_phy(struct sk_buff *skb, struct genl_info *info) | |||
| 105 | goto out_dev; | 106 | goto out_dev; |
| 106 | 107 | ||
| 107 | rc = ieee802154_nl_fill_phy(msg, info->snd_portid, info->snd_seq, | 108 | rc = ieee802154_nl_fill_phy(msg, info->snd_portid, info->snd_seq, |
| 108 | 0, phy); | 109 | 0, phy); |
| 109 | if (rc < 0) | 110 | if (rc < 0) |
| 110 | goto out_free; | 111 | goto out_free; |
| 111 | 112 | ||
| @@ -117,7 +118,6 @@ out_free: | |||
| 117 | out_dev: | 118 | out_dev: |
| 118 | wpan_phy_put(phy); | 119 | wpan_phy_put(phy); |
| 119 | return rc; | 120 | return rc; |
| 120 | |||
| 121 | } | 121 | } |
| 122 | 122 | ||
| 123 | struct dump_phy_data { | 123 | struct dump_phy_data { |
| @@ -137,10 +137,10 @@ static int ieee802154_dump_phy_iter(struct wpan_phy *phy, void *_data) | |||
| 137 | return 0; | 137 | return 0; |
| 138 | 138 | ||
| 139 | rc = ieee802154_nl_fill_phy(data->skb, | 139 | rc = ieee802154_nl_fill_phy(data->skb, |
| 140 | NETLINK_CB(data->cb->skb).portid, | 140 | NETLINK_CB(data->cb->skb).portid, |
| 141 | data->cb->nlh->nlmsg_seq, | 141 | data->cb->nlh->nlmsg_seq, |
| 142 | NLM_F_MULTI, | 142 | NLM_F_MULTI, |
| 143 | phy); | 143 | phy); |
| 144 | 144 | ||
| 145 | if (rc < 0) { | 145 | if (rc < 0) { |
| 146 | data->idx--; | 146 | data->idx--; |
| @@ -238,10 +238,9 @@ int ieee802154_add_iface(struct sk_buff *skb, struct genl_info *info) | |||
| 238 | 238 | ||
| 239 | addr.sa_family = ARPHRD_IEEE802154; | 239 | addr.sa_family = ARPHRD_IEEE802154; |
| 240 | nla_memcpy(&addr.sa_data, info->attrs[IEEE802154_ATTR_HW_ADDR], | 240 | nla_memcpy(&addr.sa_data, info->attrs[IEEE802154_ATTR_HW_ADDR], |
| 241 | IEEE802154_ADDR_LEN); | 241 | IEEE802154_ADDR_LEN); |
| 242 | 242 | ||
| 243 | /* | 243 | /* strangely enough, some callbacks (inetdev_event) from |
| 244 | * strangely enough, some callbacks (inetdev_event) from | ||
| 245 | * dev_set_mac_address require RTNL_LOCK | 244 | * dev_set_mac_address require RTNL_LOCK |
| 246 | */ | 245 | */ |
| 247 | rtnl_lock(); | 246 | rtnl_lock(); |
diff --git a/net/ieee802154/raw.c b/net/ieee802154/raw.c index 74d54fae33d7..9d1f64806f02 100644 --- a/net/ieee802154/raw.c +++ b/net/ieee802154/raw.c | |||
| @@ -96,7 +96,7 @@ out: | |||
| 96 | } | 96 | } |
| 97 | 97 | ||
| 98 | static int raw_connect(struct sock *sk, struct sockaddr *uaddr, | 98 | static int raw_connect(struct sock *sk, struct sockaddr *uaddr, |
| 99 | int addr_len) | 99 | int addr_len) |
| 100 | { | 100 | { |
| 101 | return -ENOTSUPP; | 101 | return -ENOTSUPP; |
| 102 | } | 102 | } |
| @@ -106,8 +106,8 @@ static int raw_disconnect(struct sock *sk, int flags) | |||
| 106 | return 0; | 106 | return 0; |
| 107 | } | 107 | } |
| 108 | 108 | ||
| 109 | static int raw_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg, | 109 | static int raw_sendmsg(struct kiocb *iocb, struct sock *sk, |
| 110 | size_t size) | 110 | struct msghdr *msg, size_t size) |
| 111 | { | 111 | { |
| 112 | struct net_device *dev; | 112 | struct net_device *dev; |
| 113 | unsigned int mtu; | 113 | unsigned int mtu; |
| @@ -145,7 +145,7 @@ static int raw_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg, | |||
| 145 | hlen = LL_RESERVED_SPACE(dev); | 145 | hlen = LL_RESERVED_SPACE(dev); |
| 146 | tlen = dev->needed_tailroom; | 146 | tlen = dev->needed_tailroom; |
| 147 | skb = sock_alloc_send_skb(sk, hlen + tlen + size, | 147 | skb = sock_alloc_send_skb(sk, hlen + tlen + size, |
| 148 | msg->msg_flags & MSG_DONTWAIT, &err); | 148 | msg->msg_flags & MSG_DONTWAIT, &err); |
| 149 | if (!skb) | 149 | if (!skb) |
| 150 | goto out_dev; | 150 | goto out_dev; |
| 151 | 151 | ||
| @@ -235,7 +235,6 @@ void ieee802154_raw_deliver(struct net_device *dev, struct sk_buff *skb) | |||
| 235 | bh_lock_sock(sk); | 235 | bh_lock_sock(sk); |
| 236 | if (!sk->sk_bound_dev_if || | 236 | if (!sk->sk_bound_dev_if || |
| 237 | sk->sk_bound_dev_if == dev->ifindex) { | 237 | sk->sk_bound_dev_if == dev->ifindex) { |
| 238 | |||
| 239 | struct sk_buff *clone; | 238 | struct sk_buff *clone; |
| 240 | 239 | ||
| 241 | clone = skb_clone(skb, GFP_ATOMIC); | 240 | clone = skb_clone(skb, GFP_ATOMIC); |
| @@ -248,13 +247,13 @@ void ieee802154_raw_deliver(struct net_device *dev, struct sk_buff *skb) | |||
| 248 | } | 247 | } |
| 249 | 248 | ||
| 250 | static int raw_getsockopt(struct sock *sk, int level, int optname, | 249 | static int raw_getsockopt(struct sock *sk, int level, int optname, |
| 251 | char __user *optval, int __user *optlen) | 250 | char __user *optval, int __user *optlen) |
| 252 | { | 251 | { |
| 253 | return -EOPNOTSUPP; | 252 | return -EOPNOTSUPP; |
| 254 | } | 253 | } |
| 255 | 254 | ||
| 256 | static int raw_setsockopt(struct sock *sk, int level, int optname, | 255 | static int raw_setsockopt(struct sock *sk, int level, int optname, |
| 257 | char __user *optval, unsigned int optlen) | 256 | char __user *optval, unsigned int optlen) |
| 258 | { | 257 | { |
| 259 | return -EOPNOTSUPP; | 258 | return -EOPNOTSUPP; |
| 260 | } | 259 | } |
| @@ -274,4 +273,3 @@ struct proto ieee802154_raw_prot = { | |||
| 274 | .getsockopt = raw_getsockopt, | 273 | .getsockopt = raw_getsockopt, |
| 275 | .setsockopt = raw_setsockopt, | 274 | .setsockopt = raw_setsockopt, |
| 276 | }; | 275 | }; |
| 277 | |||
diff --git a/net/ieee802154/reassembly.c b/net/ieee802154/reassembly.c index 6f1428c4870b..ffec6ce51005 100644 --- a/net/ieee802154/reassembly.c +++ b/net/ieee802154/reassembly.c | |||
| @@ -30,6 +30,8 @@ | |||
| 30 | 30 | ||
| 31 | #include "reassembly.h" | 31 | #include "reassembly.h" |
| 32 | 32 | ||
| 33 | static const char lowpan_frags_cache_name[] = "lowpan-frags"; | ||
| 34 | |||
| 33 | struct lowpan_frag_info { | 35 | struct lowpan_frag_info { |
| 34 | __be16 d_tag; | 36 | __be16 d_tag; |
| 35 | u16 d_size; | 37 | u16 d_size; |
| @@ -50,29 +52,25 @@ static unsigned int lowpan_hash_frag(__be16 tag, u16 d_size, | |||
| 50 | const struct ieee802154_addr *saddr, | 52 | const struct ieee802154_addr *saddr, |
| 51 | const struct ieee802154_addr *daddr) | 53 | const struct ieee802154_addr *daddr) |
| 52 | { | 54 | { |
| 53 | u32 c; | ||
| 54 | |||
| 55 | net_get_random_once(&lowpan_frags.rnd, sizeof(lowpan_frags.rnd)); | 55 | net_get_random_once(&lowpan_frags.rnd, sizeof(lowpan_frags.rnd)); |
| 56 | c = jhash_3words(ieee802154_addr_hash(saddr), | 56 | return jhash_3words(ieee802154_addr_hash(saddr), |
| 57 | ieee802154_addr_hash(daddr), | 57 | ieee802154_addr_hash(daddr), |
| 58 | (__force u32)(tag + (d_size << 16)), | 58 | (__force u32)(tag + (d_size << 16)), |
| 59 | lowpan_frags.rnd); | 59 | lowpan_frags.rnd); |
| 60 | |||
| 61 | return c & (INETFRAGS_HASHSZ - 1); | ||
| 62 | } | 60 | } |
| 63 | 61 | ||
| 64 | static unsigned int lowpan_hashfn(struct inet_frag_queue *q) | 62 | static unsigned int lowpan_hashfn(const struct inet_frag_queue *q) |
| 65 | { | 63 | { |
| 66 | struct lowpan_frag_queue *fq; | 64 | const struct lowpan_frag_queue *fq; |
| 67 | 65 | ||
| 68 | fq = container_of(q, struct lowpan_frag_queue, q); | 66 | fq = container_of(q, struct lowpan_frag_queue, q); |
| 69 | return lowpan_hash_frag(fq->tag, fq->d_size, &fq->saddr, &fq->daddr); | 67 | return lowpan_hash_frag(fq->tag, fq->d_size, &fq->saddr, &fq->daddr); |
| 70 | } | 68 | } |
| 71 | 69 | ||
| 72 | static bool lowpan_frag_match(struct inet_frag_queue *q, void *a) | 70 | static bool lowpan_frag_match(const struct inet_frag_queue *q, const void *a) |
| 73 | { | 71 | { |
| 74 | struct lowpan_frag_queue *fq; | 72 | const struct lowpan_frag_queue *fq; |
| 75 | struct lowpan_create_arg *arg = a; | 73 | const struct lowpan_create_arg *arg = a; |
| 76 | 74 | ||
| 77 | fq = container_of(q, struct lowpan_frag_queue, q); | 75 | fq = container_of(q, struct lowpan_frag_queue, q); |
| 78 | return fq->tag == arg->tag && fq->d_size == arg->d_size && | 76 | return fq->tag == arg->tag && fq->d_size == arg->d_size && |
| @@ -80,10 +78,10 @@ static bool lowpan_frag_match(struct inet_frag_queue *q, void *a) | |||
| 80 | ieee802154_addr_equal(&fq->daddr, arg->dst); | 78 | ieee802154_addr_equal(&fq->daddr, arg->dst); |
| 81 | } | 79 | } |
| 82 | 80 | ||
| 83 | static void lowpan_frag_init(struct inet_frag_queue *q, void *a) | 81 | static void lowpan_frag_init(struct inet_frag_queue *q, const void *a) |
| 84 | { | 82 | { |
| 83 | const struct lowpan_create_arg *arg = a; | ||
| 85 | struct lowpan_frag_queue *fq; | 84 | struct lowpan_frag_queue *fq; |
| 86 | struct lowpan_create_arg *arg = a; | ||
| 87 | 85 | ||
| 88 | fq = container_of(q, struct lowpan_frag_queue, q); | 86 | fq = container_of(q, struct lowpan_frag_queue, q); |
| 89 | 87 | ||
| @@ -103,7 +101,7 @@ static void lowpan_frag_expire(unsigned long data) | |||
| 103 | 101 | ||
| 104 | spin_lock(&fq->q.lock); | 102 | spin_lock(&fq->q.lock); |
| 105 | 103 | ||
| 106 | if (fq->q.last_in & INET_FRAG_COMPLETE) | 104 | if (fq->q.flags & INET_FRAG_COMPLETE) |
| 107 | goto out; | 105 | goto out; |
| 108 | 106 | ||
| 109 | inet_frag_kill(&fq->q, &lowpan_frags); | 107 | inet_frag_kill(&fq->q, &lowpan_frags); |
| @@ -128,7 +126,6 @@ fq_find(struct net *net, const struct lowpan_frag_info *frag_info, | |||
| 128 | arg.src = src; | 126 | arg.src = src; |
| 129 | arg.dst = dst; | 127 | arg.dst = dst; |
| 130 | 128 | ||
| 131 | read_lock(&lowpan_frags.lock); | ||
| 132 | hash = lowpan_hash_frag(frag_info->d_tag, frag_info->d_size, src, dst); | 129 | hash = lowpan_hash_frag(frag_info->d_tag, frag_info->d_size, src, dst); |
| 133 | 130 | ||
| 134 | q = inet_frag_find(&ieee802154_lowpan->frags, | 131 | q = inet_frag_find(&ieee802154_lowpan->frags, |
| @@ -147,7 +144,7 @@ static int lowpan_frag_queue(struct lowpan_frag_queue *fq, | |||
| 147 | struct net_device *dev; | 144 | struct net_device *dev; |
| 148 | int end, offset; | 145 | int end, offset; |
| 149 | 146 | ||
| 150 | if (fq->q.last_in & INET_FRAG_COMPLETE) | 147 | if (fq->q.flags & INET_FRAG_COMPLETE) |
| 151 | goto err; | 148 | goto err; |
| 152 | 149 | ||
| 153 | offset = lowpan_cb(skb)->d_offset << 3; | 150 | offset = lowpan_cb(skb)->d_offset << 3; |
| @@ -159,14 +156,14 @@ static int lowpan_frag_queue(struct lowpan_frag_queue *fq, | |||
| 159 | * or have different end, the segment is corrupted. | 156 | * or have different end, the segment is corrupted. |
| 160 | */ | 157 | */ |
| 161 | if (end < fq->q.len || | 158 | if (end < fq->q.len || |
| 162 | ((fq->q.last_in & INET_FRAG_LAST_IN) && end != fq->q.len)) | 159 | ((fq->q.flags & INET_FRAG_LAST_IN) && end != fq->q.len)) |
| 163 | goto err; | 160 | goto err; |
| 164 | fq->q.last_in |= INET_FRAG_LAST_IN; | 161 | fq->q.flags |= INET_FRAG_LAST_IN; |
| 165 | fq->q.len = end; | 162 | fq->q.len = end; |
| 166 | } else { | 163 | } else { |
| 167 | if (end > fq->q.len) { | 164 | if (end > fq->q.len) { |
| 168 | /* Some bits beyond end -> corruption. */ | 165 | /* Some bits beyond end -> corruption. */ |
| 169 | if (fq->q.last_in & INET_FRAG_LAST_IN) | 166 | if (fq->q.flags & INET_FRAG_LAST_IN) |
| 170 | goto err; | 167 | goto err; |
| 171 | fq->q.len = end; | 168 | fq->q.len = end; |
| 172 | } | 169 | } |
| @@ -206,13 +203,13 @@ found: | |||
| 206 | if (frag_type == LOWPAN_DISPATCH_FRAG1) { | 203 | if (frag_type == LOWPAN_DISPATCH_FRAG1) { |
| 207 | /* Calculate uncomp. 6lowpan header to estimate full size */ | 204 | /* Calculate uncomp. 6lowpan header to estimate full size */ |
| 208 | fq->q.meat += lowpan_uncompress_size(skb, NULL); | 205 | fq->q.meat += lowpan_uncompress_size(skb, NULL); |
| 209 | fq->q.last_in |= INET_FRAG_FIRST_IN; | 206 | fq->q.flags |= INET_FRAG_FIRST_IN; |
| 210 | } else { | 207 | } else { |
| 211 | fq->q.meat += skb->len; | 208 | fq->q.meat += skb->len; |
| 212 | } | 209 | } |
| 213 | add_frag_mem_limit(&fq->q, skb->truesize); | 210 | add_frag_mem_limit(&fq->q, skb->truesize); |
| 214 | 211 | ||
| 215 | if (fq->q.last_in == (INET_FRAG_FIRST_IN | INET_FRAG_LAST_IN) && | 212 | if (fq->q.flags == (INET_FRAG_FIRST_IN | INET_FRAG_LAST_IN) && |
| 216 | fq->q.meat == fq->q.len) { | 213 | fq->q.meat == fq->q.len) { |
| 217 | int res; | 214 | int res; |
| 218 | unsigned long orefdst = skb->_skb_refdst; | 215 | unsigned long orefdst = skb->_skb_refdst; |
| @@ -223,7 +220,6 @@ found: | |||
| 223 | return res; | 220 | return res; |
| 224 | } | 221 | } |
| 225 | 222 | ||
| 226 | inet_frag_lru_move(&fq->q); | ||
| 227 | return -1; | 223 | return -1; |
| 228 | err: | 224 | err: |
| 229 | kfree_skb(skb); | 225 | kfree_skb(skb); |
| @@ -373,11 +369,10 @@ int lowpan_frag_rcv(struct sk_buff *skb, const u8 frag_type) | |||
| 373 | if (frag_info->d_size > ieee802154_lowpan->max_dsize) | 369 | if (frag_info->d_size > ieee802154_lowpan->max_dsize) |
| 374 | goto err; | 370 | goto err; |
| 375 | 371 | ||
| 376 | inet_frag_evictor(&ieee802154_lowpan->frags, &lowpan_frags, false); | ||
| 377 | |||
| 378 | fq = fq_find(net, frag_info, &source, &dest); | 372 | fq = fq_find(net, frag_info, &source, &dest); |
| 379 | if (fq != NULL) { | 373 | if (fq != NULL) { |
| 380 | int ret; | 374 | int ret; |
| 375 | |||
| 381 | spin_lock(&fq->q.lock); | 376 | spin_lock(&fq->q.lock); |
| 382 | ret = lowpan_frag_queue(fq, skb, frag_type); | 377 | ret = lowpan_frag_queue(fq, skb, frag_type); |
| 383 | spin_unlock(&fq->q.lock); | 378 | spin_unlock(&fq->q.lock); |
| @@ -393,20 +388,25 @@ err: | |||
| 393 | EXPORT_SYMBOL(lowpan_frag_rcv); | 388 | EXPORT_SYMBOL(lowpan_frag_rcv); |
| 394 | 389 | ||
| 395 | #ifdef CONFIG_SYSCTL | 390 | #ifdef CONFIG_SYSCTL |
| 391 | static int zero; | ||
| 392 | |||
| 396 | static struct ctl_table lowpan_frags_ns_ctl_table[] = { | 393 | static struct ctl_table lowpan_frags_ns_ctl_table[] = { |
| 397 | { | 394 | { |
| 398 | .procname = "6lowpanfrag_high_thresh", | 395 | .procname = "6lowpanfrag_high_thresh", |
| 399 | .data = &init_net.ieee802154_lowpan.frags.high_thresh, | 396 | .data = &init_net.ieee802154_lowpan.frags.high_thresh, |
| 400 | .maxlen = sizeof(int), | 397 | .maxlen = sizeof(int), |
| 401 | .mode = 0644, | 398 | .mode = 0644, |
| 402 | .proc_handler = proc_dointvec | 399 | .proc_handler = proc_dointvec_minmax, |
| 400 | .extra1 = &init_net.ieee802154_lowpan.frags.low_thresh | ||
| 403 | }, | 401 | }, |
| 404 | { | 402 | { |
| 405 | .procname = "6lowpanfrag_low_thresh", | 403 | .procname = "6lowpanfrag_low_thresh", |
| 406 | .data = &init_net.ieee802154_lowpan.frags.low_thresh, | 404 | .data = &init_net.ieee802154_lowpan.frags.low_thresh, |
| 407 | .maxlen = sizeof(int), | 405 | .maxlen = sizeof(int), |
| 408 | .mode = 0644, | 406 | .mode = 0644, |
| 409 | .proc_handler = proc_dointvec | 407 | .proc_handler = proc_dointvec_minmax, |
| 408 | .extra1 = &zero, | ||
| 409 | .extra2 = &init_net.ieee802154_lowpan.frags.high_thresh | ||
| 410 | }, | 410 | }, |
| 411 | { | 411 | { |
| 412 | .procname = "6lowpanfrag_time", | 412 | .procname = "6lowpanfrag_time", |
| @@ -425,10 +425,12 @@ static struct ctl_table lowpan_frags_ns_ctl_table[] = { | |||
| 425 | { } | 425 | { } |
| 426 | }; | 426 | }; |
| 427 | 427 | ||
| 428 | /* secret interval has been deprecated */ | ||
| 429 | static int lowpan_frags_secret_interval_unused; | ||
| 428 | static struct ctl_table lowpan_frags_ctl_table[] = { | 430 | static struct ctl_table lowpan_frags_ctl_table[] = { |
| 429 | { | 431 | { |
| 430 | .procname = "6lowpanfrag_secret_interval", | 432 | .procname = "6lowpanfrag_secret_interval", |
| 431 | .data = &lowpan_frags.secret_interval, | 433 | .data = &lowpan_frags_secret_interval_unused, |
| 432 | .maxlen = sizeof(int), | 434 | .maxlen = sizeof(int), |
| 433 | .mode = 0644, | 435 | .mode = 0644, |
| 434 | .proc_handler = proc_dointvec_jiffies, | 436 | .proc_handler = proc_dointvec_jiffies, |
| @@ -451,7 +453,10 @@ static int __net_init lowpan_frags_ns_sysctl_register(struct net *net) | |||
| 451 | goto err_alloc; | 453 | goto err_alloc; |
| 452 | 454 | ||
| 453 | table[0].data = &ieee802154_lowpan->frags.high_thresh; | 455 | table[0].data = &ieee802154_lowpan->frags.high_thresh; |
| 456 | table[0].extra1 = &ieee802154_lowpan->frags.low_thresh; | ||
| 457 | table[0].extra2 = &init_net.ieee802154_lowpan.frags.high_thresh; | ||
| 454 | table[1].data = &ieee802154_lowpan->frags.low_thresh; | 458 | table[1].data = &ieee802154_lowpan->frags.low_thresh; |
| 459 | table[1].extra2 = &ieee802154_lowpan->frags.high_thresh; | ||
| 455 | table[2].data = &ieee802154_lowpan->frags.timeout; | 460 | table[2].data = &ieee802154_lowpan->frags.timeout; |
| 456 | table[3].data = &ieee802154_lowpan->max_dsize; | 461 | table[3].data = &ieee802154_lowpan->max_dsize; |
| 457 | 462 | ||
| @@ -568,8 +573,10 @@ int __init lowpan_net_frag_init(void) | |||
| 568 | lowpan_frags.qsize = sizeof(struct frag_queue); | 573 | lowpan_frags.qsize = sizeof(struct frag_queue); |
| 569 | lowpan_frags.match = lowpan_frag_match; | 574 | lowpan_frags.match = lowpan_frag_match; |
| 570 | lowpan_frags.frag_expire = lowpan_frag_expire; | 575 | lowpan_frags.frag_expire = lowpan_frag_expire; |
| 571 | lowpan_frags.secret_interval = 10 * 60 * HZ; | 576 | lowpan_frags.frags_cache_name = lowpan_frags_cache_name; |
| 572 | inet_frags_init(&lowpan_frags); | 577 | ret = inet_frags_init(&lowpan_frags); |
| 578 | if (ret) | ||
| 579 | goto err_pernet; | ||
| 573 | 580 | ||
| 574 | return ret; | 581 | return ret; |
| 575 | err_pernet: | 582 | err_pernet: |
diff --git a/net/ieee802154/wpan-class.c b/net/ieee802154/wpan-class.c index 8d6f6704da84..4955e0fe5883 100644 --- a/net/ieee802154/wpan-class.c +++ b/net/ieee802154/wpan-class.c | |||
| @@ -48,7 +48,8 @@ MASTER_SHOW(transmit_power, "%d +- 1 dB"); | |||
| 48 | MASTER_SHOW(cca_mode, "%d"); | 48 | MASTER_SHOW(cca_mode, "%d"); |
| 49 | 49 | ||
| 50 | static ssize_t channels_supported_show(struct device *dev, | 50 | static ssize_t channels_supported_show(struct device *dev, |
| 51 | struct device_attribute *attr, char *buf) | 51 | struct device_attribute *attr, |
| 52 | char *buf) | ||
| 52 | { | 53 | { |
| 53 | struct wpan_phy *phy = container_of(dev, struct wpan_phy, dev); | 54 | struct wpan_phy *phy = container_of(dev, struct wpan_phy, dev); |
| 54 | int ret; | 55 | int ret; |
| @@ -57,7 +58,7 @@ static ssize_t channels_supported_show(struct device *dev, | |||
| 57 | mutex_lock(&phy->pib_lock); | 58 | mutex_lock(&phy->pib_lock); |
| 58 | for (i = 0; i < 32; i++) { | 59 | for (i = 0; i < 32; i++) { |
| 59 | ret = snprintf(buf + len, PAGE_SIZE - len, | 60 | ret = snprintf(buf + len, PAGE_SIZE - len, |
| 60 | "%#09x\n", phy->channels_supported[i]); | 61 | "%#09x\n", phy->channels_supported[i]); |
| 61 | if (ret < 0) | 62 | if (ret < 0) |
| 62 | break; | 63 | break; |
| 63 | len += ret; | 64 | len += ret; |
| @@ -80,6 +81,7 @@ ATTRIBUTE_GROUPS(pmib); | |||
| 80 | static void wpan_phy_release(struct device *d) | 81 | static void wpan_phy_release(struct device *d) |
| 81 | { | 82 | { |
| 82 | struct wpan_phy *phy = container_of(d, struct wpan_phy, dev); | 83 | struct wpan_phy *phy = container_of(d, struct wpan_phy, dev); |
| 84 | |||
| 83 | kfree(phy); | 85 | kfree(phy); |
| 84 | } | 86 | } |
| 85 | 87 | ||
| @@ -121,11 +123,12 @@ static int wpan_phy_iter(struct device *dev, void *_data) | |||
| 121 | { | 123 | { |
| 122 | struct wpan_phy_iter_data *wpid = _data; | 124 | struct wpan_phy_iter_data *wpid = _data; |
| 123 | struct wpan_phy *phy = container_of(dev, struct wpan_phy, dev); | 125 | struct wpan_phy *phy = container_of(dev, struct wpan_phy, dev); |
| 126 | |||
| 124 | return wpid->fn(phy, wpid->data); | 127 | return wpid->fn(phy, wpid->data); |
| 125 | } | 128 | } |
| 126 | 129 | ||
| 127 | int wpan_phy_for_each(int (*fn)(struct wpan_phy *phy, void *data), | 130 | int wpan_phy_for_each(int (*fn)(struct wpan_phy *phy, void *data), |
| 128 | void *data) | 131 | void *data) |
| 129 | { | 132 | { |
| 130 | struct wpan_phy_iter_data wpid = { | 133 | struct wpan_phy_iter_data wpid = { |
| 131 | .fn = fn, | 134 | .fn = fn, |
| @@ -197,6 +200,7 @@ EXPORT_SYMBOL(wpan_phy_free); | |||
| 197 | static int __init wpan_phy_class_init(void) | 200 | static int __init wpan_phy_class_init(void) |
| 198 | { | 201 | { |
| 199 | int rc; | 202 | int rc; |
| 203 | |||
| 200 | rc = class_register(&wpan_phy_class); | 204 | rc = class_register(&wpan_phy_class); |
| 201 | if (rc) | 205 | if (rc) |
| 202 | goto err; | 206 | goto err; |
diff --git a/net/ipv4/Kconfig b/net/ipv4/Kconfig index 05c57f0fcabe..dbc10d84161f 100644 --- a/net/ipv4/Kconfig +++ b/net/ipv4/Kconfig | |||
| @@ -307,6 +307,10 @@ config NET_IPVTI | |||
| 307 | the notion of a secure tunnel for IPSEC and then use routing protocol | 307 | the notion of a secure tunnel for IPSEC and then use routing protocol |
| 308 | on top. | 308 | on top. |
| 309 | 309 | ||
| 310 | config NET_UDP_TUNNEL | ||
| 311 | tristate | ||
| 312 | default n | ||
| 313 | |||
| 310 | config INET_AH | 314 | config INET_AH |
| 311 | tristate "IP: AH transformation" | 315 | tristate "IP: AH transformation" |
| 312 | select XFRM_ALGO | 316 | select XFRM_ALGO |
diff --git a/net/ipv4/Makefile b/net/ipv4/Makefile index f032688d20d3..8ee1cd4053ee 100644 --- a/net/ipv4/Makefile +++ b/net/ipv4/Makefile | |||
| @@ -22,6 +22,7 @@ obj-$(CONFIG_NET_IPIP) += ipip.o | |||
| 22 | gre-y := gre_demux.o | 22 | gre-y := gre_demux.o |
| 23 | obj-$(CONFIG_NET_IPGRE_DEMUX) += gre.o | 23 | obj-$(CONFIG_NET_IPGRE_DEMUX) += gre.o |
| 24 | obj-$(CONFIG_NET_IPGRE) += ip_gre.o | 24 | obj-$(CONFIG_NET_IPGRE) += ip_gre.o |
| 25 | obj-$(CONFIG_NET_UDP_TUNNEL) += udp_tunnel.o | ||
| 25 | obj-$(CONFIG_NET_IPVTI) += ip_vti.o | 26 | obj-$(CONFIG_NET_IPVTI) += ip_vti.o |
| 26 | obj-$(CONFIG_SYN_COOKIES) += syncookies.o | 27 | obj-$(CONFIG_SYN_COOKIES) += syncookies.o |
| 27 | obj-$(CONFIG_INET_AH) += ah4.o | 28 | obj-$(CONFIG_INET_AH) += ah4.o |
diff --git a/net/ipv4/cipso_ipv4.c b/net/ipv4/cipso_ipv4.c index 69e77c8ff285..05b708bbdb0d 100644 --- a/net/ipv4/cipso_ipv4.c +++ b/net/ipv4/cipso_ipv4.c | |||
| @@ -890,8 +890,8 @@ static int cipso_v4_map_cat_rbm_hton(const struct cipso_v4_doi *doi_def, | |||
| 890 | } | 890 | } |
| 891 | 891 | ||
| 892 | for (;;) { | 892 | for (;;) { |
| 893 | host_spot = netlbl_secattr_catmap_walk(secattr->attr.mls.cat, | 893 | host_spot = netlbl_catmap_walk(secattr->attr.mls.cat, |
| 894 | host_spot + 1); | 894 | host_spot + 1); |
| 895 | if (host_spot < 0) | 895 | if (host_spot < 0) |
| 896 | break; | 896 | break; |
| 897 | 897 | ||
| @@ -973,7 +973,7 @@ static int cipso_v4_map_cat_rbm_ntoh(const struct cipso_v4_doi *doi_def, | |||
| 973 | return -EPERM; | 973 | return -EPERM; |
| 974 | break; | 974 | break; |
| 975 | } | 975 | } |
| 976 | ret_val = netlbl_secattr_catmap_setbit(secattr->attr.mls.cat, | 976 | ret_val = netlbl_catmap_setbit(&secattr->attr.mls.cat, |
| 977 | host_spot, | 977 | host_spot, |
| 978 | GFP_ATOMIC); | 978 | GFP_ATOMIC); |
| 979 | if (ret_val != 0) | 979 | if (ret_val != 0) |
| @@ -1039,8 +1039,7 @@ static int cipso_v4_map_cat_enum_hton(const struct cipso_v4_doi *doi_def, | |||
| 1039 | u32 cat_iter = 0; | 1039 | u32 cat_iter = 0; |
| 1040 | 1040 | ||
| 1041 | for (;;) { | 1041 | for (;;) { |
| 1042 | cat = netlbl_secattr_catmap_walk(secattr->attr.mls.cat, | 1042 | cat = netlbl_catmap_walk(secattr->attr.mls.cat, cat + 1); |
| 1043 | cat + 1); | ||
| 1044 | if (cat < 0) | 1043 | if (cat < 0) |
| 1045 | break; | 1044 | break; |
| 1046 | if ((cat_iter + 2) > net_cat_len) | 1045 | if ((cat_iter + 2) > net_cat_len) |
| @@ -1075,9 +1074,9 @@ static int cipso_v4_map_cat_enum_ntoh(const struct cipso_v4_doi *doi_def, | |||
| 1075 | u32 iter; | 1074 | u32 iter; |
| 1076 | 1075 | ||
| 1077 | for (iter = 0; iter < net_cat_len; iter += 2) { | 1076 | for (iter = 0; iter < net_cat_len; iter += 2) { |
| 1078 | ret_val = netlbl_secattr_catmap_setbit(secattr->attr.mls.cat, | 1077 | ret_val = netlbl_catmap_setbit(&secattr->attr.mls.cat, |
| 1079 | get_unaligned_be16(&net_cat[iter]), | 1078 | get_unaligned_be16(&net_cat[iter]), |
| 1080 | GFP_ATOMIC); | 1079 | GFP_ATOMIC); |
| 1081 | if (ret_val != 0) | 1080 | if (ret_val != 0) |
| 1082 | return ret_val; | 1081 | return ret_val; |
| 1083 | } | 1082 | } |
| @@ -1155,8 +1154,7 @@ static int cipso_v4_map_cat_rng_hton(const struct cipso_v4_doi *doi_def, | |||
| 1155 | return -ENOSPC; | 1154 | return -ENOSPC; |
| 1156 | 1155 | ||
| 1157 | for (;;) { | 1156 | for (;;) { |
| 1158 | iter = netlbl_secattr_catmap_walk(secattr->attr.mls.cat, | 1157 | iter = netlbl_catmap_walk(secattr->attr.mls.cat, iter + 1); |
| 1159 | iter + 1); | ||
| 1160 | if (iter < 0) | 1158 | if (iter < 0) |
| 1161 | break; | 1159 | break; |
| 1162 | cat_size += (iter == 0 ? 0 : sizeof(u16)); | 1160 | cat_size += (iter == 0 ? 0 : sizeof(u16)); |
| @@ -1164,8 +1162,7 @@ static int cipso_v4_map_cat_rng_hton(const struct cipso_v4_doi *doi_def, | |||
| 1164 | return -ENOSPC; | 1162 | return -ENOSPC; |
| 1165 | array[array_cnt++] = iter; | 1163 | array[array_cnt++] = iter; |
| 1166 | 1164 | ||
| 1167 | iter = netlbl_secattr_catmap_walk_rng(secattr->attr.mls.cat, | 1165 | iter = netlbl_catmap_walkrng(secattr->attr.mls.cat, iter); |
| 1168 | iter); | ||
| 1169 | if (iter < 0) | 1166 | if (iter < 0) |
| 1170 | return -EFAULT; | 1167 | return -EFAULT; |
| 1171 | cat_size += sizeof(u16); | 1168 | cat_size += sizeof(u16); |
| @@ -1217,10 +1214,10 @@ static int cipso_v4_map_cat_rng_ntoh(const struct cipso_v4_doi *doi_def, | |||
| 1217 | else | 1214 | else |
| 1218 | cat_low = 0; | 1215 | cat_low = 0; |
| 1219 | 1216 | ||
| 1220 | ret_val = netlbl_secattr_catmap_setrng(secattr->attr.mls.cat, | 1217 | ret_val = netlbl_catmap_setrng(&secattr->attr.mls.cat, |
| 1221 | cat_low, | 1218 | cat_low, |
| 1222 | cat_high, | 1219 | cat_high, |
| 1223 | GFP_ATOMIC); | 1220 | GFP_ATOMIC); |
| 1224 | if (ret_val != 0) | 1221 | if (ret_val != 0) |
| 1225 | return ret_val; | 1222 | return ret_val; |
| 1226 | } | 1223 | } |
| @@ -1335,16 +1332,12 @@ static int cipso_v4_parsetag_rbm(const struct cipso_v4_doi *doi_def, | |||
| 1335 | secattr->flags |= NETLBL_SECATTR_MLS_LVL; | 1332 | secattr->flags |= NETLBL_SECATTR_MLS_LVL; |
| 1336 | 1333 | ||
| 1337 | if (tag_len > 4) { | 1334 | if (tag_len > 4) { |
| 1338 | secattr->attr.mls.cat = netlbl_secattr_catmap_alloc(GFP_ATOMIC); | ||
| 1339 | if (secattr->attr.mls.cat == NULL) | ||
| 1340 | return -ENOMEM; | ||
| 1341 | |||
| 1342 | ret_val = cipso_v4_map_cat_rbm_ntoh(doi_def, | 1335 | ret_val = cipso_v4_map_cat_rbm_ntoh(doi_def, |
| 1343 | &tag[4], | 1336 | &tag[4], |
| 1344 | tag_len - 4, | 1337 | tag_len - 4, |
| 1345 | secattr); | 1338 | secattr); |
| 1346 | if (ret_val != 0) { | 1339 | if (ret_val != 0) { |
| 1347 | netlbl_secattr_catmap_free(secattr->attr.mls.cat); | 1340 | netlbl_catmap_free(secattr->attr.mls.cat); |
| 1348 | return ret_val; | 1341 | return ret_val; |
| 1349 | } | 1342 | } |
| 1350 | 1343 | ||
| @@ -1430,16 +1423,12 @@ static int cipso_v4_parsetag_enum(const struct cipso_v4_doi *doi_def, | |||
| 1430 | secattr->flags |= NETLBL_SECATTR_MLS_LVL; | 1423 | secattr->flags |= NETLBL_SECATTR_MLS_LVL; |
| 1431 | 1424 | ||
| 1432 | if (tag_len > 4) { | 1425 | if (tag_len > 4) { |
| 1433 | secattr->attr.mls.cat = netlbl_secattr_catmap_alloc(GFP_ATOMIC); | ||
| 1434 | if (secattr->attr.mls.cat == NULL) | ||
| 1435 | return -ENOMEM; | ||
| 1436 | |||
| 1437 | ret_val = cipso_v4_map_cat_enum_ntoh(doi_def, | 1426 | ret_val = cipso_v4_map_cat_enum_ntoh(doi_def, |
| 1438 | &tag[4], | 1427 | &tag[4], |
| 1439 | tag_len - 4, | 1428 | tag_len - 4, |
| 1440 | secattr); | 1429 | secattr); |
| 1441 | if (ret_val != 0) { | 1430 | if (ret_val != 0) { |
| 1442 | netlbl_secattr_catmap_free(secattr->attr.mls.cat); | 1431 | netlbl_catmap_free(secattr->attr.mls.cat); |
| 1443 | return ret_val; | 1432 | return ret_val; |
| 1444 | } | 1433 | } |
| 1445 | 1434 | ||
| @@ -1524,16 +1513,12 @@ static int cipso_v4_parsetag_rng(const struct cipso_v4_doi *doi_def, | |||
| 1524 | secattr->flags |= NETLBL_SECATTR_MLS_LVL; | 1513 | secattr->flags |= NETLBL_SECATTR_MLS_LVL; |
| 1525 | 1514 | ||
| 1526 | if (tag_len > 4) { | 1515 | if (tag_len > 4) { |
| 1527 | secattr->attr.mls.cat = netlbl_secattr_catmap_alloc(GFP_ATOMIC); | ||
| 1528 | if (secattr->attr.mls.cat == NULL) | ||
| 1529 | return -ENOMEM; | ||
| 1530 | |||
| 1531 | ret_val = cipso_v4_map_cat_rng_ntoh(doi_def, | 1516 | ret_val = cipso_v4_map_cat_rng_ntoh(doi_def, |
| 1532 | &tag[4], | 1517 | &tag[4], |
| 1533 | tag_len - 4, | 1518 | tag_len - 4, |
| 1534 | secattr); | 1519 | secattr); |
| 1535 | if (ret_val != 0) { | 1520 | if (ret_val != 0) { |
| 1536 | netlbl_secattr_catmap_free(secattr->attr.mls.cat); | 1521 | netlbl_catmap_free(secattr->attr.mls.cat); |
| 1537 | return ret_val; | 1522 | return ret_val; |
| 1538 | } | 1523 | } |
| 1539 | 1524 | ||
diff --git a/net/ipv4/datagram.c b/net/ipv4/datagram.c index a3095fdefbed..90c0e8386116 100644 --- a/net/ipv4/datagram.c +++ b/net/ipv4/datagram.c | |||
| @@ -76,6 +76,7 @@ int ip4_datagram_connect(struct sock *sk, struct sockaddr *uaddr, int addr_len) | |||
| 76 | inet->inet_daddr = fl4->daddr; | 76 | inet->inet_daddr = fl4->daddr; |
| 77 | inet->inet_dport = usin->sin_port; | 77 | inet->inet_dport = usin->sin_port; |
| 78 | sk->sk_state = TCP_ESTABLISHED; | 78 | sk->sk_state = TCP_ESTABLISHED; |
| 79 | inet_set_txhash(sk); | ||
| 79 | inet->inet_id = jiffies; | 80 | inet->inet_id = jiffies; |
| 80 | 81 | ||
| 81 | sk_dst_set(sk, &rt->dst); | 82 | sk_dst_set(sk, &rt->dst); |
diff --git a/net/ipv4/devinet.c b/net/ipv4/devinet.c index e9449376b58e..214882e7d6de 100644 --- a/net/ipv4/devinet.c +++ b/net/ipv4/devinet.c | |||
| @@ -180,11 +180,12 @@ static BLOCKING_NOTIFIER_HEAD(inetaddr_chain); | |||
| 180 | static void inet_del_ifa(struct in_device *in_dev, struct in_ifaddr **ifap, | 180 | static void inet_del_ifa(struct in_device *in_dev, struct in_ifaddr **ifap, |
| 181 | int destroy); | 181 | int destroy); |
| 182 | #ifdef CONFIG_SYSCTL | 182 | #ifdef CONFIG_SYSCTL |
| 183 | static void devinet_sysctl_register(struct in_device *idev); | 183 | static int devinet_sysctl_register(struct in_device *idev); |
| 184 | static void devinet_sysctl_unregister(struct in_device *idev); | 184 | static void devinet_sysctl_unregister(struct in_device *idev); |
| 185 | #else | 185 | #else |
| 186 | static void devinet_sysctl_register(struct in_device *idev) | 186 | static int devinet_sysctl_register(struct in_device *idev) |
| 187 | { | 187 | { |
| 188 | return 0; | ||
| 188 | } | 189 | } |
| 189 | static void devinet_sysctl_unregister(struct in_device *idev) | 190 | static void devinet_sysctl_unregister(struct in_device *idev) |
| 190 | { | 191 | { |
| @@ -232,6 +233,7 @@ EXPORT_SYMBOL(in_dev_finish_destroy); | |||
| 232 | static struct in_device *inetdev_init(struct net_device *dev) | 233 | static struct in_device *inetdev_init(struct net_device *dev) |
| 233 | { | 234 | { |
| 234 | struct in_device *in_dev; | 235 | struct in_device *in_dev; |
| 236 | int err = -ENOMEM; | ||
| 235 | 237 | ||
| 236 | ASSERT_RTNL(); | 238 | ASSERT_RTNL(); |
| 237 | 239 | ||
| @@ -252,7 +254,13 @@ static struct in_device *inetdev_init(struct net_device *dev) | |||
| 252 | /* Account for reference dev->ip_ptr (below) */ | 254 | /* Account for reference dev->ip_ptr (below) */ |
| 253 | in_dev_hold(in_dev); | 255 | in_dev_hold(in_dev); |
| 254 | 256 | ||
| 255 | devinet_sysctl_register(in_dev); | 257 | err = devinet_sysctl_register(in_dev); |
| 258 | if (err) { | ||
| 259 | in_dev->dead = 1; | ||
| 260 | in_dev_put(in_dev); | ||
| 261 | in_dev = NULL; | ||
| 262 | goto out; | ||
| 263 | } | ||
| 256 | ip_mc_init_dev(in_dev); | 264 | ip_mc_init_dev(in_dev); |
| 257 | if (dev->flags & IFF_UP) | 265 | if (dev->flags & IFF_UP) |
| 258 | ip_mc_up(in_dev); | 266 | ip_mc_up(in_dev); |
| @@ -260,7 +268,7 @@ static struct in_device *inetdev_init(struct net_device *dev) | |||
| 260 | /* we can receive as soon as ip_ptr is set -- do this last */ | 268 | /* we can receive as soon as ip_ptr is set -- do this last */ |
| 261 | rcu_assign_pointer(dev->ip_ptr, in_dev); | 269 | rcu_assign_pointer(dev->ip_ptr, in_dev); |
| 262 | out: | 270 | out: |
| 263 | return in_dev; | 271 | return in_dev ?: ERR_PTR(err); |
| 264 | out_kfree: | 272 | out_kfree: |
| 265 | kfree(in_dev); | 273 | kfree(in_dev); |
| 266 | in_dev = NULL; | 274 | in_dev = NULL; |
| @@ -1347,8 +1355,8 @@ static int inetdev_event(struct notifier_block *this, unsigned long event, | |||
| 1347 | if (!in_dev) { | 1355 | if (!in_dev) { |
| 1348 | if (event == NETDEV_REGISTER) { | 1356 | if (event == NETDEV_REGISTER) { |
| 1349 | in_dev = inetdev_init(dev); | 1357 | in_dev = inetdev_init(dev); |
| 1350 | if (!in_dev) | 1358 | if (IS_ERR(in_dev)) |
| 1351 | return notifier_from_errno(-ENOMEM); | 1359 | return notifier_from_errno(PTR_ERR(in_dev)); |
| 1352 | if (dev->flags & IFF_LOOPBACK) { | 1360 | if (dev->flags & IFF_LOOPBACK) { |
| 1353 | IN_DEV_CONF_SET(in_dev, NOXFRM, 1); | 1361 | IN_DEV_CONF_SET(in_dev, NOXFRM, 1); |
| 1354 | IN_DEV_CONF_SET(in_dev, NOPOLICY, 1); | 1362 | IN_DEV_CONF_SET(in_dev, NOPOLICY, 1); |
| @@ -2182,11 +2190,21 @@ static void __devinet_sysctl_unregister(struct ipv4_devconf *cnf) | |||
| 2182 | kfree(t); | 2190 | kfree(t); |
| 2183 | } | 2191 | } |
| 2184 | 2192 | ||
| 2185 | static void devinet_sysctl_register(struct in_device *idev) | 2193 | static int devinet_sysctl_register(struct in_device *idev) |
| 2186 | { | 2194 | { |
| 2187 | neigh_sysctl_register(idev->dev, idev->arp_parms, NULL); | 2195 | int err; |
| 2188 | __devinet_sysctl_register(dev_net(idev->dev), idev->dev->name, | 2196 | |
| 2197 | if (!sysctl_dev_name_is_allowed(idev->dev->name)) | ||
| 2198 | return -EINVAL; | ||
| 2199 | |||
| 2200 | err = neigh_sysctl_register(idev->dev, idev->arp_parms, NULL); | ||
| 2201 | if (err) | ||
| 2202 | return err; | ||
| 2203 | err = __devinet_sysctl_register(dev_net(idev->dev), idev->dev->name, | ||
| 2189 | &idev->cnf); | 2204 | &idev->cnf); |
| 2205 | if (err) | ||
| 2206 | neigh_sysctl_unregister(idev->arp_parms); | ||
| 2207 | return err; | ||
| 2190 | } | 2208 | } |
| 2191 | 2209 | ||
| 2192 | static void devinet_sysctl_unregister(struct in_device *idev) | 2210 | static void devinet_sysctl_unregister(struct in_device *idev) |
diff --git a/net/ipv4/fib_trie.c b/net/ipv4/fib_trie.c index 5afeb5aa4c7c..e9cb2588e416 100644 --- a/net/ipv4/fib_trie.c +++ b/net/ipv4/fib_trie.c | |||
| @@ -940,7 +940,7 @@ static void insert_leaf_info(struct hlist_head *head, struct leaf_info *new) | |||
| 940 | last = li; | 940 | last = li; |
| 941 | } | 941 | } |
| 942 | if (last) | 942 | if (last) |
| 943 | hlist_add_after_rcu(&last->hlist, &new->hlist); | 943 | hlist_add_behind_rcu(&new->hlist, &last->hlist); |
| 944 | else | 944 | else |
| 945 | hlist_add_before_rcu(&new->hlist, &li->hlist); | 945 | hlist_add_before_rcu(&new->hlist, &li->hlist); |
| 946 | } | 946 | } |
diff --git a/net/ipv4/gre_offload.c b/net/ipv4/gre_offload.c index f0bdd47bbbcb..6556263c8fa5 100644 --- a/net/ipv4/gre_offload.c +++ b/net/ipv4/gre_offload.c | |||
| @@ -74,7 +74,7 @@ static struct sk_buff *gre_gso_segment(struct sk_buff *skb, | |||
| 74 | /* segment inner packet. */ | 74 | /* segment inner packet. */ |
| 75 | enc_features = skb->dev->hw_enc_features & netif_skb_features(skb); | 75 | enc_features = skb->dev->hw_enc_features & netif_skb_features(skb); |
| 76 | segs = skb_mac_gso_segment(skb, enc_features); | 76 | segs = skb_mac_gso_segment(skb, enc_features); |
| 77 | if (!segs || IS_ERR(segs)) { | 77 | if (IS_ERR_OR_NULL(segs)) { |
| 78 | skb_gso_error_unwind(skb, protocol, ghl, mac_offset, mac_len); | 78 | skb_gso_error_unwind(skb, protocol, ghl, mac_offset, mac_len); |
| 79 | goto out; | 79 | goto out; |
| 80 | } | 80 | } |
diff --git a/net/ipv4/icmp.c b/net/ipv4/icmp.c index 42b7bcf8045b..ea7d4afe8205 100644 --- a/net/ipv4/icmp.c +++ b/net/ipv4/icmp.c | |||
| @@ -663,16 +663,16 @@ static void icmp_socket_deliver(struct sk_buff *skb, u32 info) | |||
| 663 | /* Checkin full IP header plus 8 bytes of protocol to | 663 | /* Checkin full IP header plus 8 bytes of protocol to |
| 664 | * avoid additional coding at protocol handlers. | 664 | * avoid additional coding at protocol handlers. |
| 665 | */ | 665 | */ |
| 666 | if (!pskb_may_pull(skb, iph->ihl * 4 + 8)) | 666 | if (!pskb_may_pull(skb, iph->ihl * 4 + 8)) { |
| 667 | ICMP_INC_STATS_BH(dev_net(skb->dev), ICMP_MIB_INERRORS); | ||
| 667 | return; | 668 | return; |
| 669 | } | ||
| 668 | 670 | ||
| 669 | raw_icmp_error(skb, protocol, info); | 671 | raw_icmp_error(skb, protocol, info); |
| 670 | 672 | ||
| 671 | rcu_read_lock(); | ||
| 672 | ipprot = rcu_dereference(inet_protos[protocol]); | 673 | ipprot = rcu_dereference(inet_protos[protocol]); |
| 673 | if (ipprot && ipprot->err_handler) | 674 | if (ipprot && ipprot->err_handler) |
| 674 | ipprot->err_handler(skb, info); | 675 | ipprot->err_handler(skb, info); |
| 675 | rcu_read_unlock(); | ||
| 676 | } | 676 | } |
| 677 | 677 | ||
| 678 | static bool icmp_tag_validation(int proto) | 678 | static bool icmp_tag_validation(int proto) |
diff --git a/net/ipv4/igmp.c b/net/ipv4/igmp.c index db710b059bab..f10eab462282 100644 --- a/net/ipv4/igmp.c +++ b/net/ipv4/igmp.c | |||
| @@ -1321,7 +1321,7 @@ void ip_mc_inc_group(struct in_device *in_dev, __be32 addr) | |||
| 1321 | atomic_set(&im->refcnt, 1); | 1321 | atomic_set(&im->refcnt, 1); |
| 1322 | spin_lock_init(&im->lock); | 1322 | spin_lock_init(&im->lock); |
| 1323 | #ifdef CONFIG_IP_MULTICAST | 1323 | #ifdef CONFIG_IP_MULTICAST |
| 1324 | setup_timer(&im->timer, &igmp_timer_expire, (unsigned long)im); | 1324 | setup_timer(&im->timer, igmp_timer_expire, (unsigned long)im); |
| 1325 | im->unsolicit_count = IGMP_Unsolicited_Report_Count; | 1325 | im->unsolicit_count = IGMP_Unsolicited_Report_Count; |
| 1326 | #endif | 1326 | #endif |
| 1327 | 1327 | ||
diff --git a/net/ipv4/inet_fragment.c b/net/ipv4/inet_fragment.c index 3b01959bf4bb..9eb89f3f0ee4 100644 --- a/net/ipv4/inet_fragment.c +++ b/net/ipv4/inet_fragment.c | |||
| @@ -25,6 +25,12 @@ | |||
| 25 | #include <net/inet_frag.h> | 25 | #include <net/inet_frag.h> |
| 26 | #include <net/inet_ecn.h> | 26 | #include <net/inet_ecn.h> |
| 27 | 27 | ||
| 28 | #define INETFRAGS_EVICT_BUCKETS 128 | ||
| 29 | #define INETFRAGS_EVICT_MAX 512 | ||
| 30 | |||
| 31 | /* don't rebuild inetfrag table with new secret more often than this */ | ||
| 32 | #define INETFRAGS_MIN_REBUILD_INTERVAL (5 * HZ) | ||
| 33 | |||
| 28 | /* Given the OR values of all fragments, apply RFC 3168 5.3 requirements | 34 | /* Given the OR values of all fragments, apply RFC 3168 5.3 requirements |
| 29 | * Value : 0xff if frame should be dropped. | 35 | * Value : 0xff if frame should be dropped. |
| 30 | * 0 or INET_ECN_CE value, to be ORed in to final iph->tos field | 36 | * 0 or INET_ECN_CE value, to be ORed in to final iph->tos field |
| @@ -46,24 +52,39 @@ const u8 ip_frag_ecn_table[16] = { | |||
| 46 | }; | 52 | }; |
| 47 | EXPORT_SYMBOL(ip_frag_ecn_table); | 53 | EXPORT_SYMBOL(ip_frag_ecn_table); |
| 48 | 54 | ||
| 49 | static void inet_frag_secret_rebuild(unsigned long dummy) | 55 | static unsigned int |
| 56 | inet_frag_hashfn(const struct inet_frags *f, const struct inet_frag_queue *q) | ||
| 57 | { | ||
| 58 | return f->hashfn(q) & (INETFRAGS_HASHSZ - 1); | ||
| 59 | } | ||
| 60 | |||
| 61 | static bool inet_frag_may_rebuild(struct inet_frags *f) | ||
| 62 | { | ||
| 63 | return time_after(jiffies, | ||
| 64 | f->last_rebuild_jiffies + INETFRAGS_MIN_REBUILD_INTERVAL); | ||
| 65 | } | ||
| 66 | |||
| 67 | static void inet_frag_secret_rebuild(struct inet_frags *f) | ||
| 50 | { | 68 | { |
| 51 | struct inet_frags *f = (struct inet_frags *)dummy; | ||
| 52 | unsigned long now = jiffies; | ||
| 53 | int i; | 69 | int i; |
| 54 | 70 | ||
| 55 | /* Per bucket lock NOT needed here, due to write lock protection */ | 71 | write_seqlock_bh(&f->rnd_seqlock); |
| 56 | write_lock(&f->lock); | 72 | |
| 73 | if (!inet_frag_may_rebuild(f)) | ||
| 74 | goto out; | ||
| 57 | 75 | ||
| 58 | get_random_bytes(&f->rnd, sizeof(u32)); | 76 | get_random_bytes(&f->rnd, sizeof(u32)); |
| 77 | |||
| 59 | for (i = 0; i < INETFRAGS_HASHSZ; i++) { | 78 | for (i = 0; i < INETFRAGS_HASHSZ; i++) { |
| 60 | struct inet_frag_bucket *hb; | 79 | struct inet_frag_bucket *hb; |
| 61 | struct inet_frag_queue *q; | 80 | struct inet_frag_queue *q; |
| 62 | struct hlist_node *n; | 81 | struct hlist_node *n; |
| 63 | 82 | ||
| 64 | hb = &f->hash[i]; | 83 | hb = &f->hash[i]; |
| 84 | spin_lock(&hb->chain_lock); | ||
| 85 | |||
| 65 | hlist_for_each_entry_safe(q, n, &hb->chain, list) { | 86 | hlist_for_each_entry_safe(q, n, &hb->chain, list) { |
| 66 | unsigned int hval = f->hashfn(q); | 87 | unsigned int hval = inet_frag_hashfn(f, q); |
| 67 | 88 | ||
| 68 | if (hval != i) { | 89 | if (hval != i) { |
| 69 | struct inet_frag_bucket *hb_dest; | 90 | struct inet_frag_bucket *hb_dest; |
| @@ -72,76 +93,200 @@ static void inet_frag_secret_rebuild(unsigned long dummy) | |||
| 72 | 93 | ||
| 73 | /* Relink to new hash chain. */ | 94 | /* Relink to new hash chain. */ |
| 74 | hb_dest = &f->hash[hval]; | 95 | hb_dest = &f->hash[hval]; |
| 96 | |||
| 97 | /* This is the only place where we take | ||
| 98 | * another chain_lock while already holding | ||
| 99 | * one. As this will not run concurrently, | ||
| 100 | * we cannot deadlock on hb_dest lock below, if its | ||
| 101 | * already locked it will be released soon since | ||
| 102 | * other caller cannot be waiting for hb lock | ||
| 103 | * that we've taken above. | ||
| 104 | */ | ||
| 105 | spin_lock_nested(&hb_dest->chain_lock, | ||
| 106 | SINGLE_DEPTH_NESTING); | ||
| 75 | hlist_add_head(&q->list, &hb_dest->chain); | 107 | hlist_add_head(&q->list, &hb_dest->chain); |
| 108 | spin_unlock(&hb_dest->chain_lock); | ||
| 76 | } | 109 | } |
| 77 | } | 110 | } |
| 111 | spin_unlock(&hb->chain_lock); | ||
| 112 | } | ||
| 113 | |||
| 114 | f->rebuild = false; | ||
| 115 | f->last_rebuild_jiffies = jiffies; | ||
| 116 | out: | ||
| 117 | write_sequnlock_bh(&f->rnd_seqlock); | ||
| 118 | } | ||
| 119 | |||
| 120 | static bool inet_fragq_should_evict(const struct inet_frag_queue *q) | ||
| 121 | { | ||
| 122 | return q->net->low_thresh == 0 || | ||
| 123 | frag_mem_limit(q->net) >= q->net->low_thresh; | ||
| 124 | } | ||
| 125 | |||
| 126 | static unsigned int | ||
| 127 | inet_evict_bucket(struct inet_frags *f, struct inet_frag_bucket *hb) | ||
| 128 | { | ||
| 129 | struct inet_frag_queue *fq; | ||
| 130 | struct hlist_node *n; | ||
| 131 | unsigned int evicted = 0; | ||
| 132 | HLIST_HEAD(expired); | ||
| 133 | |||
| 134 | evict_again: | ||
| 135 | spin_lock(&hb->chain_lock); | ||
| 136 | |||
| 137 | hlist_for_each_entry_safe(fq, n, &hb->chain, list) { | ||
| 138 | if (!inet_fragq_should_evict(fq)) | ||
| 139 | continue; | ||
| 140 | |||
| 141 | if (!del_timer(&fq->timer)) { | ||
| 142 | /* q expiring right now thus increment its refcount so | ||
| 143 | * it won't be freed under us and wait until the timer | ||
| 144 | * has finished executing then destroy it | ||
| 145 | */ | ||
| 146 | atomic_inc(&fq->refcnt); | ||
| 147 | spin_unlock(&hb->chain_lock); | ||
| 148 | del_timer_sync(&fq->timer); | ||
| 149 | WARN_ON(atomic_read(&fq->refcnt) != 1); | ||
| 150 | inet_frag_put(fq, f); | ||
| 151 | goto evict_again; | ||
| 152 | } | ||
| 153 | |||
| 154 | fq->flags |= INET_FRAG_EVICTED; | ||
| 155 | hlist_del(&fq->list); | ||
| 156 | hlist_add_head(&fq->list, &expired); | ||
| 157 | ++evicted; | ||
| 78 | } | 158 | } |
| 79 | write_unlock(&f->lock); | ||
| 80 | 159 | ||
| 81 | mod_timer(&f->secret_timer, now + f->secret_interval); | 160 | spin_unlock(&hb->chain_lock); |
| 161 | |||
| 162 | hlist_for_each_entry_safe(fq, n, &expired, list) | ||
| 163 | f->frag_expire((unsigned long) fq); | ||
| 164 | |||
| 165 | return evicted; | ||
| 82 | } | 166 | } |
| 83 | 167 | ||
| 84 | void inet_frags_init(struct inet_frags *f) | 168 | static void inet_frag_worker(struct work_struct *work) |
| 169 | { | ||
| 170 | unsigned int budget = INETFRAGS_EVICT_BUCKETS; | ||
| 171 | unsigned int i, evicted = 0; | ||
| 172 | struct inet_frags *f; | ||
| 173 | |||
| 174 | f = container_of(work, struct inet_frags, frags_work); | ||
| 175 | |||
| 176 | BUILD_BUG_ON(INETFRAGS_EVICT_BUCKETS >= INETFRAGS_HASHSZ); | ||
| 177 | |||
| 178 | local_bh_disable(); | ||
| 179 | |||
| 180 | for (i = ACCESS_ONCE(f->next_bucket); budget; --budget) { | ||
| 181 | evicted += inet_evict_bucket(f, &f->hash[i]); | ||
| 182 | i = (i + 1) & (INETFRAGS_HASHSZ - 1); | ||
| 183 | if (evicted > INETFRAGS_EVICT_MAX) | ||
| 184 | break; | ||
| 185 | } | ||
| 186 | |||
| 187 | f->next_bucket = i; | ||
| 188 | |||
| 189 | local_bh_enable(); | ||
| 190 | |||
| 191 | if (f->rebuild && inet_frag_may_rebuild(f)) | ||
| 192 | inet_frag_secret_rebuild(f); | ||
| 193 | } | ||
| 194 | |||
| 195 | static void inet_frag_schedule_worker(struct inet_frags *f) | ||
| 196 | { | ||
| 197 | if (unlikely(!work_pending(&f->frags_work))) | ||
| 198 | schedule_work(&f->frags_work); | ||
| 199 | } | ||
| 200 | |||
| 201 | int inet_frags_init(struct inet_frags *f) | ||
| 85 | { | 202 | { |
| 86 | int i; | 203 | int i; |
| 87 | 204 | ||
| 205 | INIT_WORK(&f->frags_work, inet_frag_worker); | ||
| 206 | |||
| 88 | for (i = 0; i < INETFRAGS_HASHSZ; i++) { | 207 | for (i = 0; i < INETFRAGS_HASHSZ; i++) { |
| 89 | struct inet_frag_bucket *hb = &f->hash[i]; | 208 | struct inet_frag_bucket *hb = &f->hash[i]; |
| 90 | 209 | ||
| 91 | spin_lock_init(&hb->chain_lock); | 210 | spin_lock_init(&hb->chain_lock); |
| 92 | INIT_HLIST_HEAD(&hb->chain); | 211 | INIT_HLIST_HEAD(&hb->chain); |
| 93 | } | 212 | } |
| 94 | rwlock_init(&f->lock); | ||
| 95 | 213 | ||
| 96 | setup_timer(&f->secret_timer, inet_frag_secret_rebuild, | 214 | seqlock_init(&f->rnd_seqlock); |
| 97 | (unsigned long)f); | 215 | f->last_rebuild_jiffies = 0; |
| 98 | f->secret_timer.expires = jiffies + f->secret_interval; | 216 | f->frags_cachep = kmem_cache_create(f->frags_cache_name, f->qsize, 0, 0, |
| 99 | add_timer(&f->secret_timer); | 217 | NULL); |
| 218 | if (!f->frags_cachep) | ||
| 219 | return -ENOMEM; | ||
| 220 | |||
| 221 | return 0; | ||
| 100 | } | 222 | } |
| 101 | EXPORT_SYMBOL(inet_frags_init); | 223 | EXPORT_SYMBOL(inet_frags_init); |
| 102 | 224 | ||
| 103 | void inet_frags_init_net(struct netns_frags *nf) | 225 | void inet_frags_init_net(struct netns_frags *nf) |
| 104 | { | 226 | { |
| 105 | nf->nqueues = 0; | ||
| 106 | init_frag_mem_limit(nf); | 227 | init_frag_mem_limit(nf); |
| 107 | INIT_LIST_HEAD(&nf->lru_list); | ||
| 108 | spin_lock_init(&nf->lru_lock); | ||
| 109 | } | 228 | } |
| 110 | EXPORT_SYMBOL(inet_frags_init_net); | 229 | EXPORT_SYMBOL(inet_frags_init_net); |
| 111 | 230 | ||
| 112 | void inet_frags_fini(struct inet_frags *f) | 231 | void inet_frags_fini(struct inet_frags *f) |
| 113 | { | 232 | { |
| 114 | del_timer(&f->secret_timer); | 233 | cancel_work_sync(&f->frags_work); |
| 234 | kmem_cache_destroy(f->frags_cachep); | ||
| 115 | } | 235 | } |
| 116 | EXPORT_SYMBOL(inet_frags_fini); | 236 | EXPORT_SYMBOL(inet_frags_fini); |
| 117 | 237 | ||
| 118 | void inet_frags_exit_net(struct netns_frags *nf, struct inet_frags *f) | 238 | void inet_frags_exit_net(struct netns_frags *nf, struct inet_frags *f) |
| 119 | { | 239 | { |
| 120 | nf->low_thresh = 0; | 240 | unsigned int seq; |
| 241 | int i; | ||
| 121 | 242 | ||
| 243 | nf->low_thresh = 0; | ||
| 122 | local_bh_disable(); | 244 | local_bh_disable(); |
| 123 | inet_frag_evictor(nf, f, true); | 245 | |
| 246 | evict_again: | ||
| 247 | seq = read_seqbegin(&f->rnd_seqlock); | ||
| 248 | |||
| 249 | for (i = 0; i < INETFRAGS_HASHSZ ; i++) | ||
| 250 | inet_evict_bucket(f, &f->hash[i]); | ||
| 251 | |||
| 252 | if (read_seqretry(&f->rnd_seqlock, seq)) | ||
| 253 | goto evict_again; | ||
| 254 | |||
| 124 | local_bh_enable(); | 255 | local_bh_enable(); |
| 125 | 256 | ||
| 126 | percpu_counter_destroy(&nf->mem); | 257 | percpu_counter_destroy(&nf->mem); |
| 127 | } | 258 | } |
| 128 | EXPORT_SYMBOL(inet_frags_exit_net); | 259 | EXPORT_SYMBOL(inet_frags_exit_net); |
| 129 | 260 | ||
| 130 | static inline void fq_unlink(struct inet_frag_queue *fq, struct inet_frags *f) | 261 | static struct inet_frag_bucket * |
| 262 | get_frag_bucket_locked(struct inet_frag_queue *fq, struct inet_frags *f) | ||
| 263 | __acquires(hb->chain_lock) | ||
| 131 | { | 264 | { |
| 132 | struct inet_frag_bucket *hb; | 265 | struct inet_frag_bucket *hb; |
| 133 | unsigned int hash; | 266 | unsigned int seq, hash; |
| 267 | |||
| 268 | restart: | ||
| 269 | seq = read_seqbegin(&f->rnd_seqlock); | ||
| 134 | 270 | ||
| 135 | read_lock(&f->lock); | 271 | hash = inet_frag_hashfn(f, fq); |
| 136 | hash = f->hashfn(fq); | ||
| 137 | hb = &f->hash[hash]; | 272 | hb = &f->hash[hash]; |
| 138 | 273 | ||
| 139 | spin_lock(&hb->chain_lock); | 274 | spin_lock(&hb->chain_lock); |
| 275 | if (read_seqretry(&f->rnd_seqlock, seq)) { | ||
| 276 | spin_unlock(&hb->chain_lock); | ||
| 277 | goto restart; | ||
| 278 | } | ||
| 279 | |||
| 280 | return hb; | ||
| 281 | } | ||
| 282 | |||
| 283 | static inline void fq_unlink(struct inet_frag_queue *fq, struct inet_frags *f) | ||
| 284 | { | ||
| 285 | struct inet_frag_bucket *hb; | ||
| 286 | |||
| 287 | hb = get_frag_bucket_locked(fq, f); | ||
| 140 | hlist_del(&fq->list); | 288 | hlist_del(&fq->list); |
| 141 | spin_unlock(&hb->chain_lock); | 289 | spin_unlock(&hb->chain_lock); |
| 142 | |||
| 143 | read_unlock(&f->lock); | ||
| 144 | inet_frag_lru_del(fq); | ||
| 145 | } | 290 | } |
| 146 | 291 | ||
| 147 | void inet_frag_kill(struct inet_frag_queue *fq, struct inet_frags *f) | 292 | void inet_frag_kill(struct inet_frag_queue *fq, struct inet_frags *f) |
| @@ -149,30 +294,29 @@ void inet_frag_kill(struct inet_frag_queue *fq, struct inet_frags *f) | |||
| 149 | if (del_timer(&fq->timer)) | 294 | if (del_timer(&fq->timer)) |
| 150 | atomic_dec(&fq->refcnt); | 295 | atomic_dec(&fq->refcnt); |
| 151 | 296 | ||
| 152 | if (!(fq->last_in & INET_FRAG_COMPLETE)) { | 297 | if (!(fq->flags & INET_FRAG_COMPLETE)) { |
| 153 | fq_unlink(fq, f); | 298 | fq_unlink(fq, f); |
| 154 | atomic_dec(&fq->refcnt); | 299 | atomic_dec(&fq->refcnt); |
| 155 | fq->last_in |= INET_FRAG_COMPLETE; | 300 | fq->flags |= INET_FRAG_COMPLETE; |
| 156 | } | 301 | } |
| 157 | } | 302 | } |
| 158 | EXPORT_SYMBOL(inet_frag_kill); | 303 | EXPORT_SYMBOL(inet_frag_kill); |
| 159 | 304 | ||
| 160 | static inline void frag_kfree_skb(struct netns_frags *nf, struct inet_frags *f, | 305 | static inline void frag_kfree_skb(struct netns_frags *nf, struct inet_frags *f, |
| 161 | struct sk_buff *skb) | 306 | struct sk_buff *skb) |
| 162 | { | 307 | { |
| 163 | if (f->skb_free) | 308 | if (f->skb_free) |
| 164 | f->skb_free(skb); | 309 | f->skb_free(skb); |
| 165 | kfree_skb(skb); | 310 | kfree_skb(skb); |
| 166 | } | 311 | } |
| 167 | 312 | ||
| 168 | void inet_frag_destroy(struct inet_frag_queue *q, struct inet_frags *f, | 313 | void inet_frag_destroy(struct inet_frag_queue *q, struct inet_frags *f) |
| 169 | int *work) | ||
| 170 | { | 314 | { |
| 171 | struct sk_buff *fp; | 315 | struct sk_buff *fp; |
| 172 | struct netns_frags *nf; | 316 | struct netns_frags *nf; |
| 173 | unsigned int sum, sum_truesize = 0; | 317 | unsigned int sum, sum_truesize = 0; |
| 174 | 318 | ||
| 175 | WARN_ON(!(q->last_in & INET_FRAG_COMPLETE)); | 319 | WARN_ON(!(q->flags & INET_FRAG_COMPLETE)); |
| 176 | WARN_ON(del_timer(&q->timer) != 0); | 320 | WARN_ON(del_timer(&q->timer) != 0); |
| 177 | 321 | ||
| 178 | /* Release all fragment data. */ | 322 | /* Release all fragment data. */ |
| @@ -186,87 +330,32 @@ void inet_frag_destroy(struct inet_frag_queue *q, struct inet_frags *f, | |||
| 186 | fp = xp; | 330 | fp = xp; |
| 187 | } | 331 | } |
| 188 | sum = sum_truesize + f->qsize; | 332 | sum = sum_truesize + f->qsize; |
| 189 | if (work) | ||
| 190 | *work -= sum; | ||
| 191 | sub_frag_mem_limit(q, sum); | 333 | sub_frag_mem_limit(q, sum); |
| 192 | 334 | ||
| 193 | if (f->destructor) | 335 | if (f->destructor) |
| 194 | f->destructor(q); | 336 | f->destructor(q); |
| 195 | kfree(q); | 337 | kmem_cache_free(f->frags_cachep, q); |
| 196 | |||
| 197 | } | 338 | } |
| 198 | EXPORT_SYMBOL(inet_frag_destroy); | 339 | EXPORT_SYMBOL(inet_frag_destroy); |
| 199 | 340 | ||
| 200 | int inet_frag_evictor(struct netns_frags *nf, struct inet_frags *f, bool force) | ||
| 201 | { | ||
| 202 | struct inet_frag_queue *q; | ||
| 203 | int work, evicted = 0; | ||
| 204 | |||
| 205 | if (!force) { | ||
| 206 | if (frag_mem_limit(nf) <= nf->high_thresh) | ||
| 207 | return 0; | ||
| 208 | } | ||
| 209 | |||
| 210 | work = frag_mem_limit(nf) - nf->low_thresh; | ||
| 211 | while (work > 0 || force) { | ||
| 212 | spin_lock(&nf->lru_lock); | ||
| 213 | |||
| 214 | if (list_empty(&nf->lru_list)) { | ||
| 215 | spin_unlock(&nf->lru_lock); | ||
| 216 | break; | ||
| 217 | } | ||
| 218 | |||
| 219 | q = list_first_entry(&nf->lru_list, | ||
| 220 | struct inet_frag_queue, lru_list); | ||
| 221 | atomic_inc(&q->refcnt); | ||
| 222 | /* Remove q from list to avoid several CPUs grabbing it */ | ||
| 223 | list_del_init(&q->lru_list); | ||
| 224 | |||
| 225 | spin_unlock(&nf->lru_lock); | ||
| 226 | |||
| 227 | spin_lock(&q->lock); | ||
| 228 | if (!(q->last_in & INET_FRAG_COMPLETE)) | ||
| 229 | inet_frag_kill(q, f); | ||
| 230 | spin_unlock(&q->lock); | ||
| 231 | |||
| 232 | if (atomic_dec_and_test(&q->refcnt)) | ||
| 233 | inet_frag_destroy(q, f, &work); | ||
| 234 | evicted++; | ||
| 235 | } | ||
| 236 | |||
| 237 | return evicted; | ||
| 238 | } | ||
| 239 | EXPORT_SYMBOL(inet_frag_evictor); | ||
| 240 | |||
| 241 | static struct inet_frag_queue *inet_frag_intern(struct netns_frags *nf, | 341 | static struct inet_frag_queue *inet_frag_intern(struct netns_frags *nf, |
| 242 | struct inet_frag_queue *qp_in, struct inet_frags *f, | 342 | struct inet_frag_queue *qp_in, |
| 243 | void *arg) | 343 | struct inet_frags *f, |
| 344 | void *arg) | ||
| 244 | { | 345 | { |
| 245 | struct inet_frag_bucket *hb; | 346 | struct inet_frag_bucket *hb = get_frag_bucket_locked(qp_in, f); |
| 246 | struct inet_frag_queue *qp; | 347 | struct inet_frag_queue *qp; |
| 247 | unsigned int hash; | ||
| 248 | |||
| 249 | read_lock(&f->lock); /* Protects against hash rebuild */ | ||
| 250 | /* | ||
| 251 | * While we stayed w/o the lock other CPU could update | ||
| 252 | * the rnd seed, so we need to re-calculate the hash | ||
| 253 | * chain. Fortunatelly the qp_in can be used to get one. | ||
| 254 | */ | ||
| 255 | hash = f->hashfn(qp_in); | ||
| 256 | hb = &f->hash[hash]; | ||
| 257 | spin_lock(&hb->chain_lock); | ||
| 258 | 348 | ||
| 259 | #ifdef CONFIG_SMP | 349 | #ifdef CONFIG_SMP |
| 260 | /* With SMP race we have to recheck hash table, because | 350 | /* With SMP race we have to recheck hash table, because |
| 261 | * such entry could be created on other cpu, while we | 351 | * such entry could have been created on other cpu before |
| 262 | * released the hash bucket lock. | 352 | * we acquired hash bucket lock. |
| 263 | */ | 353 | */ |
| 264 | hlist_for_each_entry(qp, &hb->chain, list) { | 354 | hlist_for_each_entry(qp, &hb->chain, list) { |
| 265 | if (qp->net == nf && f->match(qp, arg)) { | 355 | if (qp->net == nf && f->match(qp, arg)) { |
| 266 | atomic_inc(&qp->refcnt); | 356 | atomic_inc(&qp->refcnt); |
| 267 | spin_unlock(&hb->chain_lock); | 357 | spin_unlock(&hb->chain_lock); |
| 268 | read_unlock(&f->lock); | 358 | qp_in->flags |= INET_FRAG_COMPLETE; |
| 269 | qp_in->last_in |= INET_FRAG_COMPLETE; | ||
| 270 | inet_frag_put(qp_in, f); | 359 | inet_frag_put(qp_in, f); |
| 271 | return qp; | 360 | return qp; |
| 272 | } | 361 | } |
| @@ -278,19 +367,24 @@ static struct inet_frag_queue *inet_frag_intern(struct netns_frags *nf, | |||
| 278 | 367 | ||
| 279 | atomic_inc(&qp->refcnt); | 368 | atomic_inc(&qp->refcnt); |
| 280 | hlist_add_head(&qp->list, &hb->chain); | 369 | hlist_add_head(&qp->list, &hb->chain); |
| 281 | inet_frag_lru_add(nf, qp); | 370 | |
| 282 | spin_unlock(&hb->chain_lock); | 371 | spin_unlock(&hb->chain_lock); |
| 283 | read_unlock(&f->lock); | ||
| 284 | 372 | ||
| 285 | return qp; | 373 | return qp; |
| 286 | } | 374 | } |
| 287 | 375 | ||
| 288 | static struct inet_frag_queue *inet_frag_alloc(struct netns_frags *nf, | 376 | static struct inet_frag_queue *inet_frag_alloc(struct netns_frags *nf, |
| 289 | struct inet_frags *f, void *arg) | 377 | struct inet_frags *f, |
| 378 | void *arg) | ||
| 290 | { | 379 | { |
| 291 | struct inet_frag_queue *q; | 380 | struct inet_frag_queue *q; |
| 292 | 381 | ||
| 293 | q = kzalloc(f->qsize, GFP_ATOMIC); | 382 | if (frag_mem_limit(nf) > nf->high_thresh) { |
| 383 | inet_frag_schedule_worker(f); | ||
| 384 | return NULL; | ||
| 385 | } | ||
| 386 | |||
| 387 | q = kmem_cache_zalloc(f->frags_cachep, GFP_ATOMIC); | ||
| 294 | if (q == NULL) | 388 | if (q == NULL) |
| 295 | return NULL; | 389 | return NULL; |
| 296 | 390 | ||
| @@ -301,13 +395,13 @@ static struct inet_frag_queue *inet_frag_alloc(struct netns_frags *nf, | |||
| 301 | setup_timer(&q->timer, f->frag_expire, (unsigned long)q); | 395 | setup_timer(&q->timer, f->frag_expire, (unsigned long)q); |
| 302 | spin_lock_init(&q->lock); | 396 | spin_lock_init(&q->lock); |
| 303 | atomic_set(&q->refcnt, 1); | 397 | atomic_set(&q->refcnt, 1); |
| 304 | INIT_LIST_HEAD(&q->lru_list); | ||
| 305 | 398 | ||
| 306 | return q; | 399 | return q; |
| 307 | } | 400 | } |
| 308 | 401 | ||
| 309 | static struct inet_frag_queue *inet_frag_create(struct netns_frags *nf, | 402 | static struct inet_frag_queue *inet_frag_create(struct netns_frags *nf, |
| 310 | struct inet_frags *f, void *arg) | 403 | struct inet_frags *f, |
| 404 | void *arg) | ||
| 311 | { | 405 | { |
| 312 | struct inet_frag_queue *q; | 406 | struct inet_frag_queue *q; |
| 313 | 407 | ||
| @@ -319,13 +413,17 @@ static struct inet_frag_queue *inet_frag_create(struct netns_frags *nf, | |||
| 319 | } | 413 | } |
| 320 | 414 | ||
| 321 | struct inet_frag_queue *inet_frag_find(struct netns_frags *nf, | 415 | struct inet_frag_queue *inet_frag_find(struct netns_frags *nf, |
| 322 | struct inet_frags *f, void *key, unsigned int hash) | 416 | struct inet_frags *f, void *key, |
| 323 | __releases(&f->lock) | 417 | unsigned int hash) |
| 324 | { | 418 | { |
| 325 | struct inet_frag_bucket *hb; | 419 | struct inet_frag_bucket *hb; |
| 326 | struct inet_frag_queue *q; | 420 | struct inet_frag_queue *q; |
| 327 | int depth = 0; | 421 | int depth = 0; |
| 328 | 422 | ||
| 423 | if (frag_mem_limit(nf) > nf->low_thresh) | ||
| 424 | inet_frag_schedule_worker(f); | ||
| 425 | |||
| 426 | hash &= (INETFRAGS_HASHSZ - 1); | ||
| 329 | hb = &f->hash[hash]; | 427 | hb = &f->hash[hash]; |
| 330 | 428 | ||
| 331 | spin_lock(&hb->chain_lock); | 429 | spin_lock(&hb->chain_lock); |
| @@ -333,18 +431,22 @@ struct inet_frag_queue *inet_frag_find(struct netns_frags *nf, | |||
| 333 | if (q->net == nf && f->match(q, key)) { | 431 | if (q->net == nf && f->match(q, key)) { |
| 334 | atomic_inc(&q->refcnt); | 432 | atomic_inc(&q->refcnt); |
| 335 | spin_unlock(&hb->chain_lock); | 433 | spin_unlock(&hb->chain_lock); |
| 336 | read_unlock(&f->lock); | ||
| 337 | return q; | 434 | return q; |
| 338 | } | 435 | } |
| 339 | depth++; | 436 | depth++; |
| 340 | } | 437 | } |
| 341 | spin_unlock(&hb->chain_lock); | 438 | spin_unlock(&hb->chain_lock); |
| 342 | read_unlock(&f->lock); | ||
| 343 | 439 | ||
| 344 | if (depth <= INETFRAGS_MAXDEPTH) | 440 | if (depth <= INETFRAGS_MAXDEPTH) |
| 345 | return inet_frag_create(nf, f, key); | 441 | return inet_frag_create(nf, f, key); |
| 346 | else | 442 | |
| 347 | return ERR_PTR(-ENOBUFS); | 443 | if (inet_frag_may_rebuild(f)) { |
| 444 | if (!f->rebuild) | ||
| 445 | f->rebuild = true; | ||
| 446 | inet_frag_schedule_worker(f); | ||
| 447 | } | ||
| 448 | |||
| 449 | return ERR_PTR(-ENOBUFS); | ||
| 348 | } | 450 | } |
| 349 | EXPORT_SYMBOL(inet_frag_find); | 451 | EXPORT_SYMBOL(inet_frag_find); |
| 350 | 452 | ||
diff --git a/net/ipv4/ip_fragment.c b/net/ipv4/ip_fragment.c index ed32313e307c..15f0e2bad7ad 100644 --- a/net/ipv4/ip_fragment.c +++ b/net/ipv4/ip_fragment.c | |||
| @@ -55,6 +55,7 @@ | |||
| 55 | */ | 55 | */ |
| 56 | 56 | ||
| 57 | static int sysctl_ipfrag_max_dist __read_mostly = 64; | 57 | static int sysctl_ipfrag_max_dist __read_mostly = 64; |
| 58 | static const char ip_frag_cache_name[] = "ip4-frags"; | ||
| 58 | 59 | ||
| 59 | struct ipfrag_skb_cb | 60 | struct ipfrag_skb_cb |
| 60 | { | 61 | { |
| @@ -86,11 +87,6 @@ static inline u8 ip4_frag_ecn(u8 tos) | |||
| 86 | 87 | ||
| 87 | static struct inet_frags ip4_frags; | 88 | static struct inet_frags ip4_frags; |
| 88 | 89 | ||
| 89 | int ip_frag_nqueues(struct net *net) | ||
| 90 | { | ||
| 91 | return net->ipv4.frags.nqueues; | ||
| 92 | } | ||
| 93 | |||
| 94 | int ip_frag_mem(struct net *net) | 90 | int ip_frag_mem(struct net *net) |
| 95 | { | 91 | { |
| 96 | return sum_frag_mem_limit(&net->ipv4.frags); | 92 | return sum_frag_mem_limit(&net->ipv4.frags); |
| @@ -109,21 +105,21 @@ static unsigned int ipqhashfn(__be16 id, __be32 saddr, __be32 daddr, u8 prot) | |||
| 109 | net_get_random_once(&ip4_frags.rnd, sizeof(ip4_frags.rnd)); | 105 | net_get_random_once(&ip4_frags.rnd, sizeof(ip4_frags.rnd)); |
| 110 | return jhash_3words((__force u32)id << 16 | prot, | 106 | return jhash_3words((__force u32)id << 16 | prot, |
| 111 | (__force u32)saddr, (__force u32)daddr, | 107 | (__force u32)saddr, (__force u32)daddr, |
| 112 | ip4_frags.rnd) & (INETFRAGS_HASHSZ - 1); | 108 | ip4_frags.rnd); |
| 113 | } | 109 | } |
| 114 | 110 | ||
| 115 | static unsigned int ip4_hashfn(struct inet_frag_queue *q) | 111 | static unsigned int ip4_hashfn(const struct inet_frag_queue *q) |
| 116 | { | 112 | { |
| 117 | struct ipq *ipq; | 113 | const struct ipq *ipq; |
| 118 | 114 | ||
| 119 | ipq = container_of(q, struct ipq, q); | 115 | ipq = container_of(q, struct ipq, q); |
| 120 | return ipqhashfn(ipq->id, ipq->saddr, ipq->daddr, ipq->protocol); | 116 | return ipqhashfn(ipq->id, ipq->saddr, ipq->daddr, ipq->protocol); |
| 121 | } | 117 | } |
| 122 | 118 | ||
| 123 | static bool ip4_frag_match(struct inet_frag_queue *q, void *a) | 119 | static bool ip4_frag_match(const struct inet_frag_queue *q, const void *a) |
| 124 | { | 120 | { |
| 125 | struct ipq *qp; | 121 | const struct ipq *qp; |
| 126 | struct ip4_create_arg *arg = a; | 122 | const struct ip4_create_arg *arg = a; |
| 127 | 123 | ||
| 128 | qp = container_of(q, struct ipq, q); | 124 | qp = container_of(q, struct ipq, q); |
| 129 | return qp->id == arg->iph->id && | 125 | return qp->id == arg->iph->id && |
| @@ -133,14 +129,14 @@ static bool ip4_frag_match(struct inet_frag_queue *q, void *a) | |||
| 133 | qp->user == arg->user; | 129 | qp->user == arg->user; |
| 134 | } | 130 | } |
| 135 | 131 | ||
| 136 | static void ip4_frag_init(struct inet_frag_queue *q, void *a) | 132 | static void ip4_frag_init(struct inet_frag_queue *q, const void *a) |
| 137 | { | 133 | { |
| 138 | struct ipq *qp = container_of(q, struct ipq, q); | 134 | struct ipq *qp = container_of(q, struct ipq, q); |
| 139 | struct netns_ipv4 *ipv4 = container_of(q->net, struct netns_ipv4, | 135 | struct netns_ipv4 *ipv4 = container_of(q->net, struct netns_ipv4, |
| 140 | frags); | 136 | frags); |
| 141 | struct net *net = container_of(ipv4, struct net, ipv4); | 137 | struct net *net = container_of(ipv4, struct net, ipv4); |
| 142 | 138 | ||
| 143 | struct ip4_create_arg *arg = a; | 139 | const struct ip4_create_arg *arg = a; |
| 144 | 140 | ||
| 145 | qp->protocol = arg->iph->protocol; | 141 | qp->protocol = arg->iph->protocol; |
| 146 | qp->id = arg->iph->id; | 142 | qp->id = arg->iph->id; |
| @@ -177,18 +173,6 @@ static void ipq_kill(struct ipq *ipq) | |||
| 177 | inet_frag_kill(&ipq->q, &ip4_frags); | 173 | inet_frag_kill(&ipq->q, &ip4_frags); |
| 178 | } | 174 | } |
| 179 | 175 | ||
| 180 | /* Memory limiting on fragments. Evictor trashes the oldest | ||
| 181 | * fragment queue until we are back under the threshold. | ||
| 182 | */ | ||
| 183 | static void ip_evictor(struct net *net) | ||
| 184 | { | ||
| 185 | int evicted; | ||
| 186 | |||
| 187 | evicted = inet_frag_evictor(&net->ipv4.frags, &ip4_frags, false); | ||
| 188 | if (evicted) | ||
| 189 | IP_ADD_STATS_BH(net, IPSTATS_MIB_REASMFAILS, evicted); | ||
| 190 | } | ||
| 191 | |||
| 192 | /* | 176 | /* |
| 193 | * Oops, a fragment queue timed out. Kill it and send an ICMP reply. | 177 | * Oops, a fragment queue timed out. Kill it and send an ICMP reply. |
| 194 | */ | 178 | */ |
| @@ -202,19 +186,22 @@ static void ip_expire(unsigned long arg) | |||
| 202 | 186 | ||
| 203 | spin_lock(&qp->q.lock); | 187 | spin_lock(&qp->q.lock); |
| 204 | 188 | ||
| 205 | if (qp->q.last_in & INET_FRAG_COMPLETE) | 189 | if (qp->q.flags & INET_FRAG_COMPLETE) |
| 206 | goto out; | 190 | goto out; |
| 207 | 191 | ||
| 208 | ipq_kill(qp); | 192 | ipq_kill(qp); |
| 209 | |||
| 210 | IP_INC_STATS_BH(net, IPSTATS_MIB_REASMTIMEOUT); | ||
| 211 | IP_INC_STATS_BH(net, IPSTATS_MIB_REASMFAILS); | 193 | IP_INC_STATS_BH(net, IPSTATS_MIB_REASMFAILS); |
| 212 | 194 | ||
| 213 | if ((qp->q.last_in & INET_FRAG_FIRST_IN) && qp->q.fragments != NULL) { | 195 | if (!(qp->q.flags & INET_FRAG_EVICTED)) { |
| 214 | struct sk_buff *head = qp->q.fragments; | 196 | struct sk_buff *head = qp->q.fragments; |
| 215 | const struct iphdr *iph; | 197 | const struct iphdr *iph; |
| 216 | int err; | 198 | int err; |
| 217 | 199 | ||
| 200 | IP_INC_STATS_BH(net, IPSTATS_MIB_REASMTIMEOUT); | ||
| 201 | |||
| 202 | if (!(qp->q.flags & INET_FRAG_FIRST_IN) || !qp->q.fragments) | ||
| 203 | goto out; | ||
| 204 | |||
| 218 | rcu_read_lock(); | 205 | rcu_read_lock(); |
| 219 | head->dev = dev_get_by_index_rcu(net, qp->iif); | 206 | head->dev = dev_get_by_index_rcu(net, qp->iif); |
| 220 | if (!head->dev) | 207 | if (!head->dev) |
| @@ -227,8 +214,7 @@ static void ip_expire(unsigned long arg) | |||
| 227 | if (err) | 214 | if (err) |
| 228 | goto out_rcu_unlock; | 215 | goto out_rcu_unlock; |
| 229 | 216 | ||
| 230 | /* | 217 | /* Only an end host needs to send an ICMP |
| 231 | * Only an end host needs to send an ICMP | ||
| 232 | * "Fragment Reassembly Timeout" message, per RFC792. | 218 | * "Fragment Reassembly Timeout" message, per RFC792. |
| 233 | */ | 219 | */ |
| 234 | if (qp->user == IP_DEFRAG_AF_PACKET || | 220 | if (qp->user == IP_DEFRAG_AF_PACKET || |
| @@ -237,7 +223,6 @@ static void ip_expire(unsigned long arg) | |||
| 237 | (skb_rtable(head)->rt_type != RTN_LOCAL))) | 223 | (skb_rtable(head)->rt_type != RTN_LOCAL))) |
| 238 | goto out_rcu_unlock; | 224 | goto out_rcu_unlock; |
| 239 | 225 | ||
| 240 | |||
| 241 | /* Send an ICMP "Fragment Reassembly Timeout" message. */ | 226 | /* Send an ICMP "Fragment Reassembly Timeout" message. */ |
| 242 | icmp_send(head, ICMP_TIME_EXCEEDED, ICMP_EXC_FRAGTIME, 0); | 227 | icmp_send(head, ICMP_TIME_EXCEEDED, ICMP_EXC_FRAGTIME, 0); |
| 243 | out_rcu_unlock: | 228 | out_rcu_unlock: |
| @@ -260,7 +245,6 @@ static inline struct ipq *ip_find(struct net *net, struct iphdr *iph, u32 user) | |||
| 260 | arg.iph = iph; | 245 | arg.iph = iph; |
| 261 | arg.user = user; | 246 | arg.user = user; |
| 262 | 247 | ||
| 263 | read_lock(&ip4_frags.lock); | ||
| 264 | hash = ipqhashfn(iph->id, iph->saddr, iph->daddr, iph->protocol); | 248 | hash = ipqhashfn(iph->id, iph->saddr, iph->daddr, iph->protocol); |
| 265 | 249 | ||
| 266 | q = inet_frag_find(&net->ipv4.frags, &ip4_frags, &arg, hash); | 250 | q = inet_frag_find(&net->ipv4.frags, &ip4_frags, &arg, hash); |
| @@ -319,7 +303,7 @@ static int ip_frag_reinit(struct ipq *qp) | |||
| 319 | } while (fp); | 303 | } while (fp); |
| 320 | sub_frag_mem_limit(&qp->q, sum_truesize); | 304 | sub_frag_mem_limit(&qp->q, sum_truesize); |
| 321 | 305 | ||
| 322 | qp->q.last_in = 0; | 306 | qp->q.flags = 0; |
| 323 | qp->q.len = 0; | 307 | qp->q.len = 0; |
| 324 | qp->q.meat = 0; | 308 | qp->q.meat = 0; |
| 325 | qp->q.fragments = NULL; | 309 | qp->q.fragments = NULL; |
| @@ -340,7 +324,7 @@ static int ip_frag_queue(struct ipq *qp, struct sk_buff *skb) | |||
| 340 | int err = -ENOENT; | 324 | int err = -ENOENT; |
| 341 | u8 ecn; | 325 | u8 ecn; |
| 342 | 326 | ||
| 343 | if (qp->q.last_in & INET_FRAG_COMPLETE) | 327 | if (qp->q.flags & INET_FRAG_COMPLETE) |
| 344 | goto err; | 328 | goto err; |
| 345 | 329 | ||
| 346 | if (!(IPCB(skb)->flags & IPSKB_FRAG_COMPLETE) && | 330 | if (!(IPCB(skb)->flags & IPSKB_FRAG_COMPLETE) && |
| @@ -367,9 +351,9 @@ static int ip_frag_queue(struct ipq *qp, struct sk_buff *skb) | |||
| 367 | * or have different end, the segment is corrupted. | 351 | * or have different end, the segment is corrupted. |
| 368 | */ | 352 | */ |
| 369 | if (end < qp->q.len || | 353 | if (end < qp->q.len || |
| 370 | ((qp->q.last_in & INET_FRAG_LAST_IN) && end != qp->q.len)) | 354 | ((qp->q.flags & INET_FRAG_LAST_IN) && end != qp->q.len)) |
| 371 | goto err; | 355 | goto err; |
| 372 | qp->q.last_in |= INET_FRAG_LAST_IN; | 356 | qp->q.flags |= INET_FRAG_LAST_IN; |
| 373 | qp->q.len = end; | 357 | qp->q.len = end; |
| 374 | } else { | 358 | } else { |
| 375 | if (end&7) { | 359 | if (end&7) { |
| @@ -379,7 +363,7 @@ static int ip_frag_queue(struct ipq *qp, struct sk_buff *skb) | |||
| 379 | } | 363 | } |
| 380 | if (end > qp->q.len) { | 364 | if (end > qp->q.len) { |
| 381 | /* Some bits beyond end -> corruption. */ | 365 | /* Some bits beyond end -> corruption. */ |
| 382 | if (qp->q.last_in & INET_FRAG_LAST_IN) | 366 | if (qp->q.flags & INET_FRAG_LAST_IN) |
| 383 | goto err; | 367 | goto err; |
| 384 | qp->q.len = end; | 368 | qp->q.len = end; |
| 385 | } | 369 | } |
| @@ -488,13 +472,13 @@ found: | |||
| 488 | qp->ecn |= ecn; | 472 | qp->ecn |= ecn; |
| 489 | add_frag_mem_limit(&qp->q, skb->truesize); | 473 | add_frag_mem_limit(&qp->q, skb->truesize); |
| 490 | if (offset == 0) | 474 | if (offset == 0) |
| 491 | qp->q.last_in |= INET_FRAG_FIRST_IN; | 475 | qp->q.flags |= INET_FRAG_FIRST_IN; |
| 492 | 476 | ||
| 493 | if (ip_hdr(skb)->frag_off & htons(IP_DF) && | 477 | if (ip_hdr(skb)->frag_off & htons(IP_DF) && |
| 494 | skb->len + ihl > qp->q.max_size) | 478 | skb->len + ihl > qp->q.max_size) |
| 495 | qp->q.max_size = skb->len + ihl; | 479 | qp->q.max_size = skb->len + ihl; |
| 496 | 480 | ||
| 497 | if (qp->q.last_in == (INET_FRAG_FIRST_IN | INET_FRAG_LAST_IN) && | 481 | if (qp->q.flags == (INET_FRAG_FIRST_IN | INET_FRAG_LAST_IN) && |
| 498 | qp->q.meat == qp->q.len) { | 482 | qp->q.meat == qp->q.len) { |
| 499 | unsigned long orefdst = skb->_skb_refdst; | 483 | unsigned long orefdst = skb->_skb_refdst; |
| 500 | 484 | ||
| @@ -505,7 +489,6 @@ found: | |||
| 505 | } | 489 | } |
| 506 | 490 | ||
| 507 | skb_dst_drop(skb); | 491 | skb_dst_drop(skb); |
| 508 | inet_frag_lru_move(&qp->q); | ||
| 509 | return -EINPROGRESS; | 492 | return -EINPROGRESS; |
| 510 | 493 | ||
| 511 | err: | 494 | err: |
| @@ -655,9 +638,6 @@ int ip_defrag(struct sk_buff *skb, u32 user) | |||
| 655 | net = skb->dev ? dev_net(skb->dev) : dev_net(skb_dst(skb)->dev); | 638 | net = skb->dev ? dev_net(skb->dev) : dev_net(skb_dst(skb)->dev); |
| 656 | IP_INC_STATS_BH(net, IPSTATS_MIB_REASMREQDS); | 639 | IP_INC_STATS_BH(net, IPSTATS_MIB_REASMREQDS); |
| 657 | 640 | ||
| 658 | /* Start by cleaning up the memory. */ | ||
| 659 | ip_evictor(net); | ||
| 660 | |||
| 661 | /* Lookup (or create) queue header */ | 641 | /* Lookup (or create) queue header */ |
| 662 | if ((qp = ip_find(net, ip_hdr(skb), user)) != NULL) { | 642 | if ((qp = ip_find(net, ip_hdr(skb), user)) != NULL) { |
| 663 | int ret; | 643 | int ret; |
| @@ -721,14 +701,17 @@ static struct ctl_table ip4_frags_ns_ctl_table[] = { | |||
| 721 | .data = &init_net.ipv4.frags.high_thresh, | 701 | .data = &init_net.ipv4.frags.high_thresh, |
| 722 | .maxlen = sizeof(int), | 702 | .maxlen = sizeof(int), |
| 723 | .mode = 0644, | 703 | .mode = 0644, |
| 724 | .proc_handler = proc_dointvec | 704 | .proc_handler = proc_dointvec_minmax, |
| 705 | .extra1 = &init_net.ipv4.frags.low_thresh | ||
| 725 | }, | 706 | }, |
| 726 | { | 707 | { |
| 727 | .procname = "ipfrag_low_thresh", | 708 | .procname = "ipfrag_low_thresh", |
| 728 | .data = &init_net.ipv4.frags.low_thresh, | 709 | .data = &init_net.ipv4.frags.low_thresh, |
| 729 | .maxlen = sizeof(int), | 710 | .maxlen = sizeof(int), |
| 730 | .mode = 0644, | 711 | .mode = 0644, |
| 731 | .proc_handler = proc_dointvec | 712 | .proc_handler = proc_dointvec_minmax, |
| 713 | .extra1 = &zero, | ||
| 714 | .extra2 = &init_net.ipv4.frags.high_thresh | ||
| 732 | }, | 715 | }, |
| 733 | { | 716 | { |
| 734 | .procname = "ipfrag_time", | 717 | .procname = "ipfrag_time", |
| @@ -740,10 +723,12 @@ static struct ctl_table ip4_frags_ns_ctl_table[] = { | |||
| 740 | { } | 723 | { } |
| 741 | }; | 724 | }; |
| 742 | 725 | ||
| 726 | /* secret interval has been deprecated */ | ||
| 727 | static int ip4_frags_secret_interval_unused; | ||
| 743 | static struct ctl_table ip4_frags_ctl_table[] = { | 728 | static struct ctl_table ip4_frags_ctl_table[] = { |
| 744 | { | 729 | { |
| 745 | .procname = "ipfrag_secret_interval", | 730 | .procname = "ipfrag_secret_interval", |
| 746 | .data = &ip4_frags.secret_interval, | 731 | .data = &ip4_frags_secret_interval_unused, |
| 747 | .maxlen = sizeof(int), | 732 | .maxlen = sizeof(int), |
| 748 | .mode = 0644, | 733 | .mode = 0644, |
| 749 | .proc_handler = proc_dointvec_jiffies, | 734 | .proc_handler = proc_dointvec_jiffies, |
| @@ -771,7 +756,10 @@ static int __net_init ip4_frags_ns_ctl_register(struct net *net) | |||
| 771 | goto err_alloc; | 756 | goto err_alloc; |
| 772 | 757 | ||
| 773 | table[0].data = &net->ipv4.frags.high_thresh; | 758 | table[0].data = &net->ipv4.frags.high_thresh; |
| 759 | table[0].extra1 = &net->ipv4.frags.low_thresh; | ||
| 760 | table[0].extra2 = &init_net.ipv4.frags.high_thresh; | ||
| 774 | table[1].data = &net->ipv4.frags.low_thresh; | 761 | table[1].data = &net->ipv4.frags.low_thresh; |
| 762 | table[1].extra2 = &net->ipv4.frags.high_thresh; | ||
| 775 | table[2].data = &net->ipv4.frags.timeout; | 763 | table[2].data = &net->ipv4.frags.timeout; |
| 776 | 764 | ||
| 777 | /* Don't export sysctls to unprivileged users */ | 765 | /* Don't export sysctls to unprivileged users */ |
| @@ -873,6 +861,7 @@ void __init ipfrag_init(void) | |||
| 873 | ip4_frags.qsize = sizeof(struct ipq); | 861 | ip4_frags.qsize = sizeof(struct ipq); |
| 874 | ip4_frags.match = ip4_frag_match; | 862 | ip4_frags.match = ip4_frag_match; |
| 875 | ip4_frags.frag_expire = ip_expire; | 863 | ip4_frags.frag_expire = ip_expire; |
| 876 | ip4_frags.secret_interval = 10 * 60 * HZ; | 864 | ip4_frags.frags_cache_name = ip_frag_cache_name; |
| 877 | inet_frags_init(&ip4_frags); | 865 | if (inet_frags_init(&ip4_frags)) |
| 866 | panic("IP: failed to allocate ip4_frags cache\n"); | ||
| 878 | } | 867 | } |
diff --git a/net/ipv4/ip_output.c b/net/ipv4/ip_output.c index 8d3b6b0e9857..215af2b155cb 100644 --- a/net/ipv4/ip_output.c +++ b/net/ipv4/ip_output.c | |||
| @@ -855,11 +855,15 @@ static int __ip_append_data(struct sock *sk, | |||
| 855 | unsigned int maxfraglen, fragheaderlen, maxnonfragsize; | 855 | unsigned int maxfraglen, fragheaderlen, maxnonfragsize; |
| 856 | int csummode = CHECKSUM_NONE; | 856 | int csummode = CHECKSUM_NONE; |
| 857 | struct rtable *rt = (struct rtable *)cork->dst; | 857 | struct rtable *rt = (struct rtable *)cork->dst; |
| 858 | u32 tskey = 0; | ||
| 858 | 859 | ||
| 859 | skb = skb_peek_tail(queue); | 860 | skb = skb_peek_tail(queue); |
| 860 | 861 | ||
| 861 | exthdrlen = !skb ? rt->dst.header_len : 0; | 862 | exthdrlen = !skb ? rt->dst.header_len : 0; |
| 862 | mtu = cork->fragsize; | 863 | mtu = cork->fragsize; |
| 864 | if (cork->tx_flags & SKBTX_ANY_SW_TSTAMP && | ||
| 865 | sk->sk_tsflags & SOF_TIMESTAMPING_OPT_ID) | ||
| 866 | tskey = sk->sk_tskey++; | ||
| 863 | 867 | ||
| 864 | hh_len = LL_RESERVED_SPACE(rt->dst.dev); | 868 | hh_len = LL_RESERVED_SPACE(rt->dst.dev); |
| 865 | 869 | ||
| @@ -962,10 +966,6 @@ alloc_new_skb: | |||
| 962 | sk->sk_allocation); | 966 | sk->sk_allocation); |
| 963 | if (unlikely(skb == NULL)) | 967 | if (unlikely(skb == NULL)) |
| 964 | err = -ENOBUFS; | 968 | err = -ENOBUFS; |
| 965 | else | ||
| 966 | /* only the initial fragment is | ||
| 967 | time stamped */ | ||
| 968 | cork->tx_flags = 0; | ||
| 969 | } | 969 | } |
| 970 | if (skb == NULL) | 970 | if (skb == NULL) |
| 971 | goto error; | 971 | goto error; |
| @@ -976,7 +976,12 @@ alloc_new_skb: | |||
| 976 | skb->ip_summed = csummode; | 976 | skb->ip_summed = csummode; |
| 977 | skb->csum = 0; | 977 | skb->csum = 0; |
| 978 | skb_reserve(skb, hh_len); | 978 | skb_reserve(skb, hh_len); |
| 979 | |||
| 980 | /* only the initial fragment is time stamped */ | ||
| 979 | skb_shinfo(skb)->tx_flags = cork->tx_flags; | 981 | skb_shinfo(skb)->tx_flags = cork->tx_flags; |
| 982 | cork->tx_flags = 0; | ||
| 983 | skb_shinfo(skb)->tskey = tskey; | ||
| 984 | tskey = 0; | ||
| 980 | 985 | ||
| 981 | /* | 986 | /* |
| 982 | * Find where to start putting bytes. | 987 | * Find where to start putting bytes. |
diff --git a/net/ipv4/ip_sockglue.c b/net/ipv4/ip_sockglue.c index 64741b938632..5cb830c78990 100644 --- a/net/ipv4/ip_sockglue.c +++ b/net/ipv4/ip_sockglue.c | |||
| @@ -1319,7 +1319,7 @@ static int do_ip_getsockopt(struct sock *sk, int level, int optname, | |||
| 1319 | if (sk->sk_type != SOCK_STREAM) | 1319 | if (sk->sk_type != SOCK_STREAM) |
| 1320 | return -ENOPROTOOPT; | 1320 | return -ENOPROTOOPT; |
| 1321 | 1321 | ||
| 1322 | msg.msg_control = optval; | 1322 | msg.msg_control = (__force void *) optval; |
| 1323 | msg.msg_controllen = len; | 1323 | msg.msg_controllen = len; |
| 1324 | msg.msg_flags = flags; | 1324 | msg.msg_flags = flags; |
| 1325 | 1325 | ||
diff --git a/net/ipv4/ip_tunnel.c b/net/ipv4/ip_tunnel.c index 6f9de61dce5f..afed1aac2638 100644 --- a/net/ipv4/ip_tunnel.c +++ b/net/ipv4/ip_tunnel.c | |||
| @@ -69,23 +69,25 @@ static unsigned int ip_tunnel_hash(__be32 key, __be32 remote) | |||
| 69 | } | 69 | } |
| 70 | 70 | ||
| 71 | static void __tunnel_dst_set(struct ip_tunnel_dst *idst, | 71 | static void __tunnel_dst_set(struct ip_tunnel_dst *idst, |
| 72 | struct dst_entry *dst) | 72 | struct dst_entry *dst, __be32 saddr) |
| 73 | { | 73 | { |
| 74 | struct dst_entry *old_dst; | 74 | struct dst_entry *old_dst; |
| 75 | 75 | ||
| 76 | dst_clone(dst); | 76 | dst_clone(dst); |
| 77 | old_dst = xchg((__force struct dst_entry **)&idst->dst, dst); | 77 | old_dst = xchg((__force struct dst_entry **)&idst->dst, dst); |
| 78 | dst_release(old_dst); | 78 | dst_release(old_dst); |
| 79 | idst->saddr = saddr; | ||
| 79 | } | 80 | } |
| 80 | 81 | ||
| 81 | static void tunnel_dst_set(struct ip_tunnel *t, struct dst_entry *dst) | 82 | static void tunnel_dst_set(struct ip_tunnel *t, |
| 83 | struct dst_entry *dst, __be32 saddr) | ||
| 82 | { | 84 | { |
| 83 | __tunnel_dst_set(this_cpu_ptr(t->dst_cache), dst); | 85 | __tunnel_dst_set(this_cpu_ptr(t->dst_cache), dst, saddr); |
| 84 | } | 86 | } |
| 85 | 87 | ||
| 86 | static void tunnel_dst_reset(struct ip_tunnel *t) | 88 | static void tunnel_dst_reset(struct ip_tunnel *t) |
| 87 | { | 89 | { |
| 88 | tunnel_dst_set(t, NULL); | 90 | tunnel_dst_set(t, NULL, 0); |
| 89 | } | 91 | } |
| 90 | 92 | ||
| 91 | void ip_tunnel_dst_reset_all(struct ip_tunnel *t) | 93 | void ip_tunnel_dst_reset_all(struct ip_tunnel *t) |
| @@ -93,20 +95,25 @@ void ip_tunnel_dst_reset_all(struct ip_tunnel *t) | |||
| 93 | int i; | 95 | int i; |
| 94 | 96 | ||
| 95 | for_each_possible_cpu(i) | 97 | for_each_possible_cpu(i) |
| 96 | __tunnel_dst_set(per_cpu_ptr(t->dst_cache, i), NULL); | 98 | __tunnel_dst_set(per_cpu_ptr(t->dst_cache, i), NULL, 0); |
| 97 | } | 99 | } |
| 98 | EXPORT_SYMBOL(ip_tunnel_dst_reset_all); | 100 | EXPORT_SYMBOL(ip_tunnel_dst_reset_all); |
| 99 | 101 | ||
| 100 | static struct rtable *tunnel_rtable_get(struct ip_tunnel *t, u32 cookie) | 102 | static struct rtable *tunnel_rtable_get(struct ip_tunnel *t, |
| 103 | u32 cookie, __be32 *saddr) | ||
| 101 | { | 104 | { |
| 105 | struct ip_tunnel_dst *idst; | ||
| 102 | struct dst_entry *dst; | 106 | struct dst_entry *dst; |
| 103 | 107 | ||
| 104 | rcu_read_lock(); | 108 | rcu_read_lock(); |
| 105 | dst = rcu_dereference(this_cpu_ptr(t->dst_cache)->dst); | 109 | idst = this_cpu_ptr(t->dst_cache); |
| 110 | dst = rcu_dereference(idst->dst); | ||
| 106 | if (dst && !atomic_inc_not_zero(&dst->__refcnt)) | 111 | if (dst && !atomic_inc_not_zero(&dst->__refcnt)) |
| 107 | dst = NULL; | 112 | dst = NULL; |
| 108 | if (dst) { | 113 | if (dst) { |
| 109 | if (dst->obsolete && dst->ops->check(dst, cookie) == NULL) { | 114 | if (!dst->obsolete || dst->ops->check(dst, cookie)) { |
| 115 | *saddr = idst->saddr; | ||
| 116 | } else { | ||
| 110 | tunnel_dst_reset(t); | 117 | tunnel_dst_reset(t); |
| 111 | dst_release(dst); | 118 | dst_release(dst); |
| 112 | dst = NULL; | 119 | dst = NULL; |
| @@ -305,7 +312,7 @@ static struct net_device *__ip_tunnel_create(struct net *net, | |||
| 305 | } | 312 | } |
| 306 | 313 | ||
| 307 | ASSERT_RTNL(); | 314 | ASSERT_RTNL(); |
| 308 | dev = alloc_netdev(ops->priv_size, name, ops->setup); | 315 | dev = alloc_netdev(ops->priv_size, name, NET_NAME_UNKNOWN, ops->setup); |
| 309 | if (!dev) { | 316 | if (!dev) { |
| 310 | err = -ENOMEM; | 317 | err = -ENOMEM; |
| 311 | goto failed; | 318 | goto failed; |
| @@ -367,7 +374,7 @@ static int ip_tunnel_bind_dev(struct net_device *dev) | |||
| 367 | 374 | ||
| 368 | if (!IS_ERR(rt)) { | 375 | if (!IS_ERR(rt)) { |
| 369 | tdev = rt->dst.dev; | 376 | tdev = rt->dst.dev; |
| 370 | tunnel_dst_set(tunnel, &rt->dst); | 377 | tunnel_dst_set(tunnel, &rt->dst, fl4.saddr); |
| 371 | ip_rt_put(rt); | 378 | ip_rt_put(rt); |
| 372 | } | 379 | } |
| 373 | if (dev->type != ARPHRD_ETHER) | 380 | if (dev->type != ARPHRD_ETHER) |
| @@ -610,7 +617,7 @@ void ip_tunnel_xmit(struct sk_buff *skb, struct net_device *dev, | |||
| 610 | init_tunnel_flow(&fl4, protocol, dst, tnl_params->saddr, | 617 | init_tunnel_flow(&fl4, protocol, dst, tnl_params->saddr, |
| 611 | tunnel->parms.o_key, RT_TOS(tos), tunnel->parms.link); | 618 | tunnel->parms.o_key, RT_TOS(tos), tunnel->parms.link); |
| 612 | 619 | ||
| 613 | rt = connected ? tunnel_rtable_get(tunnel, 0) : NULL; | 620 | rt = connected ? tunnel_rtable_get(tunnel, 0, &fl4.saddr) : NULL; |
| 614 | 621 | ||
| 615 | if (!rt) { | 622 | if (!rt) { |
| 616 | rt = ip_route_output_key(tunnel->net, &fl4); | 623 | rt = ip_route_output_key(tunnel->net, &fl4); |
| @@ -620,7 +627,7 @@ void ip_tunnel_xmit(struct sk_buff *skb, struct net_device *dev, | |||
| 620 | goto tx_error; | 627 | goto tx_error; |
| 621 | } | 628 | } |
| 622 | if (connected) | 629 | if (connected) |
| 623 | tunnel_dst_set(tunnel, &rt->dst); | 630 | tunnel_dst_set(tunnel, &rt->dst, fl4.saddr); |
| 624 | } | 631 | } |
| 625 | 632 | ||
| 626 | if (rt->dst.dev == dev) { | 633 | if (rt->dst.dev == dev) { |
diff --git a/net/ipv4/ip_vti.c b/net/ipv4/ip_vti.c index b8960f3527f3..e453cb724a95 100644 --- a/net/ipv4/ip_vti.c +++ b/net/ipv4/ip_vti.c | |||
| @@ -534,40 +534,28 @@ static struct rtnl_link_ops vti_link_ops __read_mostly = { | |||
| 534 | 534 | ||
| 535 | static int __init vti_init(void) | 535 | static int __init vti_init(void) |
| 536 | { | 536 | { |
| 537 | const char *msg; | ||
| 537 | int err; | 538 | int err; |
| 538 | 539 | ||
| 539 | pr_info("IPv4 over IPSec tunneling driver\n"); | 540 | pr_info("IPv4 over IPsec tunneling driver\n"); |
| 540 | 541 | ||
| 542 | msg = "tunnel device"; | ||
| 541 | err = register_pernet_device(&vti_net_ops); | 543 | err = register_pernet_device(&vti_net_ops); |
| 542 | if (err < 0) | 544 | if (err < 0) |
| 543 | return err; | 545 | goto pernet_dev_failed; |
| 544 | err = xfrm4_protocol_register(&vti_esp4_protocol, IPPROTO_ESP); | ||
| 545 | if (err < 0) { | ||
| 546 | unregister_pernet_device(&vti_net_ops); | ||
| 547 | pr_info("vti init: can't register tunnel\n"); | ||
| 548 | |||
| 549 | return err; | ||
| 550 | } | ||
| 551 | 546 | ||
| 547 | msg = "tunnel protocols"; | ||
| 548 | err = xfrm4_protocol_register(&vti_esp4_protocol, IPPROTO_ESP); | ||
| 549 | if (err < 0) | ||
| 550 | goto xfrm_proto_esp_failed; | ||
| 552 | err = xfrm4_protocol_register(&vti_ah4_protocol, IPPROTO_AH); | 551 | err = xfrm4_protocol_register(&vti_ah4_protocol, IPPROTO_AH); |
| 553 | if (err < 0) { | 552 | if (err < 0) |
| 554 | xfrm4_protocol_deregister(&vti_esp4_protocol, IPPROTO_ESP); | 553 | goto xfrm_proto_ah_failed; |
| 555 | unregister_pernet_device(&vti_net_ops); | ||
| 556 | pr_info("vti init: can't register tunnel\n"); | ||
| 557 | |||
| 558 | return err; | ||
| 559 | } | ||
| 560 | |||
| 561 | err = xfrm4_protocol_register(&vti_ipcomp4_protocol, IPPROTO_COMP); | 554 | err = xfrm4_protocol_register(&vti_ipcomp4_protocol, IPPROTO_COMP); |
| 562 | if (err < 0) { | 555 | if (err < 0) |
| 563 | xfrm4_protocol_deregister(&vti_ah4_protocol, IPPROTO_AH); | 556 | goto xfrm_proto_comp_failed; |
| 564 | xfrm4_protocol_deregister(&vti_esp4_protocol, IPPROTO_ESP); | ||
| 565 | unregister_pernet_device(&vti_net_ops); | ||
| 566 | pr_info("vti init: can't register tunnel\n"); | ||
| 567 | |||
| 568 | return err; | ||
| 569 | } | ||
| 570 | 557 | ||
| 558 | msg = "netlink interface"; | ||
| 571 | err = rtnl_link_register(&vti_link_ops); | 559 | err = rtnl_link_register(&vti_link_ops); |
| 572 | if (err < 0) | 560 | if (err < 0) |
| 573 | goto rtnl_link_failed; | 561 | goto rtnl_link_failed; |
| @@ -576,23 +564,23 @@ static int __init vti_init(void) | |||
| 576 | 564 | ||
| 577 | rtnl_link_failed: | 565 | rtnl_link_failed: |
| 578 | xfrm4_protocol_deregister(&vti_ipcomp4_protocol, IPPROTO_COMP); | 566 | xfrm4_protocol_deregister(&vti_ipcomp4_protocol, IPPROTO_COMP); |
| 567 | xfrm_proto_comp_failed: | ||
| 579 | xfrm4_protocol_deregister(&vti_ah4_protocol, IPPROTO_AH); | 568 | xfrm4_protocol_deregister(&vti_ah4_protocol, IPPROTO_AH); |
| 569 | xfrm_proto_ah_failed: | ||
| 580 | xfrm4_protocol_deregister(&vti_esp4_protocol, IPPROTO_ESP); | 570 | xfrm4_protocol_deregister(&vti_esp4_protocol, IPPROTO_ESP); |
| 571 | xfrm_proto_esp_failed: | ||
| 581 | unregister_pernet_device(&vti_net_ops); | 572 | unregister_pernet_device(&vti_net_ops); |
| 573 | pernet_dev_failed: | ||
| 574 | pr_err("vti init: failed to register %s\n", msg); | ||
| 582 | return err; | 575 | return err; |
| 583 | } | 576 | } |
| 584 | 577 | ||
| 585 | static void __exit vti_fini(void) | 578 | static void __exit vti_fini(void) |
| 586 | { | 579 | { |
| 587 | rtnl_link_unregister(&vti_link_ops); | 580 | rtnl_link_unregister(&vti_link_ops); |
| 588 | if (xfrm4_protocol_deregister(&vti_ipcomp4_protocol, IPPROTO_COMP)) | 581 | xfrm4_protocol_deregister(&vti_ipcomp4_protocol, IPPROTO_COMP); |
| 589 | pr_info("vti close: can't deregister tunnel\n"); | 582 | xfrm4_protocol_deregister(&vti_ah4_protocol, IPPROTO_AH); |
| 590 | if (xfrm4_protocol_deregister(&vti_ah4_protocol, IPPROTO_AH)) | 583 | xfrm4_protocol_deregister(&vti_esp4_protocol, IPPROTO_ESP); |
| 591 | pr_info("vti close: can't deregister tunnel\n"); | ||
| 592 | if (xfrm4_protocol_deregister(&vti_esp4_protocol, IPPROTO_ESP)) | ||
| 593 | pr_info("vti close: can't deregister tunnel\n"); | ||
| 594 | |||
| 595 | |||
| 596 | unregister_pernet_device(&vti_net_ops); | 584 | unregister_pernet_device(&vti_net_ops); |
| 597 | } | 585 | } |
| 598 | 586 | ||
diff --git a/net/ipv4/ipconfig.c b/net/ipv4/ipconfig.c index b3e86ea7b71b..5bbef4fdcb43 100644 --- a/net/ipv4/ipconfig.c +++ b/net/ipv4/ipconfig.c | |||
| @@ -143,8 +143,6 @@ __be32 ic_servaddr = NONE; /* Boot server IP address */ | |||
| 143 | __be32 root_server_addr = NONE; /* Address of NFS server */ | 143 | __be32 root_server_addr = NONE; /* Address of NFS server */ |
| 144 | u8 root_server_path[256] = { 0, }; /* Path to mount as root */ | 144 | u8 root_server_path[256] = { 0, }; /* Path to mount as root */ |
| 145 | 145 | ||
| 146 | __be32 ic_dev_xid; /* Device under configuration */ | ||
| 147 | |||
| 148 | /* vendor class identifier */ | 146 | /* vendor class identifier */ |
| 149 | static char vendor_class_identifier[253] __initdata; | 147 | static char vendor_class_identifier[253] __initdata; |
| 150 | 148 | ||
| @@ -654,6 +652,7 @@ static struct packet_type bootp_packet_type __initdata = { | |||
| 654 | .func = ic_bootp_recv, | 652 | .func = ic_bootp_recv, |
| 655 | }; | 653 | }; |
| 656 | 654 | ||
| 655 | static __be32 ic_dev_xid; /* Device under configuration */ | ||
| 657 | 656 | ||
| 658 | /* | 657 | /* |
| 659 | * Initialize DHCP/BOOTP extension fields in the request. | 658 | * Initialize DHCP/BOOTP extension fields in the request. |
| @@ -1218,10 +1217,10 @@ static int __init ic_dynamic(void) | |||
| 1218 | get_random_bytes(&timeout, sizeof(timeout)); | 1217 | get_random_bytes(&timeout, sizeof(timeout)); |
| 1219 | timeout = CONF_BASE_TIMEOUT + (timeout % (unsigned int) CONF_TIMEOUT_RANDOM); | 1218 | timeout = CONF_BASE_TIMEOUT + (timeout % (unsigned int) CONF_TIMEOUT_RANDOM); |
| 1220 | for (;;) { | 1219 | for (;;) { |
| 1220 | #ifdef IPCONFIG_BOOTP | ||
| 1221 | /* Track the device we are configuring */ | 1221 | /* Track the device we are configuring */ |
| 1222 | ic_dev_xid = d->xid; | 1222 | ic_dev_xid = d->xid; |
| 1223 | 1223 | ||
| 1224 | #ifdef IPCONFIG_BOOTP | ||
| 1225 | if (do_bootp && (d->able & IC_BOOTP)) | 1224 | if (do_bootp && (d->able & IC_BOOTP)) |
| 1226 | ic_bootp_send_if(d, jiffies - start_jiffies); | 1225 | ic_bootp_send_if(d, jiffies - start_jiffies); |
| 1227 | #endif | 1226 | #endif |
diff --git a/net/ipv4/ipmr.c b/net/ipv4/ipmr.c index 65bcaa789043..c8034587859d 100644 --- a/net/ipv4/ipmr.c +++ b/net/ipv4/ipmr.c | |||
| @@ -500,7 +500,7 @@ static struct net_device *ipmr_reg_vif(struct net *net, struct mr_table *mrt) | |||
| 500 | else | 500 | else |
| 501 | sprintf(name, "pimreg%u", mrt->id); | 501 | sprintf(name, "pimreg%u", mrt->id); |
| 502 | 502 | ||
| 503 | dev = alloc_netdev(0, name, reg_vif_setup); | 503 | dev = alloc_netdev(0, name, NET_NAME_UNKNOWN, reg_vif_setup); |
| 504 | 504 | ||
| 505 | if (dev == NULL) | 505 | if (dev == NULL) |
| 506 | return NULL; | 506 | return NULL; |
diff --git a/net/ipv4/netfilter/Kconfig b/net/ipv4/netfilter/Kconfig index a26ce035e3fa..fb173126f03d 100644 --- a/net/ipv4/netfilter/Kconfig +++ b/net/ipv4/netfilter/Kconfig | |||
| @@ -36,6 +36,16 @@ config NF_CONNTRACK_PROC_COMPAT | |||
| 36 | 36 | ||
| 37 | If unsure, say Y. | 37 | If unsure, say Y. |
| 38 | 38 | ||
| 39 | config NF_LOG_ARP | ||
| 40 | tristate "ARP packet logging" | ||
| 41 | default m if NETFILTER_ADVANCED=n | ||
| 42 | select NF_LOG_COMMON | ||
| 43 | |||
| 44 | config NF_LOG_IPV4 | ||
| 45 | tristate "IPv4 packet logging" | ||
| 46 | default m if NETFILTER_ADVANCED=n | ||
| 47 | select NF_LOG_COMMON | ||
| 48 | |||
| 39 | config NF_TABLES_IPV4 | 49 | config NF_TABLES_IPV4 |
| 40 | depends on NF_TABLES | 50 | depends on NF_TABLES |
| 41 | tristate "IPv4 nf_tables support" | 51 | tristate "IPv4 nf_tables support" |
| @@ -159,25 +169,6 @@ config IP_NF_TARGET_SYNPROXY | |||
| 159 | 169 | ||
| 160 | To compile it as a module, choose M here. If unsure, say N. | 170 | To compile it as a module, choose M here. If unsure, say N. |
| 161 | 171 | ||
| 162 | config IP_NF_TARGET_ULOG | ||
| 163 | tristate "ULOG target support (obsolete)" | ||
| 164 | default m if NETFILTER_ADVANCED=n | ||
| 165 | ---help--- | ||
| 166 | |||
| 167 | This option enables the old IPv4-only "ipt_ULOG" implementation | ||
| 168 | which has been obsoleted by the new "nfnetlink_log" code (see | ||
| 169 | CONFIG_NETFILTER_NETLINK_LOG). | ||
| 170 | |||
| 171 | This option adds a `ULOG' target, which allows you to create rules in | ||
| 172 | any iptables table. The packet is passed to a userspace logging | ||
| 173 | daemon using netlink multicast sockets; unlike the LOG target | ||
| 174 | which can only be viewed through syslog. | ||
| 175 | |||
| 176 | The appropriate userspace logging daemon (ulogd) may be obtained from | ||
| 177 | <http://www.netfilter.org/projects/ulogd/index.html> | ||
| 178 | |||
| 179 | To compile it as a module, choose M here. If unsure, say N. | ||
| 180 | |||
| 181 | # NAT + specific targets: nf_conntrack | 172 | # NAT + specific targets: nf_conntrack |
| 182 | config NF_NAT_IPV4 | 173 | config NF_NAT_IPV4 |
| 183 | tristate "IPv4 NAT" | 174 | tristate "IPv4 NAT" |
diff --git a/net/ipv4/netfilter/Makefile b/net/ipv4/netfilter/Makefile index 90b82405331e..33001621465b 100644 --- a/net/ipv4/netfilter/Makefile +++ b/net/ipv4/netfilter/Makefile | |||
| @@ -19,6 +19,10 @@ obj-$(CONFIG_NF_NAT_IPV4) += nf_nat_ipv4.o | |||
| 19 | # defrag | 19 | # defrag |
| 20 | obj-$(CONFIG_NF_DEFRAG_IPV4) += nf_defrag_ipv4.o | 20 | obj-$(CONFIG_NF_DEFRAG_IPV4) += nf_defrag_ipv4.o |
| 21 | 21 | ||
| 22 | # logging | ||
| 23 | obj-$(CONFIG_NF_LOG_ARP) += nf_log_arp.o | ||
| 24 | obj-$(CONFIG_NF_LOG_IPV4) += nf_log_ipv4.o | ||
| 25 | |||
| 22 | # NAT helpers (nf_conntrack) | 26 | # NAT helpers (nf_conntrack) |
| 23 | obj-$(CONFIG_NF_NAT_H323) += nf_nat_h323.o | 27 | obj-$(CONFIG_NF_NAT_H323) += nf_nat_h323.o |
| 24 | obj-$(CONFIG_NF_NAT_PPTP) += nf_nat_pptp.o | 28 | obj-$(CONFIG_NF_NAT_PPTP) += nf_nat_pptp.o |
| @@ -53,7 +57,6 @@ obj-$(CONFIG_IP_NF_TARGET_ECN) += ipt_ECN.o | |||
| 53 | obj-$(CONFIG_IP_NF_TARGET_MASQUERADE) += ipt_MASQUERADE.o | 57 | obj-$(CONFIG_IP_NF_TARGET_MASQUERADE) += ipt_MASQUERADE.o |
| 54 | obj-$(CONFIG_IP_NF_TARGET_REJECT) += ipt_REJECT.o | 58 | obj-$(CONFIG_IP_NF_TARGET_REJECT) += ipt_REJECT.o |
| 55 | obj-$(CONFIG_IP_NF_TARGET_SYNPROXY) += ipt_SYNPROXY.o | 59 | obj-$(CONFIG_IP_NF_TARGET_SYNPROXY) += ipt_SYNPROXY.o |
| 56 | obj-$(CONFIG_IP_NF_TARGET_ULOG) += ipt_ULOG.o | ||
| 57 | 60 | ||
| 58 | # generic ARP tables | 61 | # generic ARP tables |
| 59 | obj-$(CONFIG_IP_NF_ARPTABLES) += arp_tables.o | 62 | obj-$(CONFIG_IP_NF_ARPTABLES) += arp_tables.o |
diff --git a/net/ipv4/netfilter/ipt_ULOG.c b/net/ipv4/netfilter/ipt_ULOG.c deleted file mode 100644 index 9cb993cd224b..000000000000 --- a/net/ipv4/netfilter/ipt_ULOG.c +++ /dev/null | |||
| @@ -1,498 +0,0 @@ | |||
| 1 | /* | ||
| 2 | * netfilter module for userspace packet logging daemons | ||
| 3 | * | ||
| 4 | * (C) 2000-2004 by Harald Welte <laforge@netfilter.org> | ||
| 5 | * (C) 1999-2001 Paul `Rusty' Russell | ||
| 6 | * (C) 2002-2004 Netfilter Core Team <coreteam@netfilter.org> | ||
| 7 | * (C) 2005-2007 Patrick McHardy <kaber@trash.net> | ||
| 8 | * | ||
| 9 | * This program is free software; you can redistribute it and/or modify | ||
| 10 | * it under the terms of the GNU General Public License version 2 as | ||
| 11 | * published by the Free Software Foundation. | ||
| 12 | * | ||
| 13 | * This module accepts two parameters: | ||
| 14 | * | ||
| 15 | * nlbufsiz: | ||
| 16 | * The parameter specifies how big the buffer for each netlink multicast | ||
| 17 | * group is. e.g. If you say nlbufsiz=8192, up to eight kb of packets will | ||
| 18 | * get accumulated in the kernel until they are sent to userspace. It is | ||
| 19 | * NOT possible to allocate more than 128kB, and it is strongly discouraged, | ||
| 20 | * because atomically allocating 128kB inside the network rx softirq is not | ||
| 21 | * reliable. Please also keep in mind that this buffer size is allocated for | ||
| 22 | * each nlgroup you are using, so the total kernel memory usage increases | ||
| 23 | * by that factor. | ||
| 24 | * | ||
| 25 | * Actually you should use nlbufsiz a bit smaller than PAGE_SIZE, since | ||
| 26 | * nlbufsiz is used with alloc_skb, which adds another | ||
| 27 | * sizeof(struct skb_shared_info). Use NLMSG_GOODSIZE instead. | ||
| 28 | * | ||
| 29 | * flushtimeout: | ||
| 30 | * Specify, after how many hundredths of a second the queue should be | ||
| 31 | * flushed even if it is not full yet. | ||
| 32 | */ | ||
| 33 | #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt | ||
| 34 | #include <linux/module.h> | ||
| 35 | #include <linux/spinlock.h> | ||
| 36 | #include <linux/socket.h> | ||
| 37 | #include <linux/slab.h> | ||
| 38 | #include <linux/skbuff.h> | ||
| 39 | #include <linux/kernel.h> | ||
| 40 | #include <linux/timer.h> | ||
| 41 | #include <net/netlink.h> | ||
| 42 | #include <linux/netdevice.h> | ||
| 43 | #include <linux/mm.h> | ||
| 44 | #include <linux/moduleparam.h> | ||
| 45 | #include <linux/netfilter.h> | ||
| 46 | #include <linux/netfilter/x_tables.h> | ||
| 47 | #include <linux/netfilter_ipv4/ipt_ULOG.h> | ||
| 48 | #include <net/netfilter/nf_log.h> | ||
| 49 | #include <net/netns/generic.h> | ||
| 50 | #include <net/sock.h> | ||
| 51 | #include <linux/bitops.h> | ||
| 52 | #include <asm/unaligned.h> | ||
| 53 | |||
| 54 | MODULE_LICENSE("GPL"); | ||
| 55 | MODULE_AUTHOR("Harald Welte <laforge@gnumonks.org>"); | ||
| 56 | MODULE_DESCRIPTION("Xtables: packet logging to netlink using ULOG"); | ||
| 57 | MODULE_ALIAS_NET_PF_PROTO(PF_NETLINK, NETLINK_NFLOG); | ||
| 58 | |||
| 59 | #define ULOG_NL_EVENT 111 /* Harald's favorite number */ | ||
| 60 | #define ULOG_MAXNLGROUPS 32 /* numer of nlgroups */ | ||
| 61 | |||
| 62 | static unsigned int nlbufsiz = NLMSG_GOODSIZE; | ||
| 63 | module_param(nlbufsiz, uint, 0400); | ||
| 64 | MODULE_PARM_DESC(nlbufsiz, "netlink buffer size"); | ||
| 65 | |||
| 66 | static unsigned int flushtimeout = 10; | ||
| 67 | module_param(flushtimeout, uint, 0600); | ||
| 68 | MODULE_PARM_DESC(flushtimeout, "buffer flush timeout (hundredths of a second)"); | ||
| 69 | |||
| 70 | static bool nflog = true; | ||
| 71 | module_param(nflog, bool, 0400); | ||
| 72 | MODULE_PARM_DESC(nflog, "register as internal netfilter logging module"); | ||
| 73 | |||
| 74 | /* global data structures */ | ||
| 75 | |||
| 76 | typedef struct { | ||
| 77 | unsigned int qlen; /* number of nlmsgs' in the skb */ | ||
| 78 | struct nlmsghdr *lastnlh; /* netlink header of last msg in skb */ | ||
| 79 | struct sk_buff *skb; /* the pre-allocated skb */ | ||
| 80 | struct timer_list timer; /* the timer function */ | ||
| 81 | } ulog_buff_t; | ||
| 82 | |||
| 83 | static int ulog_net_id __read_mostly; | ||
| 84 | struct ulog_net { | ||
| 85 | unsigned int nlgroup[ULOG_MAXNLGROUPS]; | ||
| 86 | ulog_buff_t ulog_buffers[ULOG_MAXNLGROUPS]; | ||
| 87 | struct sock *nflognl; | ||
| 88 | spinlock_t lock; | ||
| 89 | }; | ||
| 90 | |||
| 91 | static struct ulog_net *ulog_pernet(struct net *net) | ||
| 92 | { | ||
| 93 | return net_generic(net, ulog_net_id); | ||
| 94 | } | ||
| 95 | |||
| 96 | /* send one ulog_buff_t to userspace */ | ||
| 97 | static void ulog_send(struct ulog_net *ulog, unsigned int nlgroupnum) | ||
| 98 | { | ||
| 99 | ulog_buff_t *ub = &ulog->ulog_buffers[nlgroupnum]; | ||
| 100 | |||
| 101 | pr_debug("ulog_send: timer is deleting\n"); | ||
| 102 | del_timer(&ub->timer); | ||
| 103 | |||
| 104 | if (!ub->skb) { | ||
| 105 | pr_debug("ulog_send: nothing to send\n"); | ||
| 106 | return; | ||
| 107 | } | ||
| 108 | |||
| 109 | /* last nlmsg needs NLMSG_DONE */ | ||
| 110 | if (ub->qlen > 1) | ||
| 111 | ub->lastnlh->nlmsg_type = NLMSG_DONE; | ||
| 112 | |||
| 113 | NETLINK_CB(ub->skb).dst_group = nlgroupnum + 1; | ||
| 114 | pr_debug("throwing %d packets to netlink group %u\n", | ||
| 115 | ub->qlen, nlgroupnum + 1); | ||
| 116 | netlink_broadcast(ulog->nflognl, ub->skb, 0, nlgroupnum + 1, | ||
| 117 | GFP_ATOMIC); | ||
| 118 | |||
| 119 | ub->qlen = 0; | ||
| 120 | ub->skb = NULL; | ||
| 121 | ub->lastnlh = NULL; | ||
| 122 | } | ||
| 123 | |||
| 124 | |||
| 125 | /* timer function to flush queue in flushtimeout time */ | ||
| 126 | static void ulog_timer(unsigned long data) | ||
| 127 | { | ||
| 128 | unsigned int groupnum = *((unsigned int *)data); | ||
| 129 | struct ulog_net *ulog = container_of((void *)data, | ||
| 130 | struct ulog_net, | ||
| 131 | nlgroup[groupnum]); | ||
| 132 | pr_debug("timer function called, calling ulog_send\n"); | ||
| 133 | |||
| 134 | /* lock to protect against somebody modifying our structure | ||
| 135 | * from ipt_ulog_target at the same time */ | ||
| 136 | spin_lock_bh(&ulog->lock); | ||
| 137 | ulog_send(ulog, groupnum); | ||
| 138 | spin_unlock_bh(&ulog->lock); | ||
| 139 | } | ||
| 140 | |||
| 141 | static struct sk_buff *ulog_alloc_skb(unsigned int size) | ||
| 142 | { | ||
| 143 | struct sk_buff *skb; | ||
| 144 | unsigned int n; | ||
| 145 | |||
| 146 | /* alloc skb which should be big enough for a whole | ||
| 147 | * multipart message. WARNING: has to be <= 131000 | ||
| 148 | * due to slab allocator restrictions */ | ||
| 149 | |||
| 150 | n = max(size, nlbufsiz); | ||
| 151 | skb = alloc_skb(n, GFP_ATOMIC | __GFP_NOWARN); | ||
| 152 | if (!skb) { | ||
| 153 | if (n > size) { | ||
| 154 | /* try to allocate only as much as we need for | ||
| 155 | * current packet */ | ||
| 156 | |||
| 157 | skb = alloc_skb(size, GFP_ATOMIC); | ||
| 158 | if (!skb) | ||
| 159 | pr_debug("cannot even allocate %ub\n", size); | ||
| 160 | } | ||
| 161 | } | ||
| 162 | |||
| 163 | return skb; | ||
| 164 | } | ||
| 165 | |||
| 166 | static void ipt_ulog_packet(struct net *net, | ||
| 167 | unsigned int hooknum, | ||
| 168 | const struct sk_buff *skb, | ||
| 169 | const struct net_device *in, | ||
| 170 | const struct net_device *out, | ||
| 171 | const struct ipt_ulog_info *loginfo, | ||
| 172 | const char *prefix) | ||
| 173 | { | ||
| 174 | ulog_buff_t *ub; | ||
| 175 | ulog_packet_msg_t *pm; | ||
| 176 | size_t size, copy_len; | ||
| 177 | struct nlmsghdr *nlh; | ||
| 178 | struct timeval tv; | ||
| 179 | struct ulog_net *ulog = ulog_pernet(net); | ||
| 180 | |||
| 181 | /* ffs == find first bit set, necessary because userspace | ||
| 182 | * is already shifting groupnumber, but we need unshifted. | ||
| 183 | * ffs() returns [1..32], we need [0..31] */ | ||
| 184 | unsigned int groupnum = ffs(loginfo->nl_group) - 1; | ||
| 185 | |||
| 186 | /* calculate the size of the skb needed */ | ||
| 187 | if (loginfo->copy_range == 0 || loginfo->copy_range > skb->len) | ||
| 188 | copy_len = skb->len; | ||
| 189 | else | ||
| 190 | copy_len = loginfo->copy_range; | ||
| 191 | |||
| 192 | size = nlmsg_total_size(sizeof(*pm) + copy_len); | ||
| 193 | |||
| 194 | ub = &ulog->ulog_buffers[groupnum]; | ||
| 195 | |||
| 196 | spin_lock_bh(&ulog->lock); | ||
| 197 | |||
| 198 | if (!ub->skb) { | ||
| 199 | if (!(ub->skb = ulog_alloc_skb(size))) | ||
| 200 | goto alloc_failure; | ||
| 201 | } else if (ub->qlen >= loginfo->qthreshold || | ||
| 202 | size > skb_tailroom(ub->skb)) { | ||
| 203 | /* either the queue len is too high or we don't have | ||
| 204 | * enough room in nlskb left. send it to userspace. */ | ||
| 205 | |||
| 206 | ulog_send(ulog, groupnum); | ||
| 207 | |||
| 208 | if (!(ub->skb = ulog_alloc_skb(size))) | ||
| 209 | goto alloc_failure; | ||
| 210 | } | ||
| 211 | |||
| 212 | pr_debug("qlen %d, qthreshold %Zu\n", ub->qlen, loginfo->qthreshold); | ||
| 213 | |||
| 214 | nlh = nlmsg_put(ub->skb, 0, ub->qlen, ULOG_NL_EVENT, | ||
| 215 | sizeof(*pm)+copy_len, 0); | ||
| 216 | if (!nlh) { | ||
| 217 | pr_debug("error during nlmsg_put\n"); | ||
| 218 | goto out_unlock; | ||
| 219 | } | ||
| 220 | ub->qlen++; | ||
| 221 | |||
| 222 | pm = nlmsg_data(nlh); | ||
| 223 | memset(pm, 0, sizeof(*pm)); | ||
| 224 | |||
| 225 | /* We might not have a timestamp, get one */ | ||
| 226 | if (skb->tstamp.tv64 == 0) | ||
| 227 | __net_timestamp((struct sk_buff *)skb); | ||
| 228 | |||
| 229 | /* copy hook, prefix, timestamp, payload, etc. */ | ||
| 230 | pm->data_len = copy_len; | ||
| 231 | tv = ktime_to_timeval(skb->tstamp); | ||
| 232 | put_unaligned(tv.tv_sec, &pm->timestamp_sec); | ||
| 233 | put_unaligned(tv.tv_usec, &pm->timestamp_usec); | ||
| 234 | put_unaligned(skb->mark, &pm->mark); | ||
| 235 | pm->hook = hooknum; | ||
| 236 | if (prefix != NULL) { | ||
| 237 | strncpy(pm->prefix, prefix, sizeof(pm->prefix) - 1); | ||
| 238 | pm->prefix[sizeof(pm->prefix) - 1] = '\0'; | ||
| 239 | } | ||
| 240 | else if (loginfo->prefix[0] != '\0') | ||
| 241 | strncpy(pm->prefix, loginfo->prefix, sizeof(pm->prefix)); | ||
| 242 | |||
| 243 | if (in && in->hard_header_len > 0 && | ||
| 244 | skb->mac_header != skb->network_header && | ||
| 245 | in->hard_header_len <= ULOG_MAC_LEN) { | ||
| 246 | memcpy(pm->mac, skb_mac_header(skb), in->hard_header_len); | ||
| 247 | pm->mac_len = in->hard_header_len; | ||
| 248 | } else | ||
| 249 | pm->mac_len = 0; | ||
| 250 | |||
| 251 | if (in) | ||
| 252 | strncpy(pm->indev_name, in->name, sizeof(pm->indev_name)); | ||
| 253 | |||
| 254 | if (out) | ||
| 255 | strncpy(pm->outdev_name, out->name, sizeof(pm->outdev_name)); | ||
| 256 | |||
| 257 | /* copy_len <= skb->len, so can't fail. */ | ||
| 258 | if (skb_copy_bits(skb, 0, pm->payload, copy_len) < 0) | ||
| 259 | BUG(); | ||
| 260 | |||
| 261 | /* check if we are building multi-part messages */ | ||
| 262 | if (ub->qlen > 1) | ||
| 263 | ub->lastnlh->nlmsg_flags |= NLM_F_MULTI; | ||
| 264 | |||
| 265 | ub->lastnlh = nlh; | ||
| 266 | |||
| 267 | /* if timer isn't already running, start it */ | ||
| 268 | if (!timer_pending(&ub->timer)) { | ||
| 269 | ub->timer.expires = jiffies + flushtimeout * HZ / 100; | ||
| 270 | add_timer(&ub->timer); | ||
| 271 | } | ||
| 272 | |||
| 273 | /* if threshold is reached, send message to userspace */ | ||
| 274 | if (ub->qlen >= loginfo->qthreshold) { | ||
| 275 | if (loginfo->qthreshold > 1) | ||
| 276 | nlh->nlmsg_type = NLMSG_DONE; | ||
| 277 | ulog_send(ulog, groupnum); | ||
| 278 | } | ||
| 279 | out_unlock: | ||
| 280 | spin_unlock_bh(&ulog->lock); | ||
| 281 | |||
| 282 | return; | ||
| 283 | |||
| 284 | alloc_failure: | ||
| 285 | pr_debug("Error building netlink message\n"); | ||
| 286 | spin_unlock_bh(&ulog->lock); | ||
| 287 | } | ||
| 288 | |||
| 289 | static unsigned int | ||
| 290 | ulog_tg(struct sk_buff *skb, const struct xt_action_param *par) | ||
| 291 | { | ||
| 292 | struct net *net = dev_net(par->in ? par->in : par->out); | ||
| 293 | |||
| 294 | ipt_ulog_packet(net, par->hooknum, skb, par->in, par->out, | ||
| 295 | par->targinfo, NULL); | ||
| 296 | return XT_CONTINUE; | ||
| 297 | } | ||
| 298 | |||
| 299 | static void ipt_logfn(struct net *net, | ||
| 300 | u_int8_t pf, | ||
| 301 | unsigned int hooknum, | ||
| 302 | const struct sk_buff *skb, | ||
| 303 | const struct net_device *in, | ||
| 304 | const struct net_device *out, | ||
| 305 | const struct nf_loginfo *li, | ||
| 306 | const char *prefix) | ||
| 307 | { | ||
| 308 | struct ipt_ulog_info loginfo; | ||
| 309 | |||
| 310 | if (!li || li->type != NF_LOG_TYPE_ULOG) { | ||
| 311 | loginfo.nl_group = ULOG_DEFAULT_NLGROUP; | ||
| 312 | loginfo.copy_range = 0; | ||
| 313 | loginfo.qthreshold = ULOG_DEFAULT_QTHRESHOLD; | ||
| 314 | loginfo.prefix[0] = '\0'; | ||
| 315 | } else { | ||
| 316 | loginfo.nl_group = li->u.ulog.group; | ||
| 317 | loginfo.copy_range = li->u.ulog.copy_len; | ||
| 318 | loginfo.qthreshold = li->u.ulog.qthreshold; | ||
| 319 | strlcpy(loginfo.prefix, prefix, sizeof(loginfo.prefix)); | ||
| 320 | } | ||
| 321 | |||
| 322 | ipt_ulog_packet(net, hooknum, skb, in, out, &loginfo, prefix); | ||
| 323 | } | ||
| 324 | |||
| 325 | static int ulog_tg_check(const struct xt_tgchk_param *par) | ||
| 326 | { | ||
| 327 | const struct ipt_ulog_info *loginfo = par->targinfo; | ||
| 328 | |||
| 329 | if (!par->net->xt.ulog_warn_deprecated) { | ||
| 330 | pr_info("ULOG is deprecated and it will be removed soon, " | ||
| 331 | "use NFLOG instead\n"); | ||
| 332 | par->net->xt.ulog_warn_deprecated = true; | ||
| 333 | } | ||
| 334 | |||
| 335 | if (loginfo->prefix[sizeof(loginfo->prefix) - 1] != '\0') { | ||
| 336 | pr_debug("prefix not null-terminated\n"); | ||
| 337 | return -EINVAL; | ||
| 338 | } | ||
| 339 | if (loginfo->qthreshold > ULOG_MAX_QLEN) { | ||
| 340 | pr_debug("queue threshold %Zu > MAX_QLEN\n", | ||
| 341 | loginfo->qthreshold); | ||
| 342 | return -EINVAL; | ||
| 343 | } | ||
| 344 | return 0; | ||
| 345 | } | ||
| 346 | |||
| 347 | #ifdef CONFIG_COMPAT | ||
| 348 | struct compat_ipt_ulog_info { | ||
| 349 | compat_uint_t nl_group; | ||
| 350 | compat_size_t copy_range; | ||
| 351 | compat_size_t qthreshold; | ||
| 352 | char prefix[ULOG_PREFIX_LEN]; | ||
| 353 | }; | ||
| 354 | |||
| 355 | static void ulog_tg_compat_from_user(void *dst, const void *src) | ||
| 356 | { | ||
| 357 | const struct compat_ipt_ulog_info *cl = src; | ||
| 358 | struct ipt_ulog_info l = { | ||
| 359 | .nl_group = cl->nl_group, | ||
| 360 | .copy_range = cl->copy_range, | ||
| 361 | .qthreshold = cl->qthreshold, | ||
| 362 | }; | ||
| 363 | |||
| 364 | memcpy(l.prefix, cl->prefix, sizeof(l.prefix)); | ||
| 365 | memcpy(dst, &l, sizeof(l)); | ||
| 366 | } | ||
| 367 | |||
| 368 | static int ulog_tg_compat_to_user(void __user *dst, const void *src) | ||
| 369 | { | ||
| 370 | const struct ipt_ulog_info *l = src; | ||
| 371 | struct compat_ipt_ulog_info cl = { | ||
| 372 | .nl_group = l->nl_group, | ||
| 373 | .copy_range = l->copy_range, | ||
| 374 | .qthreshold = l->qthreshold, | ||
| 375 | }; | ||
| 376 | |||
| 377 | memcpy(cl.prefix, l->prefix, sizeof(cl.prefix)); | ||
| 378 | return copy_to_user(dst, &cl, sizeof(cl)) ? -EFAULT : 0; | ||
| 379 | } | ||
| 380 | #endif /* CONFIG_COMPAT */ | ||
| 381 | |||
| 382 | static struct xt_target ulog_tg_reg __read_mostly = { | ||
| 383 | .name = "ULOG", | ||
| 384 | .family = NFPROTO_IPV4, | ||
| 385 | .target = ulog_tg, | ||
| 386 | .targetsize = sizeof(struct ipt_ulog_info), | ||
| 387 | .checkentry = ulog_tg_check, | ||
| 388 | #ifdef CONFIG_COMPAT | ||
| 389 | .compatsize = sizeof(struct compat_ipt_ulog_info), | ||
| 390 | .compat_from_user = ulog_tg_compat_from_user, | ||
| 391 | .compat_to_user = ulog_tg_compat_to_user, | ||
| 392 | #endif | ||
| 393 | .me = THIS_MODULE, | ||
| 394 | }; | ||
| 395 | |||
| 396 | static struct nf_logger ipt_ulog_logger __read_mostly = { | ||
| 397 | .name = "ipt_ULOG", | ||
| 398 | .logfn = ipt_logfn, | ||
| 399 | .me = THIS_MODULE, | ||
| 400 | }; | ||
| 401 | |||
| 402 | static int __net_init ulog_tg_net_init(struct net *net) | ||
| 403 | { | ||
| 404 | int i; | ||
| 405 | struct ulog_net *ulog = ulog_pernet(net); | ||
| 406 | struct netlink_kernel_cfg cfg = { | ||
| 407 | .groups = ULOG_MAXNLGROUPS, | ||
| 408 | }; | ||
| 409 | |||
| 410 | spin_lock_init(&ulog->lock); | ||
| 411 | /* initialize ulog_buffers */ | ||
| 412 | for (i = 0; i < ULOG_MAXNLGROUPS; i++) { | ||
| 413 | ulog->nlgroup[i] = i; | ||
| 414 | setup_timer(&ulog->ulog_buffers[i].timer, ulog_timer, | ||
| 415 | (unsigned long)&ulog->nlgroup[i]); | ||
| 416 | } | ||
| 417 | |||
| 418 | ulog->nflognl = netlink_kernel_create(net, NETLINK_NFLOG, &cfg); | ||
| 419 | if (!ulog->nflognl) | ||
| 420 | return -ENOMEM; | ||
| 421 | |||
| 422 | if (nflog) | ||
| 423 | nf_log_set(net, NFPROTO_IPV4, &ipt_ulog_logger); | ||
| 424 | |||
| 425 | return 0; | ||
| 426 | } | ||
| 427 | |||
| 428 | static void __net_exit ulog_tg_net_exit(struct net *net) | ||
| 429 | { | ||
| 430 | ulog_buff_t *ub; | ||
| 431 | int i; | ||
| 432 | struct ulog_net *ulog = ulog_pernet(net); | ||
| 433 | |||
| 434 | if (nflog) | ||
| 435 | nf_log_unset(net, &ipt_ulog_logger); | ||
| 436 | |||
| 437 | netlink_kernel_release(ulog->nflognl); | ||
| 438 | |||
| 439 | /* remove pending timers and free allocated skb's */ | ||
| 440 | for (i = 0; i < ULOG_MAXNLGROUPS; i++) { | ||
| 441 | ub = &ulog->ulog_buffers[i]; | ||
| 442 | pr_debug("timer is deleting\n"); | ||
| 443 | del_timer(&ub->timer); | ||
| 444 | |||
| 445 | if (ub->skb) { | ||
| 446 | kfree_skb(ub->skb); | ||
| 447 | ub->skb = NULL; | ||
| 448 | } | ||
| 449 | } | ||
| 450 | } | ||
| 451 | |||
| 452 | static struct pernet_operations ulog_tg_net_ops = { | ||
| 453 | .init = ulog_tg_net_init, | ||
| 454 | .exit = ulog_tg_net_exit, | ||
| 455 | .id = &ulog_net_id, | ||
| 456 | .size = sizeof(struct ulog_net), | ||
| 457 | }; | ||
| 458 | |||
| 459 | static int __init ulog_tg_init(void) | ||
| 460 | { | ||
| 461 | int ret; | ||
| 462 | pr_debug("init module\n"); | ||
| 463 | |||
| 464 | if (nlbufsiz > 128*1024) { | ||
| 465 | pr_warn("Netlink buffer has to be <= 128kB\n"); | ||
| 466 | return -EINVAL; | ||
| 467 | } | ||
| 468 | |||
| 469 | ret = register_pernet_subsys(&ulog_tg_net_ops); | ||
| 470 | if (ret) | ||
| 471 | goto out_pernet; | ||
| 472 | |||
| 473 | ret = xt_register_target(&ulog_tg_reg); | ||
| 474 | if (ret < 0) | ||
| 475 | goto out_target; | ||
| 476 | |||
| 477 | if (nflog) | ||
| 478 | nf_log_register(NFPROTO_IPV4, &ipt_ulog_logger); | ||
| 479 | |||
| 480 | return 0; | ||
| 481 | |||
| 482 | out_target: | ||
| 483 | unregister_pernet_subsys(&ulog_tg_net_ops); | ||
| 484 | out_pernet: | ||
| 485 | return ret; | ||
| 486 | } | ||
| 487 | |||
| 488 | static void __exit ulog_tg_exit(void) | ||
| 489 | { | ||
| 490 | pr_debug("cleanup_module\n"); | ||
| 491 | if (nflog) | ||
| 492 | nf_log_unregister(&ipt_ulog_logger); | ||
| 493 | xt_unregister_target(&ulog_tg_reg); | ||
| 494 | unregister_pernet_subsys(&ulog_tg_net_ops); | ||
| 495 | } | ||
| 496 | |||
| 497 | module_init(ulog_tg_init); | ||
| 498 | module_exit(ulog_tg_exit); | ||
diff --git a/net/ipv4/netfilter/nf_conntrack_l3proto_ipv4.c b/net/ipv4/netfilter/nf_conntrack_l3proto_ipv4.c index 8127dc802865..a054fe083431 100644 --- a/net/ipv4/netfilter/nf_conntrack_l3proto_ipv4.c +++ b/net/ipv4/netfilter/nf_conntrack_l3proto_ipv4.c | |||
| @@ -314,7 +314,7 @@ getorigdst(struct sock *sk, int optval, void __user *user, int *len) | |||
| 314 | return -ENOENT; | 314 | return -ENOENT; |
| 315 | } | 315 | } |
| 316 | 316 | ||
| 317 | #if defined(CONFIG_NF_CT_NETLINK) || defined(CONFIG_NF_CT_NETLINK_MODULE) | 317 | #if IS_ENABLED(CONFIG_NF_CT_NETLINK) |
| 318 | 318 | ||
| 319 | #include <linux/netfilter/nfnetlink.h> | 319 | #include <linux/netfilter/nfnetlink.h> |
| 320 | #include <linux/netfilter/nfnetlink_conntrack.h> | 320 | #include <linux/netfilter/nfnetlink_conntrack.h> |
| @@ -358,7 +358,7 @@ static struct nf_sockopt_ops so_getorigdst = { | |||
| 358 | .pf = PF_INET, | 358 | .pf = PF_INET, |
| 359 | .get_optmin = SO_ORIGINAL_DST, | 359 | .get_optmin = SO_ORIGINAL_DST, |
| 360 | .get_optmax = SO_ORIGINAL_DST+1, | 360 | .get_optmax = SO_ORIGINAL_DST+1, |
| 361 | .get = &getorigdst, | 361 | .get = getorigdst, |
| 362 | .owner = THIS_MODULE, | 362 | .owner = THIS_MODULE, |
| 363 | }; | 363 | }; |
| 364 | 364 | ||
| @@ -388,7 +388,7 @@ struct nf_conntrack_l3proto nf_conntrack_l3proto_ipv4 __read_mostly = { | |||
| 388 | .invert_tuple = ipv4_invert_tuple, | 388 | .invert_tuple = ipv4_invert_tuple, |
| 389 | .print_tuple = ipv4_print_tuple, | 389 | .print_tuple = ipv4_print_tuple, |
| 390 | .get_l4proto = ipv4_get_l4proto, | 390 | .get_l4proto = ipv4_get_l4proto, |
| 391 | #if defined(CONFIG_NF_CT_NETLINK) || defined(CONFIG_NF_CT_NETLINK_MODULE) | 391 | #if IS_ENABLED(CONFIG_NF_CT_NETLINK) |
| 392 | .tuple_to_nlattr = ipv4_tuple_to_nlattr, | 392 | .tuple_to_nlattr = ipv4_tuple_to_nlattr, |
| 393 | .nlattr_tuple_size = ipv4_nlattr_tuple_size, | 393 | .nlattr_tuple_size = ipv4_nlattr_tuple_size, |
| 394 | .nlattr_to_tuple = ipv4_nlattr_to_tuple, | 394 | .nlattr_to_tuple = ipv4_nlattr_to_tuple, |
diff --git a/net/ipv4/netfilter/nf_conntrack_proto_icmp.c b/net/ipv4/netfilter/nf_conntrack_proto_icmp.c index a338dad41b7d..b91b2641adda 100644 --- a/net/ipv4/netfilter/nf_conntrack_proto_icmp.c +++ b/net/ipv4/netfilter/nf_conntrack_proto_icmp.c | |||
| @@ -226,7 +226,7 @@ icmp_error(struct net *net, struct nf_conn *tmpl, | |||
| 226 | return icmp_error_message(net, tmpl, skb, ctinfo, hooknum); | 226 | return icmp_error_message(net, tmpl, skb, ctinfo, hooknum); |
| 227 | } | 227 | } |
| 228 | 228 | ||
| 229 | #if defined(CONFIG_NF_CT_NETLINK) || defined(CONFIG_NF_CT_NETLINK_MODULE) | 229 | #if IS_ENABLED(CONFIG_NF_CT_NETLINK) |
| 230 | 230 | ||
| 231 | #include <linux/netfilter/nfnetlink.h> | 231 | #include <linux/netfilter/nfnetlink.h> |
| 232 | #include <linux/netfilter/nfnetlink_conntrack.h> | 232 | #include <linux/netfilter/nfnetlink_conntrack.h> |
| @@ -408,7 +408,7 @@ struct nf_conntrack_l4proto nf_conntrack_l4proto_icmp __read_mostly = | |||
| 408 | .error = icmp_error, | 408 | .error = icmp_error, |
| 409 | .destroy = NULL, | 409 | .destroy = NULL, |
| 410 | .me = NULL, | 410 | .me = NULL, |
| 411 | #if defined(CONFIG_NF_CT_NETLINK) || defined(CONFIG_NF_CT_NETLINK_MODULE) | 411 | #if IS_ENABLED(CONFIG_NF_CT_NETLINK) |
| 412 | .tuple_to_nlattr = icmp_tuple_to_nlattr, | 412 | .tuple_to_nlattr = icmp_tuple_to_nlattr, |
| 413 | .nlattr_tuple_size = icmp_nlattr_tuple_size, | 413 | .nlattr_tuple_size = icmp_nlattr_tuple_size, |
| 414 | .nlattr_to_tuple = icmp_nlattr_to_tuple, | 414 | .nlattr_to_tuple = icmp_nlattr_to_tuple, |
diff --git a/net/ipv4/netfilter/nf_defrag_ipv4.c b/net/ipv4/netfilter/nf_defrag_ipv4.c index b8f6381c7d0b..76bd1aef257f 100644 --- a/net/ipv4/netfilter/nf_defrag_ipv4.c +++ b/net/ipv4/netfilter/nf_defrag_ipv4.c | |||
| @@ -17,7 +17,7 @@ | |||
| 17 | #include <linux/netfilter_bridge.h> | 17 | #include <linux/netfilter_bridge.h> |
| 18 | #include <linux/netfilter_ipv4.h> | 18 | #include <linux/netfilter_ipv4.h> |
| 19 | #include <net/netfilter/ipv4/nf_defrag_ipv4.h> | 19 | #include <net/netfilter/ipv4/nf_defrag_ipv4.h> |
| 20 | #if defined(CONFIG_NF_CONNTRACK) || defined(CONFIG_NF_CONNTRACK_MODULE) | 20 | #if IS_ENABLED(CONFIG_NF_CONNTRACK) |
| 21 | #include <net/netfilter/nf_conntrack.h> | 21 | #include <net/netfilter/nf_conntrack.h> |
| 22 | #endif | 22 | #endif |
| 23 | #include <net/netfilter/nf_conntrack_zones.h> | 23 | #include <net/netfilter/nf_conntrack_zones.h> |
| @@ -45,7 +45,7 @@ static enum ip_defrag_users nf_ct_defrag_user(unsigned int hooknum, | |||
| 45 | { | 45 | { |
| 46 | u16 zone = NF_CT_DEFAULT_ZONE; | 46 | u16 zone = NF_CT_DEFAULT_ZONE; |
| 47 | 47 | ||
| 48 | #if defined(CONFIG_NF_CONNTRACK) || defined(CONFIG_NF_CONNTRACK_MODULE) | 48 | #if IS_ENABLED(CONFIG_NF_CONNTRACK) |
| 49 | if (skb->nfct) | 49 | if (skb->nfct) |
| 50 | zone = nf_ct_zone((struct nf_conn *)skb->nfct); | 50 | zone = nf_ct_zone((struct nf_conn *)skb->nfct); |
| 51 | #endif | 51 | #endif |
| @@ -74,8 +74,8 @@ static unsigned int ipv4_conntrack_defrag(const struct nf_hook_ops *ops, | |||
| 74 | inet->nodefrag) | 74 | inet->nodefrag) |
| 75 | return NF_ACCEPT; | 75 | return NF_ACCEPT; |
| 76 | 76 | ||
| 77 | #if defined(CONFIG_NF_CONNTRACK) || defined(CONFIG_NF_CONNTRACK_MODULE) | 77 | #if IS_ENABLED(CONFIG_NF_CONNTRACK) |
| 78 | #if !defined(CONFIG_NF_NAT) && !defined(CONFIG_NF_NAT_MODULE) | 78 | #if !IS_ENABLED(CONFIG_NF_NAT) |
| 79 | /* Previously seen (loopback)? Ignore. Do this before | 79 | /* Previously seen (loopback)? Ignore. Do this before |
| 80 | fragment check. */ | 80 | fragment check. */ |
| 81 | if (skb->nfct && !nf_ct_is_template((struct nf_conn *)skb->nfct)) | 81 | if (skb->nfct && !nf_ct_is_template((struct nf_conn *)skb->nfct)) |
diff --git a/net/ipv4/netfilter/nf_log_arp.c b/net/ipv4/netfilter/nf_log_arp.c new file mode 100644 index 000000000000..ccfc78db12ee --- /dev/null +++ b/net/ipv4/netfilter/nf_log_arp.c | |||
| @@ -0,0 +1,149 @@ | |||
| 1 | /* | ||
| 2 | * (C) 2014 by Pablo Neira Ayuso <pablo@netfilter.org> | ||
| 3 | * | ||
| 4 | * Based on code from ebt_log from: | ||
| 5 | * | ||
| 6 | * Bart De Schuymer <bdschuym@pandora.be> | ||
| 7 | * Harald Welte <laforge@netfilter.org> | ||
| 8 | * | ||
| 9 | * This program is free software; you can redistribute it and/or modify | ||
| 10 | * it under the terms of the GNU General Public License version 2 as | ||
| 11 | * published by the Free Software Foundation. | ||
| 12 | */ | ||
| 13 | |||
| 14 | #include <linux/module.h> | ||
| 15 | #include <linux/spinlock.h> | ||
| 16 | #include <linux/skbuff.h> | ||
| 17 | #include <linux/if_arp.h> | ||
| 18 | #include <linux/ip.h> | ||
| 19 | #include <net/route.h> | ||
| 20 | |||
| 21 | #include <linux/netfilter.h> | ||
| 22 | #include <linux/netfilter/xt_LOG.h> | ||
| 23 | #include <net/netfilter/nf_log.h> | ||
| 24 | |||
| 25 | static struct nf_loginfo default_loginfo = { | ||
| 26 | .type = NF_LOG_TYPE_LOG, | ||
| 27 | .u = { | ||
| 28 | .log = { | ||
| 29 | .level = 5, | ||
| 30 | .logflags = NF_LOG_MASK, | ||
| 31 | }, | ||
| 32 | }, | ||
| 33 | }; | ||
| 34 | |||
| 35 | struct arppayload { | ||
| 36 | unsigned char mac_src[ETH_ALEN]; | ||
| 37 | unsigned char ip_src[4]; | ||
| 38 | unsigned char mac_dst[ETH_ALEN]; | ||
| 39 | unsigned char ip_dst[4]; | ||
| 40 | }; | ||
| 41 | |||
| 42 | static void dump_arp_packet(struct nf_log_buf *m, | ||
| 43 | const struct nf_loginfo *info, | ||
| 44 | const struct sk_buff *skb, unsigned int nhoff) | ||
| 45 | { | ||
| 46 | const struct arphdr *ah; | ||
| 47 | struct arphdr _arph; | ||
| 48 | const struct arppayload *ap; | ||
| 49 | struct arppayload _arpp; | ||
| 50 | |||
| 51 | ah = skb_header_pointer(skb, 0, sizeof(_arph), &_arph); | ||
| 52 | if (ah == NULL) { | ||
| 53 | nf_log_buf_add(m, "TRUNCATED"); | ||
| 54 | return; | ||
| 55 | } | ||
| 56 | nf_log_buf_add(m, "ARP HTYPE=%d PTYPE=0x%04x OPCODE=%d", | ||
| 57 | ntohs(ah->ar_hrd), ntohs(ah->ar_pro), ntohs(ah->ar_op)); | ||
| 58 | |||
| 59 | /* If it's for Ethernet and the lengths are OK, then log the ARP | ||
| 60 | * payload. | ||
| 61 | */ | ||
| 62 | if (ah->ar_hrd != htons(1) || | ||
| 63 | ah->ar_hln != ETH_ALEN || | ||
| 64 | ah->ar_pln != sizeof(__be32)) | ||
| 65 | return; | ||
| 66 | |||
| 67 | ap = skb_header_pointer(skb, sizeof(_arph), sizeof(_arpp), &_arpp); | ||
| 68 | if (ap == NULL) { | ||
| 69 | nf_log_buf_add(m, " INCOMPLETE [%Zu bytes]", | ||
| 70 | skb->len - sizeof(_arph)); | ||
| 71 | return; | ||
| 72 | } | ||
| 73 | nf_log_buf_add(m, " MACSRC=%pM IPSRC=%pI4 MACDST=%pM IPDST=%pI4", | ||
| 74 | ap->mac_src, ap->ip_src, ap->mac_dst, ap->ip_dst); | ||
| 75 | } | ||
| 76 | |||
| 77 | void nf_log_arp_packet(struct net *net, u_int8_t pf, | ||
| 78 | unsigned int hooknum, const struct sk_buff *skb, | ||
| 79 | const struct net_device *in, | ||
| 80 | const struct net_device *out, | ||
| 81 | const struct nf_loginfo *loginfo, | ||
| 82 | const char *prefix) | ||
| 83 | { | ||
| 84 | struct nf_log_buf *m; | ||
| 85 | |||
| 86 | /* FIXME: Disabled from containers until syslog ns is supported */ | ||
| 87 | if (!net_eq(net, &init_net)) | ||
| 88 | return; | ||
| 89 | |||
| 90 | m = nf_log_buf_open(); | ||
| 91 | |||
| 92 | if (!loginfo) | ||
| 93 | loginfo = &default_loginfo; | ||
| 94 | |||
| 95 | nf_log_dump_packet_common(m, pf, hooknum, skb, in, out, loginfo, | ||
| 96 | prefix); | ||
| 97 | dump_arp_packet(m, loginfo, skb, 0); | ||
| 98 | |||
| 99 | nf_log_buf_close(m); | ||
| 100 | } | ||
| 101 | |||
| 102 | static struct nf_logger nf_arp_logger __read_mostly = { | ||
| 103 | .name = "nf_log_arp", | ||
| 104 | .type = NF_LOG_TYPE_LOG, | ||
| 105 | .logfn = nf_log_arp_packet, | ||
| 106 | .me = THIS_MODULE, | ||
| 107 | }; | ||
| 108 | |||
| 109 | static int __net_init nf_log_arp_net_init(struct net *net) | ||
| 110 | { | ||
| 111 | nf_log_set(net, NFPROTO_ARP, &nf_arp_logger); | ||
| 112 | return 0; | ||
| 113 | } | ||
| 114 | |||
| 115 | static void __net_exit nf_log_arp_net_exit(struct net *net) | ||
| 116 | { | ||
| 117 | nf_log_unset(net, &nf_arp_logger); | ||
| 118 | } | ||
| 119 | |||
| 120 | static struct pernet_operations nf_log_arp_net_ops = { | ||
| 121 | .init = nf_log_arp_net_init, | ||
| 122 | .exit = nf_log_arp_net_exit, | ||
| 123 | }; | ||
| 124 | |||
| 125 | static int __init nf_log_arp_init(void) | ||
| 126 | { | ||
| 127 | int ret; | ||
| 128 | |||
| 129 | ret = register_pernet_subsys(&nf_log_arp_net_ops); | ||
| 130 | if (ret < 0) | ||
| 131 | return ret; | ||
| 132 | |||
| 133 | nf_log_register(NFPROTO_ARP, &nf_arp_logger); | ||
| 134 | return 0; | ||
| 135 | } | ||
| 136 | |||
| 137 | static void __exit nf_log_arp_exit(void) | ||
| 138 | { | ||
| 139 | unregister_pernet_subsys(&nf_log_arp_net_ops); | ||
| 140 | nf_log_unregister(&nf_arp_logger); | ||
| 141 | } | ||
| 142 | |||
| 143 | module_init(nf_log_arp_init); | ||
| 144 | module_exit(nf_log_arp_exit); | ||
| 145 | |||
| 146 | MODULE_AUTHOR("Pablo Neira Ayuso <pablo@netfilter.org>"); | ||
| 147 | MODULE_DESCRIPTION("Netfilter ARP packet logging"); | ||
| 148 | MODULE_LICENSE("GPL"); | ||
| 149 | MODULE_ALIAS_NF_LOGGER(3, 0); | ||
diff --git a/net/ipv4/netfilter/nf_log_ipv4.c b/net/ipv4/netfilter/nf_log_ipv4.c new file mode 100644 index 000000000000..078bdca1b607 --- /dev/null +++ b/net/ipv4/netfilter/nf_log_ipv4.c | |||
| @@ -0,0 +1,385 @@ | |||
| 1 | /* (C) 1999-2001 Paul `Rusty' Russell | ||
| 2 | * (C) 2002-2004 Netfilter Core Team <coreteam@netfilter.org> | ||
| 3 | * | ||
| 4 | * This program is free software; you can redistribute it and/or modify | ||
| 5 | * it under the terms of the GNU General Public License version 2 as | ||
| 6 | * published by the Free Software Foundation. | ||
| 7 | */ | ||
| 8 | |||
| 9 | #include <linux/module.h> | ||
| 10 | #include <linux/spinlock.h> | ||
| 11 | #include <linux/skbuff.h> | ||
| 12 | #include <linux/if_arp.h> | ||
| 13 | #include <linux/ip.h> | ||
| 14 | #include <net/ipv6.h> | ||
| 15 | #include <net/icmp.h> | ||
| 16 | #include <net/udp.h> | ||
| 17 | #include <net/tcp.h> | ||
| 18 | #include <net/route.h> | ||
| 19 | |||
| 20 | #include <linux/netfilter.h> | ||
| 21 | #include <linux/netfilter/xt_LOG.h> | ||
| 22 | #include <net/netfilter/nf_log.h> | ||
| 23 | |||
| 24 | static struct nf_loginfo default_loginfo = { | ||
| 25 | .type = NF_LOG_TYPE_LOG, | ||
| 26 | .u = { | ||
| 27 | .log = { | ||
| 28 | .level = 5, | ||
| 29 | .logflags = NF_LOG_MASK, | ||
| 30 | }, | ||
| 31 | }, | ||
| 32 | }; | ||
| 33 | |||
| 34 | /* One level of recursion won't kill us */ | ||
| 35 | static void dump_ipv4_packet(struct nf_log_buf *m, | ||
| 36 | const struct nf_loginfo *info, | ||
| 37 | const struct sk_buff *skb, unsigned int iphoff) | ||
| 38 | { | ||
| 39 | struct iphdr _iph; | ||
| 40 | const struct iphdr *ih; | ||
| 41 | unsigned int logflags; | ||
| 42 | |||
| 43 | if (info->type == NF_LOG_TYPE_LOG) | ||
| 44 | logflags = info->u.log.logflags; | ||
| 45 | else | ||
| 46 | logflags = NF_LOG_MASK; | ||
| 47 | |||
| 48 | ih = skb_header_pointer(skb, iphoff, sizeof(_iph), &_iph); | ||
| 49 | if (ih == NULL) { | ||
| 50 | nf_log_buf_add(m, "TRUNCATED"); | ||
| 51 | return; | ||
| 52 | } | ||
| 53 | |||
| 54 | /* Important fields: | ||
| 55 | * TOS, len, DF/MF, fragment offset, TTL, src, dst, options. */ | ||
| 56 | /* Max length: 40 "SRC=255.255.255.255 DST=255.255.255.255 " */ | ||
| 57 | nf_log_buf_add(m, "SRC=%pI4 DST=%pI4 ", &ih->saddr, &ih->daddr); | ||
| 58 | |||
| 59 | /* Max length: 46 "LEN=65535 TOS=0xFF PREC=0xFF TTL=255 ID=65535 " */ | ||
| 60 | nf_log_buf_add(m, "LEN=%u TOS=0x%02X PREC=0x%02X TTL=%u ID=%u ", | ||
| 61 | ntohs(ih->tot_len), ih->tos & IPTOS_TOS_MASK, | ||
| 62 | ih->tos & IPTOS_PREC_MASK, ih->ttl, ntohs(ih->id)); | ||
| 63 | |||
| 64 | /* Max length: 6 "CE DF MF " */ | ||
| 65 | if (ntohs(ih->frag_off) & IP_CE) | ||
| 66 | nf_log_buf_add(m, "CE "); | ||
| 67 | if (ntohs(ih->frag_off) & IP_DF) | ||
| 68 | nf_log_buf_add(m, "DF "); | ||
| 69 | if (ntohs(ih->frag_off) & IP_MF) | ||
| 70 | nf_log_buf_add(m, "MF "); | ||
| 71 | |||
| 72 | /* Max length: 11 "FRAG:65535 " */ | ||
| 73 | if (ntohs(ih->frag_off) & IP_OFFSET) | ||
| 74 | nf_log_buf_add(m, "FRAG:%u ", ntohs(ih->frag_off) & IP_OFFSET); | ||
| 75 | |||
| 76 | if ((logflags & XT_LOG_IPOPT) && | ||
| 77 | ih->ihl * 4 > sizeof(struct iphdr)) { | ||
| 78 | const unsigned char *op; | ||
| 79 | unsigned char _opt[4 * 15 - sizeof(struct iphdr)]; | ||
| 80 | unsigned int i, optsize; | ||
| 81 | |||
| 82 | optsize = ih->ihl * 4 - sizeof(struct iphdr); | ||
| 83 | op = skb_header_pointer(skb, iphoff+sizeof(_iph), | ||
| 84 | optsize, _opt); | ||
| 85 | if (op == NULL) { | ||
| 86 | nf_log_buf_add(m, "TRUNCATED"); | ||
| 87 | return; | ||
| 88 | } | ||
| 89 | |||
| 90 | /* Max length: 127 "OPT (" 15*4*2chars ") " */ | ||
| 91 | nf_log_buf_add(m, "OPT ("); | ||
| 92 | for (i = 0; i < optsize; i++) | ||
| 93 | nf_log_buf_add(m, "%02X", op[i]); | ||
| 94 | nf_log_buf_add(m, ") "); | ||
| 95 | } | ||
| 96 | |||
| 97 | switch (ih->protocol) { | ||
| 98 | case IPPROTO_TCP: | ||
| 99 | if (nf_log_dump_tcp_header(m, skb, ih->protocol, | ||
| 100 | ntohs(ih->frag_off) & IP_OFFSET, | ||
| 101 | iphoff+ih->ihl*4, logflags)) | ||
| 102 | return; | ||
| 103 | break; | ||
| 104 | case IPPROTO_UDP: | ||
| 105 | case IPPROTO_UDPLITE: | ||
| 106 | if (nf_log_dump_udp_header(m, skb, ih->protocol, | ||
| 107 | ntohs(ih->frag_off) & IP_OFFSET, | ||
| 108 | iphoff+ih->ihl*4)) | ||
| 109 | return; | ||
| 110 | break; | ||
| 111 | case IPPROTO_ICMP: { | ||
| 112 | struct icmphdr _icmph; | ||
| 113 | const struct icmphdr *ich; | ||
| 114 | static const size_t required_len[NR_ICMP_TYPES+1] | ||
| 115 | = { [ICMP_ECHOREPLY] = 4, | ||
| 116 | [ICMP_DEST_UNREACH] | ||
| 117 | = 8 + sizeof(struct iphdr), | ||
| 118 | [ICMP_SOURCE_QUENCH] | ||
| 119 | = 8 + sizeof(struct iphdr), | ||
| 120 | [ICMP_REDIRECT] | ||
| 121 | = 8 + sizeof(struct iphdr), | ||
| 122 | [ICMP_ECHO] = 4, | ||
| 123 | [ICMP_TIME_EXCEEDED] | ||
| 124 | = 8 + sizeof(struct iphdr), | ||
| 125 | [ICMP_PARAMETERPROB] | ||
| 126 | = 8 + sizeof(struct iphdr), | ||
| 127 | [ICMP_TIMESTAMP] = 20, | ||
| 128 | [ICMP_TIMESTAMPREPLY] = 20, | ||
| 129 | [ICMP_ADDRESS] = 12, | ||
| 130 | [ICMP_ADDRESSREPLY] = 12 }; | ||
| 131 | |||
| 132 | /* Max length: 11 "PROTO=ICMP " */ | ||
| 133 | nf_log_buf_add(m, "PROTO=ICMP "); | ||
| 134 | |||
| 135 | if (ntohs(ih->frag_off) & IP_OFFSET) | ||
| 136 | break; | ||
| 137 | |||
| 138 | /* Max length: 25 "INCOMPLETE [65535 bytes] " */ | ||
| 139 | ich = skb_header_pointer(skb, iphoff + ih->ihl * 4, | ||
| 140 | sizeof(_icmph), &_icmph); | ||
| 141 | if (ich == NULL) { | ||
| 142 | nf_log_buf_add(m, "INCOMPLETE [%u bytes] ", | ||
| 143 | skb->len - iphoff - ih->ihl*4); | ||
| 144 | break; | ||
| 145 | } | ||
| 146 | |||
| 147 | /* Max length: 18 "TYPE=255 CODE=255 " */ | ||
| 148 | nf_log_buf_add(m, "TYPE=%u CODE=%u ", ich->type, ich->code); | ||
| 149 | |||
| 150 | /* Max length: 25 "INCOMPLETE [65535 bytes] " */ | ||
| 151 | if (ich->type <= NR_ICMP_TYPES && | ||
| 152 | required_len[ich->type] && | ||
| 153 | skb->len-iphoff-ih->ihl*4 < required_len[ich->type]) { | ||
| 154 | nf_log_buf_add(m, "INCOMPLETE [%u bytes] ", | ||
| 155 | skb->len - iphoff - ih->ihl*4); | ||
| 156 | break; | ||
| 157 | } | ||
| 158 | |||
| 159 | switch (ich->type) { | ||
| 160 | case ICMP_ECHOREPLY: | ||
| 161 | case ICMP_ECHO: | ||
| 162 | /* Max length: 19 "ID=65535 SEQ=65535 " */ | ||
| 163 | nf_log_buf_add(m, "ID=%u SEQ=%u ", | ||
| 164 | ntohs(ich->un.echo.id), | ||
| 165 | ntohs(ich->un.echo.sequence)); | ||
| 166 | break; | ||
| 167 | |||
| 168 | case ICMP_PARAMETERPROB: | ||
| 169 | /* Max length: 14 "PARAMETER=255 " */ | ||
| 170 | nf_log_buf_add(m, "PARAMETER=%u ", | ||
| 171 | ntohl(ich->un.gateway) >> 24); | ||
| 172 | break; | ||
| 173 | case ICMP_REDIRECT: | ||
| 174 | /* Max length: 24 "GATEWAY=255.255.255.255 " */ | ||
| 175 | nf_log_buf_add(m, "GATEWAY=%pI4 ", &ich->un.gateway); | ||
| 176 | /* Fall through */ | ||
| 177 | case ICMP_DEST_UNREACH: | ||
| 178 | case ICMP_SOURCE_QUENCH: | ||
| 179 | case ICMP_TIME_EXCEEDED: | ||
| 180 | /* Max length: 3+maxlen */ | ||
| 181 | if (!iphoff) { /* Only recurse once. */ | ||
| 182 | nf_log_buf_add(m, "["); | ||
| 183 | dump_ipv4_packet(m, info, skb, | ||
| 184 | iphoff + ih->ihl*4+sizeof(_icmph)); | ||
| 185 | nf_log_buf_add(m, "] "); | ||
| 186 | } | ||
| 187 | |||
| 188 | /* Max length: 10 "MTU=65535 " */ | ||
| 189 | if (ich->type == ICMP_DEST_UNREACH && | ||
| 190 | ich->code == ICMP_FRAG_NEEDED) { | ||
| 191 | nf_log_buf_add(m, "MTU=%u ", | ||
| 192 | ntohs(ich->un.frag.mtu)); | ||
| 193 | } | ||
| 194 | } | ||
| 195 | break; | ||
| 196 | } | ||
| 197 | /* Max Length */ | ||
| 198 | case IPPROTO_AH: { | ||
| 199 | struct ip_auth_hdr _ahdr; | ||
| 200 | const struct ip_auth_hdr *ah; | ||
| 201 | |||
| 202 | if (ntohs(ih->frag_off) & IP_OFFSET) | ||
| 203 | break; | ||
| 204 | |||
| 205 | /* Max length: 9 "PROTO=AH " */ | ||
| 206 | nf_log_buf_add(m, "PROTO=AH "); | ||
| 207 | |||
| 208 | /* Max length: 25 "INCOMPLETE [65535 bytes] " */ | ||
| 209 | ah = skb_header_pointer(skb, iphoff+ih->ihl*4, | ||
| 210 | sizeof(_ahdr), &_ahdr); | ||
| 211 | if (ah == NULL) { | ||
| 212 | nf_log_buf_add(m, "INCOMPLETE [%u bytes] ", | ||
| 213 | skb->len - iphoff - ih->ihl*4); | ||
| 214 | break; | ||
| 215 | } | ||
| 216 | |||
| 217 | /* Length: 15 "SPI=0xF1234567 " */ | ||
| 218 | nf_log_buf_add(m, "SPI=0x%x ", ntohl(ah->spi)); | ||
| 219 | break; | ||
| 220 | } | ||
| 221 | case IPPROTO_ESP: { | ||
| 222 | struct ip_esp_hdr _esph; | ||
| 223 | const struct ip_esp_hdr *eh; | ||
| 224 | |||
| 225 | /* Max length: 10 "PROTO=ESP " */ | ||
| 226 | nf_log_buf_add(m, "PROTO=ESP "); | ||
| 227 | |||
| 228 | if (ntohs(ih->frag_off) & IP_OFFSET) | ||
| 229 | break; | ||
| 230 | |||
| 231 | /* Max length: 25 "INCOMPLETE [65535 bytes] " */ | ||
| 232 | eh = skb_header_pointer(skb, iphoff+ih->ihl*4, | ||
| 233 | sizeof(_esph), &_esph); | ||
| 234 | if (eh == NULL) { | ||
| 235 | nf_log_buf_add(m, "INCOMPLETE [%u bytes] ", | ||
| 236 | skb->len - iphoff - ih->ihl*4); | ||
| 237 | break; | ||
| 238 | } | ||
| 239 | |||
| 240 | /* Length: 15 "SPI=0xF1234567 " */ | ||
| 241 | nf_log_buf_add(m, "SPI=0x%x ", ntohl(eh->spi)); | ||
| 242 | break; | ||
| 243 | } | ||
| 244 | /* Max length: 10 "PROTO 255 " */ | ||
| 245 | default: | ||
| 246 | nf_log_buf_add(m, "PROTO=%u ", ih->protocol); | ||
| 247 | } | ||
| 248 | |||
| 249 | /* Max length: 15 "UID=4294967295 " */ | ||
| 250 | if ((logflags & XT_LOG_UID) && !iphoff) | ||
| 251 | nf_log_dump_sk_uid_gid(m, skb->sk); | ||
| 252 | |||
| 253 | /* Max length: 16 "MARK=0xFFFFFFFF " */ | ||
| 254 | if (!iphoff && skb->mark) | ||
| 255 | nf_log_buf_add(m, "MARK=0x%x ", skb->mark); | ||
| 256 | |||
| 257 | /* Proto Max log string length */ | ||
| 258 | /* IP: 40+46+6+11+127 = 230 */ | ||
| 259 | /* TCP: 10+max(25,20+30+13+9+32+11+127) = 252 */ | ||
| 260 | /* UDP: 10+max(25,20) = 35 */ | ||
| 261 | /* UDPLITE: 14+max(25,20) = 39 */ | ||
| 262 | /* ICMP: 11+max(25, 18+25+max(19,14,24+3+n+10,3+n+10)) = 91+n */ | ||
| 263 | /* ESP: 10+max(25)+15 = 50 */ | ||
| 264 | /* AH: 9+max(25)+15 = 49 */ | ||
| 265 | /* unknown: 10 */ | ||
| 266 | |||
| 267 | /* (ICMP allows recursion one level deep) */ | ||
| 268 | /* maxlen = IP + ICMP + IP + max(TCP,UDP,ICMP,unknown) */ | ||
| 269 | /* maxlen = 230+ 91 + 230 + 252 = 803 */ | ||
| 270 | } | ||
| 271 | |||
| 272 | static void dump_ipv4_mac_header(struct nf_log_buf *m, | ||
| 273 | const struct nf_loginfo *info, | ||
| 274 | const struct sk_buff *skb) | ||
| 275 | { | ||
| 276 | struct net_device *dev = skb->dev; | ||
| 277 | unsigned int logflags = 0; | ||
| 278 | |||
| 279 | if (info->type == NF_LOG_TYPE_LOG) | ||
| 280 | logflags = info->u.log.logflags; | ||
| 281 | |||
| 282 | if (!(logflags & XT_LOG_MACDECODE)) | ||
| 283 | goto fallback; | ||
| 284 | |||
| 285 | switch (dev->type) { | ||
| 286 | case ARPHRD_ETHER: | ||
| 287 | nf_log_buf_add(m, "MACSRC=%pM MACDST=%pM MACPROTO=%04x ", | ||
| 288 | eth_hdr(skb)->h_source, eth_hdr(skb)->h_dest, | ||
| 289 | ntohs(eth_hdr(skb)->h_proto)); | ||
| 290 | return; | ||
| 291 | default: | ||
| 292 | break; | ||
| 293 | } | ||
| 294 | |||
| 295 | fallback: | ||
| 296 | nf_log_buf_add(m, "MAC="); | ||
| 297 | if (dev->hard_header_len && | ||
| 298 | skb->mac_header != skb->network_header) { | ||
| 299 | const unsigned char *p = skb_mac_header(skb); | ||
| 300 | unsigned int i; | ||
| 301 | |||
| 302 | nf_log_buf_add(m, "%02x", *p++); | ||
| 303 | for (i = 1; i < dev->hard_header_len; i++, p++) | ||
| 304 | nf_log_buf_add(m, ":%02x", *p); | ||
| 305 | } | ||
| 306 | nf_log_buf_add(m, " "); | ||
| 307 | } | ||
| 308 | |||
| 309 | static void nf_log_ip_packet(struct net *net, u_int8_t pf, | ||
| 310 | unsigned int hooknum, const struct sk_buff *skb, | ||
| 311 | const struct net_device *in, | ||
| 312 | const struct net_device *out, | ||
| 313 | const struct nf_loginfo *loginfo, | ||
| 314 | const char *prefix) | ||
| 315 | { | ||
| 316 | struct nf_log_buf *m; | ||
| 317 | |||
| 318 | /* FIXME: Disabled from containers until syslog ns is supported */ | ||
| 319 | if (!net_eq(net, &init_net)) | ||
| 320 | return; | ||
| 321 | |||
| 322 | m = nf_log_buf_open(); | ||
| 323 | |||
| 324 | if (!loginfo) | ||
| 325 | loginfo = &default_loginfo; | ||
| 326 | |||
| 327 | nf_log_dump_packet_common(m, pf, hooknum, skb, in, | ||
| 328 | out, loginfo, prefix); | ||
| 329 | |||
| 330 | if (in != NULL) | ||
| 331 | dump_ipv4_mac_header(m, loginfo, skb); | ||
| 332 | |||
| 333 | dump_ipv4_packet(m, loginfo, skb, 0); | ||
| 334 | |||
| 335 | nf_log_buf_close(m); | ||
| 336 | } | ||
| 337 | |||
| 338 | static struct nf_logger nf_ip_logger __read_mostly = { | ||
| 339 | .name = "nf_log_ipv4", | ||
| 340 | .type = NF_LOG_TYPE_LOG, | ||
| 341 | .logfn = nf_log_ip_packet, | ||
| 342 | .me = THIS_MODULE, | ||
| 343 | }; | ||
| 344 | |||
| 345 | static int __net_init nf_log_ipv4_net_init(struct net *net) | ||
| 346 | { | ||
| 347 | nf_log_set(net, NFPROTO_IPV4, &nf_ip_logger); | ||
| 348 | return 0; | ||
| 349 | } | ||
| 350 | |||
| 351 | static void __net_exit nf_log_ipv4_net_exit(struct net *net) | ||
| 352 | { | ||
| 353 | nf_log_unset(net, &nf_ip_logger); | ||
| 354 | } | ||
| 355 | |||
| 356 | static struct pernet_operations nf_log_ipv4_net_ops = { | ||
| 357 | .init = nf_log_ipv4_net_init, | ||
| 358 | .exit = nf_log_ipv4_net_exit, | ||
| 359 | }; | ||
| 360 | |||
| 361 | static int __init nf_log_ipv4_init(void) | ||
| 362 | { | ||
| 363 | int ret; | ||
| 364 | |||
| 365 | ret = register_pernet_subsys(&nf_log_ipv4_net_ops); | ||
| 366 | if (ret < 0) | ||
| 367 | return ret; | ||
| 368 | |||
| 369 | nf_log_register(NFPROTO_IPV4, &nf_ip_logger); | ||
| 370 | return 0; | ||
| 371 | } | ||
| 372 | |||
| 373 | static void __exit nf_log_ipv4_exit(void) | ||
| 374 | { | ||
| 375 | unregister_pernet_subsys(&nf_log_ipv4_net_ops); | ||
| 376 | nf_log_unregister(&nf_ip_logger); | ||
| 377 | } | ||
| 378 | |||
| 379 | module_init(nf_log_ipv4_init); | ||
| 380 | module_exit(nf_log_ipv4_exit); | ||
| 381 | |||
| 382 | MODULE_AUTHOR("Netfilter Core Team <coreteam@netfilter.org>"); | ||
| 383 | MODULE_DESCRIPTION("Netfilter IPv4 packet logging"); | ||
| 384 | MODULE_LICENSE("GPL"); | ||
| 385 | MODULE_ALIAS_NF_LOGGER(AF_INET, 0); | ||
diff --git a/net/ipv4/netfilter/nf_nat_l3proto_ipv4.c b/net/ipv4/netfilter/nf_nat_l3proto_ipv4.c index d8b2e14efddc..14f5ccd06337 100644 --- a/net/ipv4/netfilter/nf_nat_l3proto_ipv4.c +++ b/net/ipv4/netfilter/nf_nat_l3proto_ipv4.c | |||
| @@ -154,6 +154,7 @@ static void nf_nat_ipv4_csum_recalc(struct sk_buff *skb, | |||
| 154 | htons(oldlen), htons(datalen), 1); | 154 | htons(oldlen), htons(datalen), 1); |
| 155 | } | 155 | } |
| 156 | 156 | ||
| 157 | #if IS_ENABLED(CONFIG_NF_CT_NETLINK) | ||
| 157 | static int nf_nat_ipv4_nlattr_to_range(struct nlattr *tb[], | 158 | static int nf_nat_ipv4_nlattr_to_range(struct nlattr *tb[], |
| 158 | struct nf_nat_range *range) | 159 | struct nf_nat_range *range) |
| 159 | { | 160 | { |
| @@ -169,6 +170,7 @@ static int nf_nat_ipv4_nlattr_to_range(struct nlattr *tb[], | |||
| 169 | 170 | ||
| 170 | return 0; | 171 | return 0; |
| 171 | } | 172 | } |
| 173 | #endif | ||
| 172 | 174 | ||
| 173 | static const struct nf_nat_l3proto nf_nat_l3proto_ipv4 = { | 175 | static const struct nf_nat_l3proto nf_nat_l3proto_ipv4 = { |
| 174 | .l3proto = NFPROTO_IPV4, | 176 | .l3proto = NFPROTO_IPV4, |
| @@ -177,7 +179,9 @@ static const struct nf_nat_l3proto nf_nat_l3proto_ipv4 = { | |||
| 177 | .manip_pkt = nf_nat_ipv4_manip_pkt, | 179 | .manip_pkt = nf_nat_ipv4_manip_pkt, |
| 178 | .csum_update = nf_nat_ipv4_csum_update, | 180 | .csum_update = nf_nat_ipv4_csum_update, |
| 179 | .csum_recalc = nf_nat_ipv4_csum_recalc, | 181 | .csum_recalc = nf_nat_ipv4_csum_recalc, |
| 182 | #if IS_ENABLED(CONFIG_NF_CT_NETLINK) | ||
| 180 | .nlattr_to_range = nf_nat_ipv4_nlattr_to_range, | 183 | .nlattr_to_range = nf_nat_ipv4_nlattr_to_range, |
| 184 | #endif | ||
| 181 | #ifdef CONFIG_XFRM | 185 | #ifdef CONFIG_XFRM |
| 182 | .decode_session = nf_nat_ipv4_decode_session, | 186 | .decode_session = nf_nat_ipv4_decode_session, |
| 183 | #endif | 187 | #endif |
diff --git a/net/ipv4/netfilter/nf_nat_proto_gre.c b/net/ipv4/netfilter/nf_nat_proto_gre.c index 690d890111bb..9414923f1e15 100644 --- a/net/ipv4/netfilter/nf_nat_proto_gre.c +++ b/net/ipv4/netfilter/nf_nat_proto_gre.c | |||
| @@ -124,7 +124,7 @@ static const struct nf_nat_l4proto gre = { | |||
| 124 | .manip_pkt = gre_manip_pkt, | 124 | .manip_pkt = gre_manip_pkt, |
| 125 | .in_range = nf_nat_l4proto_in_range, | 125 | .in_range = nf_nat_l4proto_in_range, |
| 126 | .unique_tuple = gre_unique_tuple, | 126 | .unique_tuple = gre_unique_tuple, |
| 127 | #if defined(CONFIG_NF_CT_NETLINK) || defined(CONFIG_NF_CT_NETLINK_MODULE) | 127 | #if IS_ENABLED(CONFIG_NF_CT_NETLINK) |
| 128 | .nlattr_to_range = nf_nat_l4proto_nlattr_to_range, | 128 | .nlattr_to_range = nf_nat_l4proto_nlattr_to_range, |
| 129 | #endif | 129 | #endif |
| 130 | }; | 130 | }; |
diff --git a/net/ipv4/netfilter/nf_nat_proto_icmp.c b/net/ipv4/netfilter/nf_nat_proto_icmp.c index eb303471bcf6..4557b4ab8342 100644 --- a/net/ipv4/netfilter/nf_nat_proto_icmp.c +++ b/net/ipv4/netfilter/nf_nat_proto_icmp.c | |||
| @@ -77,7 +77,7 @@ const struct nf_nat_l4proto nf_nat_l4proto_icmp = { | |||
| 77 | .manip_pkt = icmp_manip_pkt, | 77 | .manip_pkt = icmp_manip_pkt, |
| 78 | .in_range = icmp_in_range, | 78 | .in_range = icmp_in_range, |
| 79 | .unique_tuple = icmp_unique_tuple, | 79 | .unique_tuple = icmp_unique_tuple, |
| 80 | #if defined(CONFIG_NF_CT_NETLINK) || defined(CONFIG_NF_CT_NETLINK_MODULE) | 80 | #if IS_ENABLED(CONFIG_NF_CT_NETLINK) |
| 81 | .nlattr_to_range = nf_nat_l4proto_nlattr_to_range, | 81 | .nlattr_to_range = nf_nat_l4proto_nlattr_to_range, |
| 82 | #endif | 82 | #endif |
| 83 | }; | 83 | }; |
diff --git a/net/ipv4/ping.c b/net/ipv4/ping.c index 044a0ddf6a79..a3c59a077a5f 100644 --- a/net/ipv4/ping.c +++ b/net/ipv4/ping.c | |||
| @@ -911,7 +911,7 @@ int ping_recvmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg, | |||
| 911 | sin6->sin6_flowinfo = ip6_flowinfo(ip6); | 911 | sin6->sin6_flowinfo = ip6_flowinfo(ip6); |
| 912 | sin6->sin6_scope_id = | 912 | sin6->sin6_scope_id = |
| 913 | ipv6_iface_scope_id(&sin6->sin6_addr, | 913 | ipv6_iface_scope_id(&sin6->sin6_addr, |
| 914 | IP6CB(skb)->iif); | 914 | inet6_iif(skb)); |
| 915 | *addr_len = sizeof(*sin6); | 915 | *addr_len = sizeof(*sin6); |
| 916 | } | 916 | } |
| 917 | 917 | ||
diff --git a/net/ipv4/proc.c b/net/ipv4/proc.c index ae0af9386f7c..8e3eb39f84e7 100644 --- a/net/ipv4/proc.c +++ b/net/ipv4/proc.c | |||
| @@ -52,6 +52,7 @@ | |||
| 52 | static int sockstat_seq_show(struct seq_file *seq, void *v) | 52 | static int sockstat_seq_show(struct seq_file *seq, void *v) |
| 53 | { | 53 | { |
| 54 | struct net *net = seq->private; | 54 | struct net *net = seq->private; |
| 55 | unsigned int frag_mem; | ||
| 55 | int orphans, sockets; | 56 | int orphans, sockets; |
| 56 | 57 | ||
| 57 | local_bh_disable(); | 58 | local_bh_disable(); |
| @@ -71,8 +72,8 @@ static int sockstat_seq_show(struct seq_file *seq, void *v) | |||
| 71 | sock_prot_inuse_get(net, &udplite_prot)); | 72 | sock_prot_inuse_get(net, &udplite_prot)); |
| 72 | seq_printf(seq, "RAW: inuse %d\n", | 73 | seq_printf(seq, "RAW: inuse %d\n", |
| 73 | sock_prot_inuse_get(net, &raw_prot)); | 74 | sock_prot_inuse_get(net, &raw_prot)); |
| 74 | seq_printf(seq, "FRAG: inuse %d memory %d\n", | 75 | frag_mem = ip_frag_mem(net); |
| 75 | ip_frag_nqueues(net), ip_frag_mem(net)); | 76 | seq_printf(seq, "FRAG: inuse %u memory %u\n", !!frag_mem, frag_mem); |
| 76 | return 0; | 77 | return 0; |
| 77 | } | 78 | } |
| 78 | 79 | ||
diff --git a/net/ipv4/raw.c b/net/ipv4/raw.c index 2c65160565e1..739db3100c23 100644 --- a/net/ipv4/raw.c +++ b/net/ipv4/raw.c | |||
| @@ -58,6 +58,7 @@ | |||
| 58 | #include <linux/in_route.h> | 58 | #include <linux/in_route.h> |
| 59 | #include <linux/route.h> | 59 | #include <linux/route.h> |
| 60 | #include <linux/skbuff.h> | 60 | #include <linux/skbuff.h> |
| 61 | #include <linux/igmp.h> | ||
| 61 | #include <net/net_namespace.h> | 62 | #include <net/net_namespace.h> |
| 62 | #include <net/dst.h> | 63 | #include <net/dst.h> |
| 63 | #include <net/sock.h> | 64 | #include <net/sock.h> |
| @@ -174,7 +175,9 @@ static int raw_v4_input(struct sk_buff *skb, const struct iphdr *iph, int hash) | |||
| 174 | 175 | ||
| 175 | while (sk) { | 176 | while (sk) { |
| 176 | delivered = 1; | 177 | delivered = 1; |
| 177 | if (iph->protocol != IPPROTO_ICMP || !icmp_filter(sk, skb)) { | 178 | if ((iph->protocol != IPPROTO_ICMP || !icmp_filter(sk, skb)) && |
| 179 | ip_mc_sf_allow(sk, iph->daddr, iph->saddr, | ||
| 180 | skb->dev->ifindex)) { | ||
| 178 | struct sk_buff *clone = skb_clone(skb, GFP_ATOMIC); | 181 | struct sk_buff *clone = skb_clone(skb, GFP_ATOMIC); |
| 179 | 182 | ||
| 180 | /* Not releasing hash table! */ | 183 | /* Not releasing hash table! */ |
| @@ -365,6 +368,8 @@ static int raw_send_hdrinc(struct sock *sk, struct flowi4 *fl4, | |||
| 365 | 368 | ||
| 366 | skb->ip_summed = CHECKSUM_NONE; | 369 | skb->ip_summed = CHECKSUM_NONE; |
| 367 | 370 | ||
| 371 | sock_tx_timestamp(sk, &skb_shinfo(skb)->tx_flags); | ||
| 372 | |||
| 368 | skb->transport_header = skb->network_header; | 373 | skb->transport_header = skb->network_header; |
| 369 | err = -EFAULT; | 374 | err = -EFAULT; |
| 370 | if (memcpy_fromiovecend((void *)iph, from, 0, length)) | 375 | if (memcpy_fromiovecend((void *)iph, from, 0, length)) |
| @@ -606,6 +611,8 @@ back_from_confirm: | |||
| 606 | &rt, msg->msg_flags); | 611 | &rt, msg->msg_flags); |
| 607 | 612 | ||
| 608 | else { | 613 | else { |
| 614 | sock_tx_timestamp(sk, &ipc.tx_flags); | ||
| 615 | |||
| 609 | if (!ipc.addr) | 616 | if (!ipc.addr) |
| 610 | ipc.addr = fl4.daddr; | 617 | ipc.addr = fl4.daddr; |
| 611 | lock_sock(sk); | 618 | lock_sock(sk); |
diff --git a/net/ipv4/route.c b/net/ipv4/route.c index 190199851c9a..eaa4b000c7b4 100644 --- a/net/ipv4/route.c +++ b/net/ipv4/route.c | |||
| @@ -1798,8 +1798,6 @@ local_input: | |||
| 1798 | no_route: | 1798 | no_route: |
| 1799 | RT_CACHE_STAT_INC(in_no_route); | 1799 | RT_CACHE_STAT_INC(in_no_route); |
| 1800 | res.type = RTN_UNREACHABLE; | 1800 | res.type = RTN_UNREACHABLE; |
| 1801 | if (err == -ESRCH) | ||
| 1802 | err = -ENETUNREACH; | ||
| 1803 | goto local_input; | 1801 | goto local_input; |
| 1804 | 1802 | ||
| 1805 | /* | 1803 | /* |
diff --git a/net/ipv4/syncookies.c b/net/ipv4/syncookies.c index c86624b36a62..c0c75688896e 100644 --- a/net/ipv4/syncookies.c +++ b/net/ipv4/syncookies.c | |||
| @@ -170,7 +170,8 @@ u32 __cookie_v4_init_sequence(const struct iphdr *iph, const struct tcphdr *th, | |||
| 170 | } | 170 | } |
| 171 | EXPORT_SYMBOL_GPL(__cookie_v4_init_sequence); | 171 | EXPORT_SYMBOL_GPL(__cookie_v4_init_sequence); |
| 172 | 172 | ||
| 173 | __u32 cookie_v4_init_sequence(struct sock *sk, struct sk_buff *skb, __u16 *mssp) | 173 | __u32 cookie_v4_init_sequence(struct sock *sk, const struct sk_buff *skb, |
| 174 | __u16 *mssp) | ||
| 174 | { | 175 | { |
| 175 | const struct iphdr *iph = ip_hdr(skb); | 176 | const struct iphdr *iph = ip_hdr(skb); |
| 176 | const struct tcphdr *th = tcp_hdr(skb); | 177 | const struct tcphdr *th = tcp_hdr(skb); |
diff --git a/net/ipv4/tcp.c b/net/ipv4/tcp.c index 9d2118e5fbc7..541f26a67ba2 100644 --- a/net/ipv4/tcp.c +++ b/net/ipv4/tcp.c | |||
| @@ -426,6 +426,17 @@ void tcp_init_sock(struct sock *sk) | |||
| 426 | } | 426 | } |
| 427 | EXPORT_SYMBOL(tcp_init_sock); | 427 | EXPORT_SYMBOL(tcp_init_sock); |
| 428 | 428 | ||
| 429 | static void tcp_tx_timestamp(struct sock *sk, struct sk_buff *skb) | ||
| 430 | { | ||
| 431 | if (sk->sk_tsflags) { | ||
| 432 | struct skb_shared_info *shinfo = skb_shinfo(skb); | ||
| 433 | |||
| 434 | sock_tx_timestamp(sk, &shinfo->tx_flags); | ||
| 435 | if (shinfo->tx_flags & SKBTX_ANY_TSTAMP) | ||
| 436 | shinfo->tskey = TCP_SKB_CB(skb)->seq + skb->len - 1; | ||
| 437 | } | ||
| 438 | } | ||
| 439 | |||
| 429 | /* | 440 | /* |
| 430 | * Wait for a TCP event. | 441 | * Wait for a TCP event. |
| 431 | * | 442 | * |
| @@ -523,7 +534,7 @@ unsigned int tcp_poll(struct file *file, struct socket *sock, poll_table *wait) | |||
| 523 | } | 534 | } |
| 524 | /* This barrier is coupled with smp_wmb() in tcp_reset() */ | 535 | /* This barrier is coupled with smp_wmb() in tcp_reset() */ |
| 525 | smp_rmb(); | 536 | smp_rmb(); |
| 526 | if (sk->sk_err) | 537 | if (sk->sk_err || !skb_queue_empty(&sk->sk_error_queue)) |
| 527 | mask |= POLLERR; | 538 | mask |= POLLERR; |
| 528 | 539 | ||
| 529 | return mask; | 540 | return mask; |
| @@ -959,8 +970,10 @@ new_segment: | |||
| 959 | 970 | ||
| 960 | copied += copy; | 971 | copied += copy; |
| 961 | offset += copy; | 972 | offset += copy; |
| 962 | if (!(size -= copy)) | 973 | if (!(size -= copy)) { |
| 974 | tcp_tx_timestamp(sk, skb); | ||
| 963 | goto out; | 975 | goto out; |
| 976 | } | ||
| 964 | 977 | ||
| 965 | if (skb->len < size_goal || (flags & MSG_OOB)) | 978 | if (skb->len < size_goal || (flags & MSG_OOB)) |
| 966 | continue; | 979 | continue; |
| @@ -1175,13 +1188,6 @@ new_segment: | |||
| 1175 | goto wait_for_memory; | 1188 | goto wait_for_memory; |
| 1176 | 1189 | ||
| 1177 | /* | 1190 | /* |
| 1178 | * All packets are restored as if they have | ||
| 1179 | * already been sent. | ||
| 1180 | */ | ||
| 1181 | if (tp->repair) | ||
| 1182 | TCP_SKB_CB(skb)->when = tcp_time_stamp; | ||
| 1183 | |||
| 1184 | /* | ||
| 1185 | * Check whether we can use HW checksum. | 1191 | * Check whether we can use HW checksum. |
| 1186 | */ | 1192 | */ |
| 1187 | if (sk->sk_route_caps & NETIF_F_ALL_CSUM) | 1193 | if (sk->sk_route_caps & NETIF_F_ALL_CSUM) |
| @@ -1190,6 +1196,13 @@ new_segment: | |||
| 1190 | skb_entail(sk, skb); | 1196 | skb_entail(sk, skb); |
| 1191 | copy = size_goal; | 1197 | copy = size_goal; |
| 1192 | max = size_goal; | 1198 | max = size_goal; |
| 1199 | |||
| 1200 | /* All packets are restored as if they have | ||
| 1201 | * already been sent. skb_mstamp isn't set to | ||
| 1202 | * avoid wrong rtt estimation. | ||
| 1203 | */ | ||
| 1204 | if (tp->repair) | ||
| 1205 | TCP_SKB_CB(skb)->sacked |= TCPCB_REPAIRED; | ||
| 1193 | } | 1206 | } |
| 1194 | 1207 | ||
| 1195 | /* Try to append data to the end of skb. */ | 1208 | /* Try to append data to the end of skb. */ |
| @@ -1252,8 +1265,10 @@ new_segment: | |||
| 1252 | 1265 | ||
| 1253 | from += copy; | 1266 | from += copy; |
| 1254 | copied += copy; | 1267 | copied += copy; |
| 1255 | if ((seglen -= copy) == 0 && iovlen == 0) | 1268 | if ((seglen -= copy) == 0 && iovlen == 0) { |
| 1269 | tcp_tx_timestamp(sk, skb); | ||
| 1256 | goto out; | 1270 | goto out; |
| 1271 | } | ||
| 1257 | 1272 | ||
| 1258 | if (skb->len < max || (flags & MSG_OOB) || unlikely(tp->repair)) | 1273 | if (skb->len < max || (flags & MSG_OOB) || unlikely(tp->repair)) |
| 1259 | continue; | 1274 | continue; |
| @@ -1617,6 +1632,9 @@ int tcp_recvmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg, | |||
| 1617 | struct sk_buff *skb; | 1632 | struct sk_buff *skb; |
| 1618 | u32 urg_hole = 0; | 1633 | u32 urg_hole = 0; |
| 1619 | 1634 | ||
| 1635 | if (unlikely(flags & MSG_ERRQUEUE)) | ||
| 1636 | return ip_recv_error(sk, msg, len, addr_len); | ||
| 1637 | |||
| 1620 | if (sk_can_busy_loop(sk) && skb_queue_empty(&sk->sk_receive_queue) && | 1638 | if (sk_can_busy_loop(sk) && skb_queue_empty(&sk->sk_receive_queue) && |
| 1621 | (sk->sk_state == TCP_ESTABLISHED)) | 1639 | (sk->sk_state == TCP_ESTABLISHED)) |
| 1622 | sk_busy_loop(sk, nonblock); | 1640 | sk_busy_loop(sk, nonblock); |
diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c index 40639c288dc2..a906e0200ff2 100644 --- a/net/ipv4/tcp_input.c +++ b/net/ipv4/tcp_input.c | |||
| @@ -74,6 +74,7 @@ | |||
| 74 | #include <linux/ipsec.h> | 74 | #include <linux/ipsec.h> |
| 75 | #include <asm/unaligned.h> | 75 | #include <asm/unaligned.h> |
| 76 | #include <net/netdma.h> | 76 | #include <net/netdma.h> |
| 77 | #include <linux/errqueue.h> | ||
| 77 | 78 | ||
| 78 | int sysctl_tcp_timestamps __read_mostly = 1; | 79 | int sysctl_tcp_timestamps __read_mostly = 1; |
| 79 | int sysctl_tcp_window_scaling __read_mostly = 1; | 80 | int sysctl_tcp_window_scaling __read_mostly = 1; |
| @@ -1904,16 +1905,17 @@ void tcp_clear_retrans(struct tcp_sock *tp) | |||
| 1904 | tp->sacked_out = 0; | 1905 | tp->sacked_out = 0; |
| 1905 | } | 1906 | } |
| 1906 | 1907 | ||
| 1907 | /* Enter Loss state. If "how" is not zero, forget all SACK information | 1908 | /* Enter Loss state. If we detect SACK reneging, forget all SACK information |
| 1908 | * and reset tags completely, otherwise preserve SACKs. If receiver | 1909 | * and reset tags completely, otherwise preserve SACKs. If receiver |
| 1909 | * dropped its ofo queue, we will know this due to reneging detection. | 1910 | * dropped its ofo queue, we will know this due to reneging detection. |
| 1910 | */ | 1911 | */ |
| 1911 | void tcp_enter_loss(struct sock *sk, int how) | 1912 | void tcp_enter_loss(struct sock *sk) |
| 1912 | { | 1913 | { |
| 1913 | const struct inet_connection_sock *icsk = inet_csk(sk); | 1914 | const struct inet_connection_sock *icsk = inet_csk(sk); |
| 1914 | struct tcp_sock *tp = tcp_sk(sk); | 1915 | struct tcp_sock *tp = tcp_sk(sk); |
| 1915 | struct sk_buff *skb; | 1916 | struct sk_buff *skb; |
| 1916 | bool new_recovery = false; | 1917 | bool new_recovery = false; |
| 1918 | bool is_reneg; /* is receiver reneging on SACKs? */ | ||
| 1917 | 1919 | ||
| 1918 | /* Reduce ssthresh if it has not yet been made inside this window. */ | 1920 | /* Reduce ssthresh if it has not yet been made inside this window. */ |
| 1919 | if (icsk->icsk_ca_state <= TCP_CA_Disorder || | 1921 | if (icsk->icsk_ca_state <= TCP_CA_Disorder || |
| @@ -1934,7 +1936,11 @@ void tcp_enter_loss(struct sock *sk, int how) | |||
| 1934 | tcp_reset_reno_sack(tp); | 1936 | tcp_reset_reno_sack(tp); |
| 1935 | 1937 | ||
| 1936 | tp->undo_marker = tp->snd_una; | 1938 | tp->undo_marker = tp->snd_una; |
| 1937 | if (how) { | 1939 | |
| 1940 | skb = tcp_write_queue_head(sk); | ||
| 1941 | is_reneg = skb && (TCP_SKB_CB(skb)->sacked & TCPCB_SACKED_ACKED); | ||
| 1942 | if (is_reneg) { | ||
| 1943 | NET_INC_STATS_BH(sock_net(sk), LINUX_MIB_TCPSACKRENEGING); | ||
| 1938 | tp->sacked_out = 0; | 1944 | tp->sacked_out = 0; |
| 1939 | tp->fackets_out = 0; | 1945 | tp->fackets_out = 0; |
| 1940 | } | 1946 | } |
| @@ -1948,7 +1954,7 @@ void tcp_enter_loss(struct sock *sk, int how) | |||
| 1948 | tp->undo_marker = 0; | 1954 | tp->undo_marker = 0; |
| 1949 | 1955 | ||
| 1950 | TCP_SKB_CB(skb)->sacked &= (~TCPCB_TAGBITS)|TCPCB_SACKED_ACKED; | 1956 | TCP_SKB_CB(skb)->sacked &= (~TCPCB_TAGBITS)|TCPCB_SACKED_ACKED; |
| 1951 | if (!(TCP_SKB_CB(skb)->sacked&TCPCB_SACKED_ACKED) || how) { | 1957 | if (!(TCP_SKB_CB(skb)->sacked&TCPCB_SACKED_ACKED) || is_reneg) { |
| 1952 | TCP_SKB_CB(skb)->sacked &= ~TCPCB_SACKED_ACKED; | 1958 | TCP_SKB_CB(skb)->sacked &= ~TCPCB_SACKED_ACKED; |
| 1953 | TCP_SKB_CB(skb)->sacked |= TCPCB_LOST; | 1959 | TCP_SKB_CB(skb)->sacked |= TCPCB_LOST; |
| 1954 | tp->lost_out += tcp_skb_pcount(skb); | 1960 | tp->lost_out += tcp_skb_pcount(skb); |
| @@ -1981,19 +1987,21 @@ void tcp_enter_loss(struct sock *sk, int how) | |||
| 1981 | * remembered SACKs do not reflect real state of receiver i.e. | 1987 | * remembered SACKs do not reflect real state of receiver i.e. |
| 1982 | * receiver _host_ is heavily congested (or buggy). | 1988 | * receiver _host_ is heavily congested (or buggy). |
| 1983 | * | 1989 | * |
| 1984 | * Do processing similar to RTO timeout. | 1990 | * To avoid big spurious retransmission bursts due to transient SACK |
| 1991 | * scoreboard oddities that look like reneging, we give the receiver a | ||
| 1992 | * little time (max(RTT/2, 10ms)) to send us some more ACKs that will | ||
| 1993 | * restore sanity to the SACK scoreboard. If the apparent reneging | ||
| 1994 | * persists until this RTO then we'll clear the SACK scoreboard. | ||
| 1985 | */ | 1995 | */ |
| 1986 | static bool tcp_check_sack_reneging(struct sock *sk, int flag) | 1996 | static bool tcp_check_sack_reneging(struct sock *sk, int flag) |
| 1987 | { | 1997 | { |
| 1988 | if (flag & FLAG_SACK_RENEGING) { | 1998 | if (flag & FLAG_SACK_RENEGING) { |
| 1989 | struct inet_connection_sock *icsk = inet_csk(sk); | 1999 | struct tcp_sock *tp = tcp_sk(sk); |
| 1990 | NET_INC_STATS_BH(sock_net(sk), LINUX_MIB_TCPSACKRENEGING); | 2000 | unsigned long delay = max(usecs_to_jiffies(tp->srtt_us >> 4), |
| 2001 | msecs_to_jiffies(10)); | ||
| 1991 | 2002 | ||
| 1992 | tcp_enter_loss(sk, 1); | ||
| 1993 | icsk->icsk_retransmits++; | ||
| 1994 | tcp_retransmit_skb(sk, tcp_write_queue_head(sk)); | ||
| 1995 | inet_csk_reset_xmit_timer(sk, ICSK_TIME_RETRANS, | 2003 | inet_csk_reset_xmit_timer(sk, ICSK_TIME_RETRANS, |
| 1996 | icsk->icsk_rto, TCP_RTO_MAX); | 2004 | delay, TCP_RTO_MAX); |
| 1997 | return true; | 2005 | return true; |
| 1998 | } | 2006 | } |
| 1999 | return false; | 2007 | return false; |
| @@ -2475,7 +2483,7 @@ static bool tcp_try_undo_loss(struct sock *sk, bool frto_undo) | |||
| 2475 | * losses and/or application stalls), do not perform any further cwnd | 2483 | * losses and/or application stalls), do not perform any further cwnd |
| 2476 | * reductions, but instead slow start up to ssthresh. | 2484 | * reductions, but instead slow start up to ssthresh. |
| 2477 | */ | 2485 | */ |
| 2478 | static void tcp_init_cwnd_reduction(struct sock *sk, const bool set_ssthresh) | 2486 | static void tcp_init_cwnd_reduction(struct sock *sk) |
| 2479 | { | 2487 | { |
| 2480 | struct tcp_sock *tp = tcp_sk(sk); | 2488 | struct tcp_sock *tp = tcp_sk(sk); |
| 2481 | 2489 | ||
| @@ -2485,8 +2493,7 @@ static void tcp_init_cwnd_reduction(struct sock *sk, const bool set_ssthresh) | |||
| 2485 | tp->prior_cwnd = tp->snd_cwnd; | 2493 | tp->prior_cwnd = tp->snd_cwnd; |
| 2486 | tp->prr_delivered = 0; | 2494 | tp->prr_delivered = 0; |
| 2487 | tp->prr_out = 0; | 2495 | tp->prr_out = 0; |
| 2488 | if (set_ssthresh) | 2496 | tp->snd_ssthresh = inet_csk(sk)->icsk_ca_ops->ssthresh(sk); |
| 2489 | tp->snd_ssthresh = inet_csk(sk)->icsk_ca_ops->ssthresh(sk); | ||
| 2490 | TCP_ECN_queue_cwr(tp); | 2497 | TCP_ECN_queue_cwr(tp); |
| 2491 | } | 2498 | } |
| 2492 | 2499 | ||
| @@ -2528,14 +2535,14 @@ static inline void tcp_end_cwnd_reduction(struct sock *sk) | |||
| 2528 | } | 2535 | } |
| 2529 | 2536 | ||
| 2530 | /* Enter CWR state. Disable cwnd undo since congestion is proven with ECN */ | 2537 | /* Enter CWR state. Disable cwnd undo since congestion is proven with ECN */ |
| 2531 | void tcp_enter_cwr(struct sock *sk, const int set_ssthresh) | 2538 | void tcp_enter_cwr(struct sock *sk) |
| 2532 | { | 2539 | { |
| 2533 | struct tcp_sock *tp = tcp_sk(sk); | 2540 | struct tcp_sock *tp = tcp_sk(sk); |
| 2534 | 2541 | ||
| 2535 | tp->prior_ssthresh = 0; | 2542 | tp->prior_ssthresh = 0; |
| 2536 | if (inet_csk(sk)->icsk_ca_state < TCP_CA_CWR) { | 2543 | if (inet_csk(sk)->icsk_ca_state < TCP_CA_CWR) { |
| 2537 | tp->undo_marker = 0; | 2544 | tp->undo_marker = 0; |
| 2538 | tcp_init_cwnd_reduction(sk, set_ssthresh); | 2545 | tcp_init_cwnd_reduction(sk); |
| 2539 | tcp_set_ca_state(sk, TCP_CA_CWR); | 2546 | tcp_set_ca_state(sk, TCP_CA_CWR); |
| 2540 | } | 2547 | } |
| 2541 | } | 2548 | } |
| @@ -2564,7 +2571,7 @@ static void tcp_try_to_open(struct sock *sk, int flag, const int prior_unsacked) | |||
| 2564 | tp->retrans_stamp = 0; | 2571 | tp->retrans_stamp = 0; |
| 2565 | 2572 | ||
| 2566 | if (flag & FLAG_ECE) | 2573 | if (flag & FLAG_ECE) |
| 2567 | tcp_enter_cwr(sk, 1); | 2574 | tcp_enter_cwr(sk); |
| 2568 | 2575 | ||
| 2569 | if (inet_csk(sk)->icsk_ca_state != TCP_CA_CWR) { | 2576 | if (inet_csk(sk)->icsk_ca_state != TCP_CA_CWR) { |
| 2570 | tcp_try_keep_open(sk); | 2577 | tcp_try_keep_open(sk); |
| @@ -2670,7 +2677,7 @@ static void tcp_enter_recovery(struct sock *sk, bool ece_ack) | |||
| 2670 | if (inet_csk(sk)->icsk_ca_state < TCP_CA_CWR) { | 2677 | if (inet_csk(sk)->icsk_ca_state < TCP_CA_CWR) { |
| 2671 | if (!ece_ack) | 2678 | if (!ece_ack) |
| 2672 | tp->prior_ssthresh = tcp_current_ssthresh(sk); | 2679 | tp->prior_ssthresh = tcp_current_ssthresh(sk); |
| 2673 | tcp_init_cwnd_reduction(sk, true); | 2680 | tcp_init_cwnd_reduction(sk); |
| 2674 | } | 2681 | } |
| 2675 | tcp_set_ca_state(sk, TCP_CA_Recovery); | 2682 | tcp_set_ca_state(sk, TCP_CA_Recovery); |
| 2676 | } | 2683 | } |
| @@ -2680,7 +2687,6 @@ static void tcp_enter_recovery(struct sock *sk, bool ece_ack) | |||
| 2680 | */ | 2687 | */ |
| 2681 | static void tcp_process_loss(struct sock *sk, int flag, bool is_dupack) | 2688 | static void tcp_process_loss(struct sock *sk, int flag, bool is_dupack) |
| 2682 | { | 2689 | { |
| 2683 | struct inet_connection_sock *icsk = inet_csk(sk); | ||
| 2684 | struct tcp_sock *tp = tcp_sk(sk); | 2690 | struct tcp_sock *tp = tcp_sk(sk); |
| 2685 | bool recovered = !before(tp->snd_una, tp->high_seq); | 2691 | bool recovered = !before(tp->snd_una, tp->high_seq); |
| 2686 | 2692 | ||
| @@ -2706,12 +2712,9 @@ static void tcp_process_loss(struct sock *sk, int flag, bool is_dupack) | |||
| 2706 | 2712 | ||
| 2707 | if (recovered) { | 2713 | if (recovered) { |
| 2708 | /* F-RTO RFC5682 sec 3.1 step 2.a and 1st part of step 3.a */ | 2714 | /* F-RTO RFC5682 sec 3.1 step 2.a and 1st part of step 3.a */ |
| 2709 | icsk->icsk_retransmits = 0; | ||
| 2710 | tcp_try_undo_recovery(sk); | 2715 | tcp_try_undo_recovery(sk); |
| 2711 | return; | 2716 | return; |
| 2712 | } | 2717 | } |
| 2713 | if (flag & FLAG_DATA_ACKED) | ||
| 2714 | icsk->icsk_retransmits = 0; | ||
| 2715 | if (tcp_is_reno(tp)) { | 2718 | if (tcp_is_reno(tp)) { |
| 2716 | /* A Reno DUPACK means new data in F-RTO step 2.b above are | 2719 | /* A Reno DUPACK means new data in F-RTO step 2.b above are |
| 2717 | * delivered. Lower inflight to clock out (re)tranmissions. | 2720 | * delivered. Lower inflight to clock out (re)tranmissions. |
| @@ -3043,10 +3046,15 @@ static int tcp_clean_rtx_queue(struct sock *sk, int prior_fackets, | |||
| 3043 | first_ackt.v64 = 0; | 3046 | first_ackt.v64 = 0; |
| 3044 | 3047 | ||
| 3045 | while ((skb = tcp_write_queue_head(sk)) && skb != tcp_send_head(sk)) { | 3048 | while ((skb = tcp_write_queue_head(sk)) && skb != tcp_send_head(sk)) { |
| 3049 | struct skb_shared_info *shinfo = skb_shinfo(skb); | ||
| 3046 | struct tcp_skb_cb *scb = TCP_SKB_CB(skb); | 3050 | struct tcp_skb_cb *scb = TCP_SKB_CB(skb); |
| 3047 | u8 sacked = scb->sacked; | 3051 | u8 sacked = scb->sacked; |
| 3048 | u32 acked_pcount; | 3052 | u32 acked_pcount; |
| 3049 | 3053 | ||
| 3054 | if (unlikely(shinfo->tx_flags & SKBTX_ACK_TSTAMP) && | ||
| 3055 | between(shinfo->tskey, prior_snd_una, tp->snd_una - 1)) | ||
| 3056 | __skb_tstamp_tx(skb, NULL, sk, SCM_TSTAMP_ACK); | ||
| 3057 | |||
| 3050 | /* Determine how many packets and what bytes were acked, tso and else */ | 3058 | /* Determine how many packets and what bytes were acked, tso and else */ |
| 3051 | if (after(scb->end_seq, tp->snd_una)) { | 3059 | if (after(scb->end_seq, tp->snd_una)) { |
| 3052 | if (tcp_skb_pcount(skb) == 1 || | 3060 | if (tcp_skb_pcount(skb) == 1 || |
| @@ -3346,7 +3354,7 @@ static void tcp_process_tlp_ack(struct sock *sk, u32 ack, int flag) | |||
| 3346 | tp->tlp_high_seq = 0; | 3354 | tp->tlp_high_seq = 0; |
| 3347 | /* Don't reduce cwnd if DSACK arrives for TLP retrans. */ | 3355 | /* Don't reduce cwnd if DSACK arrives for TLP retrans. */ |
| 3348 | if (!(flag & FLAG_DSACKING_ACK)) { | 3356 | if (!(flag & FLAG_DSACKING_ACK)) { |
| 3349 | tcp_init_cwnd_reduction(sk, true); | 3357 | tcp_init_cwnd_reduction(sk); |
| 3350 | tcp_set_ca_state(sk, TCP_CA_CWR); | 3358 | tcp_set_ca_state(sk, TCP_CA_CWR); |
| 3351 | tcp_end_cwnd_reduction(sk); | 3359 | tcp_end_cwnd_reduction(sk); |
| 3352 | tcp_try_keep_open(sk); | 3360 | tcp_try_keep_open(sk); |
| @@ -3393,8 +3401,10 @@ static int tcp_ack(struct sock *sk, const struct sk_buff *skb, int flag) | |||
| 3393 | icsk->icsk_pending == ICSK_TIME_LOSS_PROBE) | 3401 | icsk->icsk_pending == ICSK_TIME_LOSS_PROBE) |
| 3394 | tcp_rearm_rto(sk); | 3402 | tcp_rearm_rto(sk); |
| 3395 | 3403 | ||
| 3396 | if (after(ack, prior_snd_una)) | 3404 | if (after(ack, prior_snd_una)) { |
| 3397 | flag |= FLAG_SND_UNA_ADVANCED; | 3405 | flag |= FLAG_SND_UNA_ADVANCED; |
| 3406 | icsk->icsk_retransmits = 0; | ||
| 3407 | } | ||
| 3398 | 3408 | ||
| 3399 | prior_fackets = tp->fackets_out; | 3409 | prior_fackets = tp->fackets_out; |
| 3400 | 3410 | ||
| @@ -5877,3 +5887,156 @@ discard: | |||
| 5877 | return 0; | 5887 | return 0; |
| 5878 | } | 5888 | } |
| 5879 | EXPORT_SYMBOL(tcp_rcv_state_process); | 5889 | EXPORT_SYMBOL(tcp_rcv_state_process); |
| 5890 | |||
| 5891 | static inline void pr_drop_req(struct request_sock *req, __u16 port, int family) | ||
| 5892 | { | ||
| 5893 | struct inet_request_sock *ireq = inet_rsk(req); | ||
| 5894 | |||
| 5895 | if (family == AF_INET) | ||
| 5896 | LIMIT_NETDEBUG(KERN_DEBUG pr_fmt("drop open request from %pI4/%u\n"), | ||
| 5897 | &ireq->ir_rmt_addr, port); | ||
| 5898 | #if IS_ENABLED(CONFIG_IPV6) | ||
| 5899 | else if (family == AF_INET6) | ||
| 5900 | LIMIT_NETDEBUG(KERN_DEBUG pr_fmt("drop open request from %pI6/%u\n"), | ||
| 5901 | &ireq->ir_v6_rmt_addr, port); | ||
| 5902 | #endif | ||
| 5903 | } | ||
| 5904 | |||
| 5905 | int tcp_conn_request(struct request_sock_ops *rsk_ops, | ||
| 5906 | const struct tcp_request_sock_ops *af_ops, | ||
| 5907 | struct sock *sk, struct sk_buff *skb) | ||
| 5908 | { | ||
| 5909 | struct tcp_options_received tmp_opt; | ||
| 5910 | struct request_sock *req; | ||
| 5911 | struct tcp_sock *tp = tcp_sk(sk); | ||
| 5912 | struct dst_entry *dst = NULL; | ||
| 5913 | __u32 isn = TCP_SKB_CB(skb)->when; | ||
| 5914 | bool want_cookie = false, fastopen; | ||
| 5915 | struct flowi fl; | ||
| 5916 | struct tcp_fastopen_cookie foc = { .len = -1 }; | ||
| 5917 | int err; | ||
| 5918 | |||
| 5919 | |||
| 5920 | /* TW buckets are converted to open requests without | ||
| 5921 | * limitations, they conserve resources and peer is | ||
| 5922 | * evidently real one. | ||
| 5923 | */ | ||
| 5924 | if ((sysctl_tcp_syncookies == 2 || | ||
| 5925 | inet_csk_reqsk_queue_is_full(sk)) && !isn) { | ||
| 5926 | want_cookie = tcp_syn_flood_action(sk, skb, rsk_ops->slab_name); | ||
| 5927 | if (!want_cookie) | ||
| 5928 | goto drop; | ||
| 5929 | } | ||
| 5930 | |||
| 5931 | |||
| 5932 | /* Accept backlog is full. If we have already queued enough | ||
| 5933 | * of warm entries in syn queue, drop request. It is better than | ||
| 5934 | * clogging syn queue with openreqs with exponentially increasing | ||
| 5935 | * timeout. | ||
| 5936 | */ | ||
| 5937 | if (sk_acceptq_is_full(sk) && inet_csk_reqsk_queue_young(sk) > 1) { | ||
| 5938 | NET_INC_STATS_BH(sock_net(sk), LINUX_MIB_LISTENOVERFLOWS); | ||
| 5939 | goto drop; | ||
| 5940 | } | ||
| 5941 | |||
| 5942 | req = inet_reqsk_alloc(rsk_ops); | ||
| 5943 | if (!req) | ||
| 5944 | goto drop; | ||
| 5945 | |||
| 5946 | tcp_rsk(req)->af_specific = af_ops; | ||
| 5947 | |||
| 5948 | tcp_clear_options(&tmp_opt); | ||
| 5949 | tmp_opt.mss_clamp = af_ops->mss_clamp; | ||
| 5950 | tmp_opt.user_mss = tp->rx_opt.user_mss; | ||
| 5951 | tcp_parse_options(skb, &tmp_opt, 0, want_cookie ? NULL : &foc); | ||
| 5952 | |||
| 5953 | if (want_cookie && !tmp_opt.saw_tstamp) | ||
| 5954 | tcp_clear_options(&tmp_opt); | ||
| 5955 | |||
| 5956 | tmp_opt.tstamp_ok = tmp_opt.saw_tstamp; | ||
| 5957 | tcp_openreq_init(req, &tmp_opt, skb, sk); | ||
| 5958 | |||
| 5959 | af_ops->init_req(req, sk, skb); | ||
| 5960 | |||
| 5961 | if (security_inet_conn_request(sk, skb, req)) | ||
| 5962 | goto drop_and_free; | ||
| 5963 | |||
| 5964 | if (!want_cookie || tmp_opt.tstamp_ok) | ||
| 5965 | TCP_ECN_create_request(req, skb, sock_net(sk)); | ||
| 5966 | |||
| 5967 | if (want_cookie) { | ||
| 5968 | isn = cookie_init_sequence(af_ops, sk, skb, &req->mss); | ||
| 5969 | req->cookie_ts = tmp_opt.tstamp_ok; | ||
| 5970 | } else if (!isn) { | ||
| 5971 | /* VJ's idea. We save last timestamp seen | ||
| 5972 | * from the destination in peer table, when entering | ||
| 5973 | * state TIME-WAIT, and check against it before | ||
| 5974 | * accepting new connection request. | ||
| 5975 | * | ||
| 5976 | * If "isn" is not zero, this request hit alive | ||
| 5977 | * timewait bucket, so that all the necessary checks | ||
| 5978 | * are made in the function processing timewait state. | ||
| 5979 | */ | ||
| 5980 | if (tcp_death_row.sysctl_tw_recycle) { | ||
| 5981 | bool strict; | ||
| 5982 | |||
| 5983 | dst = af_ops->route_req(sk, &fl, req, &strict); | ||
| 5984 | |||
| 5985 | if (dst && strict && | ||
| 5986 | !tcp_peer_is_proven(req, dst, true, | ||
| 5987 | tmp_opt.saw_tstamp)) { | ||
| 5988 | NET_INC_STATS_BH(sock_net(sk), LINUX_MIB_PAWSPASSIVEREJECTED); | ||
| 5989 | goto drop_and_release; | ||
| 5990 | } | ||
| 5991 | } | ||
| 5992 | /* Kill the following clause, if you dislike this way. */ | ||
| 5993 | else if (!sysctl_tcp_syncookies && | ||
| 5994 | (sysctl_max_syn_backlog - inet_csk_reqsk_queue_len(sk) < | ||
| 5995 | (sysctl_max_syn_backlog >> 2)) && | ||
| 5996 | !tcp_peer_is_proven(req, dst, false, | ||
| 5997 | tmp_opt.saw_tstamp)) { | ||
| 5998 | /* Without syncookies last quarter of | ||
| 5999 | * backlog is filled with destinations, | ||
| 6000 | * proven to be alive. | ||
| 6001 | * It means that we continue to communicate | ||
| 6002 | * to destinations, already remembered | ||
| 6003 | * to the moment of synflood. | ||
| 6004 | */ | ||
| 6005 | pr_drop_req(req, ntohs(tcp_hdr(skb)->source), | ||
| 6006 | rsk_ops->family); | ||
| 6007 | goto drop_and_release; | ||
| 6008 | } | ||
| 6009 | |||
| 6010 | isn = af_ops->init_seq(skb); | ||
| 6011 | } | ||
| 6012 | if (!dst) { | ||
| 6013 | dst = af_ops->route_req(sk, &fl, req, NULL); | ||
| 6014 | if (!dst) | ||
| 6015 | goto drop_and_free; | ||
| 6016 | } | ||
| 6017 | |||
| 6018 | tcp_rsk(req)->snt_isn = isn; | ||
| 6019 | tcp_openreq_init_rwin(req, sk, dst); | ||
| 6020 | fastopen = !want_cookie && | ||
| 6021 | tcp_try_fastopen(sk, skb, req, &foc, dst); | ||
| 6022 | err = af_ops->send_synack(sk, dst, &fl, req, | ||
| 6023 | skb_get_queue_mapping(skb), &foc); | ||
| 6024 | if (!fastopen) { | ||
| 6025 | if (err || want_cookie) | ||
| 6026 | goto drop_and_free; | ||
| 6027 | |||
| 6028 | tcp_rsk(req)->listener = NULL; | ||
| 6029 | af_ops->queue_hash_add(sk, req, TCP_TIMEOUT_INIT); | ||
| 6030 | } | ||
| 6031 | |||
| 6032 | return 0; | ||
| 6033 | |||
| 6034 | drop_and_release: | ||
| 6035 | dst_release(dst); | ||
| 6036 | drop_and_free: | ||
| 6037 | reqsk_free(req); | ||
| 6038 | drop: | ||
| 6039 | NET_INC_STATS_BH(sock_net(sk), LINUX_MIB_LISTENDROPS); | ||
| 6040 | return 0; | ||
| 6041 | } | ||
| 6042 | EXPORT_SYMBOL(tcp_conn_request); | ||
diff --git a/net/ipv4/tcp_ipv4.c b/net/ipv4/tcp_ipv4.c index 77cccda1ad0c..cd17f009aede 100644 --- a/net/ipv4/tcp_ipv4.c +++ b/net/ipv4/tcp_ipv4.c | |||
| @@ -99,7 +99,7 @@ static int tcp_v4_md5_hash_hdr(char *md5_hash, const struct tcp_md5sig_key *key, | |||
| 99 | struct inet_hashinfo tcp_hashinfo; | 99 | struct inet_hashinfo tcp_hashinfo; |
| 100 | EXPORT_SYMBOL(tcp_hashinfo); | 100 | EXPORT_SYMBOL(tcp_hashinfo); |
| 101 | 101 | ||
| 102 | static inline __u32 tcp_v4_init_sequence(const struct sk_buff *skb) | 102 | static __u32 tcp_v4_init_sequence(const struct sk_buff *skb) |
| 103 | { | 103 | { |
| 104 | return secure_tcp_sequence_number(ip_hdr(skb)->daddr, | 104 | return secure_tcp_sequence_number(ip_hdr(skb)->daddr, |
| 105 | ip_hdr(skb)->saddr, | 105 | ip_hdr(skb)->saddr, |
| @@ -208,6 +208,8 @@ int tcp_v4_connect(struct sock *sk, struct sockaddr *uaddr, int addr_len) | |||
| 208 | inet->inet_dport = usin->sin_port; | 208 | inet->inet_dport = usin->sin_port; |
| 209 | inet->inet_daddr = daddr; | 209 | inet->inet_daddr = daddr; |
| 210 | 210 | ||
| 211 | inet_set_txhash(sk); | ||
| 212 | |||
| 211 | inet_csk(sk)->icsk_ext_hdr_len = 0; | 213 | inet_csk(sk)->icsk_ext_hdr_len = 0; |
| 212 | if (inet_opt) | 214 | if (inet_opt) |
| 213 | inet_csk(sk)->icsk_ext_hdr_len = inet_opt->opt.optlen; | 215 | inet_csk(sk)->icsk_ext_hdr_len = inet_opt->opt.optlen; |
| @@ -269,7 +271,7 @@ EXPORT_SYMBOL(tcp_v4_connect); | |||
| 269 | * It can be called through tcp_release_cb() if socket was owned by user | 271 | * It can be called through tcp_release_cb() if socket was owned by user |
| 270 | * at the time tcp_v4_err() was called to handle ICMP message. | 272 | * at the time tcp_v4_err() was called to handle ICMP message. |
| 271 | */ | 273 | */ |
| 272 | static void tcp_v4_mtu_reduced(struct sock *sk) | 274 | void tcp_v4_mtu_reduced(struct sock *sk) |
| 273 | { | 275 | { |
| 274 | struct dst_entry *dst; | 276 | struct dst_entry *dst; |
| 275 | struct inet_sock *inet = inet_sk(sk); | 277 | struct inet_sock *inet = inet_sk(sk); |
| @@ -300,6 +302,7 @@ static void tcp_v4_mtu_reduced(struct sock *sk) | |||
| 300 | tcp_simple_retransmit(sk); | 302 | tcp_simple_retransmit(sk); |
| 301 | } /* else let the usual retransmit timer handle it */ | 303 | } /* else let the usual retransmit timer handle it */ |
| 302 | } | 304 | } |
| 305 | EXPORT_SYMBOL(tcp_v4_mtu_reduced); | ||
| 303 | 306 | ||
| 304 | static void do_redirect(struct sk_buff *skb, struct sock *sk) | 307 | static void do_redirect(struct sk_buff *skb, struct sock *sk) |
| 305 | { | 308 | { |
| @@ -342,11 +345,6 @@ void tcp_v4_err(struct sk_buff *icmp_skb, u32 info) | |||
| 342 | int err; | 345 | int err; |
| 343 | struct net *net = dev_net(icmp_skb->dev); | 346 | struct net *net = dev_net(icmp_skb->dev); |
| 344 | 347 | ||
| 345 | if (icmp_skb->len < (iph->ihl << 2) + 8) { | ||
| 346 | ICMP_INC_STATS_BH(net, ICMP_MIB_INERRORS); | ||
| 347 | return; | ||
| 348 | } | ||
| 349 | |||
| 350 | sk = inet_lookup(net, &tcp_hashinfo, iph->daddr, th->dest, | 348 | sk = inet_lookup(net, &tcp_hashinfo, iph->daddr, th->dest, |
| 351 | iph->saddr, th->source, inet_iif(icmp_skb)); | 349 | iph->saddr, th->source, inet_iif(icmp_skb)); |
| 352 | if (!sk) { | 350 | if (!sk) { |
| @@ -814,6 +812,7 @@ static void tcp_v4_reqsk_send_ack(struct sock *sk, struct sk_buff *skb, | |||
| 814 | * socket. | 812 | * socket. |
| 815 | */ | 813 | */ |
| 816 | static int tcp_v4_send_synack(struct sock *sk, struct dst_entry *dst, | 814 | static int tcp_v4_send_synack(struct sock *sk, struct dst_entry *dst, |
| 815 | struct flowi *fl, | ||
| 817 | struct request_sock *req, | 816 | struct request_sock *req, |
| 818 | u16 queue_mapping, | 817 | u16 queue_mapping, |
| 819 | struct tcp_fastopen_cookie *foc) | 818 | struct tcp_fastopen_cookie *foc) |
| @@ -837,24 +836,11 @@ static int tcp_v4_send_synack(struct sock *sk, struct dst_entry *dst, | |||
| 837 | ireq->ir_rmt_addr, | 836 | ireq->ir_rmt_addr, |
| 838 | ireq->opt); | 837 | ireq->opt); |
| 839 | err = net_xmit_eval(err); | 838 | err = net_xmit_eval(err); |
| 840 | if (!tcp_rsk(req)->snt_synack && !err) | ||
| 841 | tcp_rsk(req)->snt_synack = tcp_time_stamp; | ||
| 842 | } | 839 | } |
| 843 | 840 | ||
| 844 | return err; | 841 | return err; |
| 845 | } | 842 | } |
| 846 | 843 | ||
| 847 | static int tcp_v4_rtx_synack(struct sock *sk, struct request_sock *req) | ||
| 848 | { | ||
| 849 | int res = tcp_v4_send_synack(sk, NULL, req, 0, NULL); | ||
| 850 | |||
| 851 | if (!res) { | ||
| 852 | TCP_INC_STATS_BH(sock_net(sk), TCP_MIB_RETRANSSEGS); | ||
| 853 | NET_INC_STATS_BH(sock_net(sk), LINUX_MIB_TCPSYNRETRANS); | ||
| 854 | } | ||
| 855 | return res; | ||
| 856 | } | ||
| 857 | |||
| 858 | /* | 844 | /* |
| 859 | * IPv4 request_sock destructor. | 845 | * IPv4 request_sock destructor. |
| 860 | */ | 846 | */ |
| @@ -1064,7 +1050,7 @@ static int tcp_v4_parse_md5_keys(struct sock *sk, char __user *optval, | |||
| 1064 | if (sin->sin_family != AF_INET) | 1050 | if (sin->sin_family != AF_INET) |
| 1065 | return -EINVAL; | 1051 | return -EINVAL; |
| 1066 | 1052 | ||
| 1067 | if (!cmd.tcpm_key || !cmd.tcpm_keylen) | 1053 | if (!cmd.tcpm_keylen) |
| 1068 | return tcp_md5_do_del(sk, (union tcp_md5_addr *)&sin->sin_addr.s_addr, | 1054 | return tcp_md5_do_del(sk, (union tcp_md5_addr *)&sin->sin_addr.s_addr, |
| 1069 | AF_INET); | 1055 | AF_INET); |
| 1070 | 1056 | ||
| @@ -1182,7 +1168,8 @@ clear_hash_noput: | |||
| 1182 | } | 1168 | } |
| 1183 | EXPORT_SYMBOL(tcp_v4_md5_hash_skb); | 1169 | EXPORT_SYMBOL(tcp_v4_md5_hash_skb); |
| 1184 | 1170 | ||
| 1185 | static bool tcp_v4_inbound_md5_hash(struct sock *sk, const struct sk_buff *skb) | 1171 | static bool __tcp_v4_inbound_md5_hash(struct sock *sk, |
| 1172 | const struct sk_buff *skb) | ||
| 1186 | { | 1173 | { |
| 1187 | /* | 1174 | /* |
| 1188 | * This gets called for each TCP segment that arrives | 1175 | * This gets called for each TCP segment that arrives |
| @@ -1235,163 +1222,81 @@ static bool tcp_v4_inbound_md5_hash(struct sock *sk, const struct sk_buff *skb) | |||
| 1235 | return false; | 1222 | return false; |
| 1236 | } | 1223 | } |
| 1237 | 1224 | ||
| 1225 | static bool tcp_v4_inbound_md5_hash(struct sock *sk, const struct sk_buff *skb) | ||
| 1226 | { | ||
| 1227 | bool ret; | ||
| 1228 | |||
| 1229 | rcu_read_lock(); | ||
| 1230 | ret = __tcp_v4_inbound_md5_hash(sk, skb); | ||
| 1231 | rcu_read_unlock(); | ||
| 1232 | |||
| 1233 | return ret; | ||
| 1234 | } | ||
| 1235 | |||
| 1238 | #endif | 1236 | #endif |
| 1239 | 1237 | ||
| 1238 | static void tcp_v4_init_req(struct request_sock *req, struct sock *sk, | ||
| 1239 | struct sk_buff *skb) | ||
| 1240 | { | ||
| 1241 | struct inet_request_sock *ireq = inet_rsk(req); | ||
| 1242 | |||
| 1243 | ireq->ir_loc_addr = ip_hdr(skb)->daddr; | ||
| 1244 | ireq->ir_rmt_addr = ip_hdr(skb)->saddr; | ||
| 1245 | ireq->no_srccheck = inet_sk(sk)->transparent; | ||
| 1246 | ireq->opt = tcp_v4_save_options(skb); | ||
| 1247 | } | ||
| 1248 | |||
| 1249 | static struct dst_entry *tcp_v4_route_req(struct sock *sk, struct flowi *fl, | ||
| 1250 | const struct request_sock *req, | ||
| 1251 | bool *strict) | ||
| 1252 | { | ||
| 1253 | struct dst_entry *dst = inet_csk_route_req(sk, &fl->u.ip4, req); | ||
| 1254 | |||
| 1255 | if (strict) { | ||
| 1256 | if (fl->u.ip4.daddr == inet_rsk(req)->ir_rmt_addr) | ||
| 1257 | *strict = true; | ||
| 1258 | else | ||
| 1259 | *strict = false; | ||
| 1260 | } | ||
| 1261 | |||
| 1262 | return dst; | ||
| 1263 | } | ||
| 1264 | |||
| 1240 | struct request_sock_ops tcp_request_sock_ops __read_mostly = { | 1265 | struct request_sock_ops tcp_request_sock_ops __read_mostly = { |
| 1241 | .family = PF_INET, | 1266 | .family = PF_INET, |
| 1242 | .obj_size = sizeof(struct tcp_request_sock), | 1267 | .obj_size = sizeof(struct tcp_request_sock), |
| 1243 | .rtx_syn_ack = tcp_v4_rtx_synack, | 1268 | .rtx_syn_ack = tcp_rtx_synack, |
| 1244 | .send_ack = tcp_v4_reqsk_send_ack, | 1269 | .send_ack = tcp_v4_reqsk_send_ack, |
| 1245 | .destructor = tcp_v4_reqsk_destructor, | 1270 | .destructor = tcp_v4_reqsk_destructor, |
| 1246 | .send_reset = tcp_v4_send_reset, | 1271 | .send_reset = tcp_v4_send_reset, |
| 1247 | .syn_ack_timeout = tcp_syn_ack_timeout, | 1272 | .syn_ack_timeout = tcp_syn_ack_timeout, |
| 1248 | }; | 1273 | }; |
| 1249 | 1274 | ||
| 1250 | #ifdef CONFIG_TCP_MD5SIG | ||
| 1251 | static const struct tcp_request_sock_ops tcp_request_sock_ipv4_ops = { | 1275 | static const struct tcp_request_sock_ops tcp_request_sock_ipv4_ops = { |
| 1276 | .mss_clamp = TCP_MSS_DEFAULT, | ||
| 1277 | #ifdef CONFIG_TCP_MD5SIG | ||
| 1252 | .md5_lookup = tcp_v4_reqsk_md5_lookup, | 1278 | .md5_lookup = tcp_v4_reqsk_md5_lookup, |
| 1253 | .calc_md5_hash = tcp_v4_md5_hash_skb, | 1279 | .calc_md5_hash = tcp_v4_md5_hash_skb, |
| 1254 | }; | ||
| 1255 | #endif | 1280 | #endif |
| 1281 | .init_req = tcp_v4_init_req, | ||
| 1282 | #ifdef CONFIG_SYN_COOKIES | ||
| 1283 | .cookie_init_seq = cookie_v4_init_sequence, | ||
| 1284 | #endif | ||
| 1285 | .route_req = tcp_v4_route_req, | ||
| 1286 | .init_seq = tcp_v4_init_sequence, | ||
| 1287 | .send_synack = tcp_v4_send_synack, | ||
| 1288 | .queue_hash_add = inet_csk_reqsk_queue_hash_add, | ||
| 1289 | }; | ||
| 1256 | 1290 | ||
| 1257 | int tcp_v4_conn_request(struct sock *sk, struct sk_buff *skb) | 1291 | int tcp_v4_conn_request(struct sock *sk, struct sk_buff *skb) |
| 1258 | { | 1292 | { |
| 1259 | struct tcp_options_received tmp_opt; | ||
| 1260 | struct request_sock *req; | ||
| 1261 | struct inet_request_sock *ireq; | ||
| 1262 | struct tcp_sock *tp = tcp_sk(sk); | ||
| 1263 | struct dst_entry *dst = NULL; | ||
| 1264 | __be32 saddr = ip_hdr(skb)->saddr; | ||
| 1265 | __be32 daddr = ip_hdr(skb)->daddr; | ||
| 1266 | __u32 isn = TCP_SKB_CB(skb)->when; | ||
| 1267 | bool want_cookie = false, fastopen; | ||
| 1268 | struct flowi4 fl4; | ||
| 1269 | struct tcp_fastopen_cookie foc = { .len = -1 }; | ||
| 1270 | int err; | ||
| 1271 | |||
| 1272 | /* Never answer to SYNs send to broadcast or multicast */ | 1293 | /* Never answer to SYNs send to broadcast or multicast */ |
| 1273 | if (skb_rtable(skb)->rt_flags & (RTCF_BROADCAST | RTCF_MULTICAST)) | 1294 | if (skb_rtable(skb)->rt_flags & (RTCF_BROADCAST | RTCF_MULTICAST)) |
| 1274 | goto drop; | 1295 | goto drop; |
| 1275 | 1296 | ||
| 1276 | /* TW buckets are converted to open requests without | 1297 | return tcp_conn_request(&tcp_request_sock_ops, |
| 1277 | * limitations, they conserve resources and peer is | 1298 | &tcp_request_sock_ipv4_ops, sk, skb); |
| 1278 | * evidently real one. | ||
| 1279 | */ | ||
| 1280 | if ((sysctl_tcp_syncookies == 2 || | ||
| 1281 | inet_csk_reqsk_queue_is_full(sk)) && !isn) { | ||
| 1282 | want_cookie = tcp_syn_flood_action(sk, skb, "TCP"); | ||
| 1283 | if (!want_cookie) | ||
| 1284 | goto drop; | ||
| 1285 | } | ||
| 1286 | |||
| 1287 | /* Accept backlog is full. If we have already queued enough | ||
| 1288 | * of warm entries in syn queue, drop request. It is better than | ||
| 1289 | * clogging syn queue with openreqs with exponentially increasing | ||
| 1290 | * timeout. | ||
| 1291 | */ | ||
| 1292 | if (sk_acceptq_is_full(sk) && inet_csk_reqsk_queue_young(sk) > 1) { | ||
| 1293 | NET_INC_STATS_BH(sock_net(sk), LINUX_MIB_LISTENOVERFLOWS); | ||
| 1294 | goto drop; | ||
| 1295 | } | ||
| 1296 | |||
| 1297 | req = inet_reqsk_alloc(&tcp_request_sock_ops); | ||
| 1298 | if (!req) | ||
| 1299 | goto drop; | ||
| 1300 | |||
| 1301 | #ifdef CONFIG_TCP_MD5SIG | ||
| 1302 | tcp_rsk(req)->af_specific = &tcp_request_sock_ipv4_ops; | ||
| 1303 | #endif | ||
| 1304 | |||
| 1305 | tcp_clear_options(&tmp_opt); | ||
| 1306 | tmp_opt.mss_clamp = TCP_MSS_DEFAULT; | ||
| 1307 | tmp_opt.user_mss = tp->rx_opt.user_mss; | ||
| 1308 | tcp_parse_options(skb, &tmp_opt, 0, want_cookie ? NULL : &foc); | ||
| 1309 | |||
| 1310 | if (want_cookie && !tmp_opt.saw_tstamp) | ||
| 1311 | tcp_clear_options(&tmp_opt); | ||
| 1312 | |||
| 1313 | tmp_opt.tstamp_ok = tmp_opt.saw_tstamp; | ||
| 1314 | tcp_openreq_init(req, &tmp_opt, skb); | ||
| 1315 | |||
| 1316 | ireq = inet_rsk(req); | ||
| 1317 | ireq->ir_loc_addr = daddr; | ||
| 1318 | ireq->ir_rmt_addr = saddr; | ||
| 1319 | ireq->no_srccheck = inet_sk(sk)->transparent; | ||
| 1320 | ireq->opt = tcp_v4_save_options(skb); | ||
| 1321 | ireq->ir_mark = inet_request_mark(sk, skb); | ||
| 1322 | |||
| 1323 | if (security_inet_conn_request(sk, skb, req)) | ||
| 1324 | goto drop_and_free; | ||
| 1325 | |||
| 1326 | if (!want_cookie || tmp_opt.tstamp_ok) | ||
| 1327 | TCP_ECN_create_request(req, skb, sock_net(sk)); | ||
| 1328 | |||
| 1329 | if (want_cookie) { | ||
| 1330 | isn = cookie_v4_init_sequence(sk, skb, &req->mss); | ||
| 1331 | req->cookie_ts = tmp_opt.tstamp_ok; | ||
| 1332 | } else if (!isn) { | ||
| 1333 | /* VJ's idea. We save last timestamp seen | ||
| 1334 | * from the destination in peer table, when entering | ||
| 1335 | * state TIME-WAIT, and check against it before | ||
| 1336 | * accepting new connection request. | ||
| 1337 | * | ||
| 1338 | * If "isn" is not zero, this request hit alive | ||
| 1339 | * timewait bucket, so that all the necessary checks | ||
| 1340 | * are made in the function processing timewait state. | ||
| 1341 | */ | ||
| 1342 | if (tmp_opt.saw_tstamp && | ||
| 1343 | tcp_death_row.sysctl_tw_recycle && | ||
| 1344 | (dst = inet_csk_route_req(sk, &fl4, req)) != NULL && | ||
| 1345 | fl4.daddr == saddr) { | ||
| 1346 | if (!tcp_peer_is_proven(req, dst, true)) { | ||
| 1347 | NET_INC_STATS_BH(sock_net(sk), LINUX_MIB_PAWSPASSIVEREJECTED); | ||
| 1348 | goto drop_and_release; | ||
| 1349 | } | ||
| 1350 | } | ||
| 1351 | /* Kill the following clause, if you dislike this way. */ | ||
| 1352 | else if (!sysctl_tcp_syncookies && | ||
| 1353 | (sysctl_max_syn_backlog - inet_csk_reqsk_queue_len(sk) < | ||
| 1354 | (sysctl_max_syn_backlog >> 2)) && | ||
| 1355 | !tcp_peer_is_proven(req, dst, false)) { | ||
| 1356 | /* Without syncookies last quarter of | ||
| 1357 | * backlog is filled with destinations, | ||
| 1358 | * proven to be alive. | ||
| 1359 | * It means that we continue to communicate | ||
| 1360 | * to destinations, already remembered | ||
| 1361 | * to the moment of synflood. | ||
| 1362 | */ | ||
| 1363 | LIMIT_NETDEBUG(KERN_DEBUG pr_fmt("drop open request from %pI4/%u\n"), | ||
| 1364 | &saddr, ntohs(tcp_hdr(skb)->source)); | ||
| 1365 | goto drop_and_release; | ||
| 1366 | } | ||
| 1367 | |||
| 1368 | isn = tcp_v4_init_sequence(skb); | ||
| 1369 | } | ||
| 1370 | if (!dst && (dst = inet_csk_route_req(sk, &fl4, req)) == NULL) | ||
| 1371 | goto drop_and_free; | ||
| 1372 | |||
| 1373 | tcp_rsk(req)->snt_isn = isn; | ||
| 1374 | tcp_rsk(req)->snt_synack = tcp_time_stamp; | ||
| 1375 | tcp_openreq_init_rwin(req, sk, dst); | ||
| 1376 | fastopen = !want_cookie && | ||
| 1377 | tcp_try_fastopen(sk, skb, req, &foc, dst); | ||
| 1378 | err = tcp_v4_send_synack(sk, dst, req, | ||
| 1379 | skb_get_queue_mapping(skb), &foc); | ||
| 1380 | if (!fastopen) { | ||
| 1381 | if (err || want_cookie) | ||
| 1382 | goto drop_and_free; | ||
| 1383 | 1299 | ||
| 1384 | tcp_rsk(req)->snt_synack = tcp_time_stamp; | ||
| 1385 | tcp_rsk(req)->listener = NULL; | ||
| 1386 | inet_csk_reqsk_queue_hash_add(sk, req, TCP_TIMEOUT_INIT); | ||
| 1387 | } | ||
| 1388 | |||
| 1389 | return 0; | ||
| 1390 | |||
| 1391 | drop_and_release: | ||
| 1392 | dst_release(dst); | ||
| 1393 | drop_and_free: | ||
| 1394 | reqsk_free(req); | ||
| 1395 | drop: | 1300 | drop: |
| 1396 | NET_INC_STATS_BH(sock_net(sk), LINUX_MIB_LISTENDROPS); | 1301 | NET_INC_STATS_BH(sock_net(sk), LINUX_MIB_LISTENDROPS); |
| 1397 | return 0; | 1302 | return 0; |
| @@ -1439,6 +1344,7 @@ struct sock *tcp_v4_syn_recv_sock(struct sock *sk, struct sk_buff *skb, | |||
| 1439 | newinet->mc_ttl = ip_hdr(skb)->ttl; | 1344 | newinet->mc_ttl = ip_hdr(skb)->ttl; |
| 1440 | newinet->rcv_tos = ip_hdr(skb)->tos; | 1345 | newinet->rcv_tos = ip_hdr(skb)->tos; |
| 1441 | inet_csk(newsk)->icsk_ext_hdr_len = 0; | 1346 | inet_csk(newsk)->icsk_ext_hdr_len = 0; |
| 1347 | inet_set_txhash(newsk); | ||
| 1442 | if (inet_opt) | 1348 | if (inet_opt) |
| 1443 | inet_csk(newsk)->icsk_ext_hdr_len = inet_opt->opt.optlen; | 1349 | inet_csk(newsk)->icsk_ext_hdr_len = inet_opt->opt.optlen; |
| 1444 | newinet->inet_id = newtp->write_seq ^ jiffies; | 1350 | newinet->inet_id = newtp->write_seq ^ jiffies; |
| @@ -1539,16 +1445,6 @@ static struct sock *tcp_v4_hnd_req(struct sock *sk, struct sk_buff *skb) | |||
| 1539 | int tcp_v4_do_rcv(struct sock *sk, struct sk_buff *skb) | 1445 | int tcp_v4_do_rcv(struct sock *sk, struct sk_buff *skb) |
| 1540 | { | 1446 | { |
| 1541 | struct sock *rsk; | 1447 | struct sock *rsk; |
| 1542 | #ifdef CONFIG_TCP_MD5SIG | ||
| 1543 | /* | ||
| 1544 | * We really want to reject the packet as early as possible | ||
| 1545 | * if: | ||
| 1546 | * o We're expecting an MD5'd packet and this is no MD5 tcp option | ||
| 1547 | * o There is an MD5 option and we're not expecting one | ||
| 1548 | */ | ||
| 1549 | if (tcp_v4_inbound_md5_hash(sk, skb)) | ||
| 1550 | goto discard; | ||
| 1551 | #endif | ||
| 1552 | 1448 | ||
| 1553 | if (sk->sk_state == TCP_ESTABLISHED) { /* Fast path */ | 1449 | if (sk->sk_state == TCP_ESTABLISHED) { /* Fast path */ |
| 1554 | struct dst_entry *dst = sk->sk_rx_dst; | 1450 | struct dst_entry *dst = sk->sk_rx_dst; |
| @@ -1751,6 +1647,18 @@ process: | |||
| 1751 | 1647 | ||
| 1752 | if (!xfrm4_policy_check(sk, XFRM_POLICY_IN, skb)) | 1648 | if (!xfrm4_policy_check(sk, XFRM_POLICY_IN, skb)) |
| 1753 | goto discard_and_relse; | 1649 | goto discard_and_relse; |
| 1650 | |||
| 1651 | #ifdef CONFIG_TCP_MD5SIG | ||
| 1652 | /* | ||
| 1653 | * We really want to reject the packet as early as possible | ||
| 1654 | * if: | ||
| 1655 | * o We're expecting an MD5'd packet and this is no MD5 tcp option | ||
| 1656 | * o There is an MD5 option and we're not expecting one | ||
| 1657 | */ | ||
| 1658 | if (tcp_v4_inbound_md5_hash(sk, skb)) | ||
| 1659 | goto discard_and_relse; | ||
| 1660 | #endif | ||
| 1661 | |||
| 1754 | nf_reset(skb); | 1662 | nf_reset(skb); |
| 1755 | 1663 | ||
| 1756 | if (sk_filter(sk, skb)) | 1664 | if (sk_filter(sk, skb)) |
| @@ -1880,6 +1788,7 @@ const struct inet_connection_sock_af_ops ipv4_specific = { | |||
| 1880 | .compat_setsockopt = compat_ip_setsockopt, | 1788 | .compat_setsockopt = compat_ip_setsockopt, |
| 1881 | .compat_getsockopt = compat_ip_getsockopt, | 1789 | .compat_getsockopt = compat_ip_getsockopt, |
| 1882 | #endif | 1790 | #endif |
| 1791 | .mtu_reduced = tcp_v4_mtu_reduced, | ||
| 1883 | }; | 1792 | }; |
| 1884 | EXPORT_SYMBOL(ipv4_specific); | 1793 | EXPORT_SYMBOL(ipv4_specific); |
| 1885 | 1794 | ||
| @@ -2499,7 +2408,6 @@ struct proto tcp_prot = { | |||
| 2499 | .sendpage = tcp_sendpage, | 2408 | .sendpage = tcp_sendpage, |
| 2500 | .backlog_rcv = tcp_v4_do_rcv, | 2409 | .backlog_rcv = tcp_v4_do_rcv, |
| 2501 | .release_cb = tcp_release_cb, | 2410 | .release_cb = tcp_release_cb, |
| 2502 | .mtu_reduced = tcp_v4_mtu_reduced, | ||
| 2503 | .hash = inet_hash, | 2411 | .hash = inet_hash, |
| 2504 | .unhash = inet_unhash, | 2412 | .unhash = inet_unhash, |
| 2505 | .get_port = inet_csk_get_port, | 2413 | .get_port = inet_csk_get_port, |
diff --git a/net/ipv4/tcp_memcontrol.c b/net/ipv4/tcp_memcontrol.c index f7a2ec3ac584..3af522622fad 100644 --- a/net/ipv4/tcp_memcontrol.c +++ b/net/ipv4/tcp_memcontrol.c | |||
| @@ -222,7 +222,7 @@ static struct cftype tcp_files[] = { | |||
| 222 | 222 | ||
| 223 | static int __init tcp_memcontrol_init(void) | 223 | static int __init tcp_memcontrol_init(void) |
| 224 | { | 224 | { |
| 225 | WARN_ON(cgroup_add_cftypes(&memory_cgrp_subsys, tcp_files)); | 225 | WARN_ON(cgroup_add_legacy_cftypes(&memory_cgrp_subsys, tcp_files)); |
| 226 | return 0; | 226 | return 0; |
| 227 | } | 227 | } |
| 228 | __initcall(tcp_memcontrol_init); | 228 | __initcall(tcp_memcontrol_init); |
diff --git a/net/ipv4/tcp_metrics.c b/net/ipv4/tcp_metrics.c index 4fe041805989..ed9c9a91851c 100644 --- a/net/ipv4/tcp_metrics.c +++ b/net/ipv4/tcp_metrics.c | |||
| @@ -576,7 +576,8 @@ reset: | |||
| 576 | tp->snd_cwnd_stamp = tcp_time_stamp; | 576 | tp->snd_cwnd_stamp = tcp_time_stamp; |
| 577 | } | 577 | } |
| 578 | 578 | ||
| 579 | bool tcp_peer_is_proven(struct request_sock *req, struct dst_entry *dst, bool paws_check) | 579 | bool tcp_peer_is_proven(struct request_sock *req, struct dst_entry *dst, |
| 580 | bool paws_check, bool timestamps) | ||
| 580 | { | 581 | { |
| 581 | struct tcp_metrics_block *tm; | 582 | struct tcp_metrics_block *tm; |
| 582 | bool ret; | 583 | bool ret; |
| @@ -589,7 +590,8 @@ bool tcp_peer_is_proven(struct request_sock *req, struct dst_entry *dst, bool pa | |||
| 589 | if (paws_check) { | 590 | if (paws_check) { |
| 590 | if (tm && | 591 | if (tm && |
| 591 | (u32)get_seconds() - tm->tcpm_ts_stamp < TCP_PAWS_MSL && | 592 | (u32)get_seconds() - tm->tcpm_ts_stamp < TCP_PAWS_MSL && |
| 592 | (s32)(tm->tcpm_ts - req->ts_recent) > TCP_PAWS_WINDOW) | 593 | ((s32)(tm->tcpm_ts - req->ts_recent) > TCP_PAWS_WINDOW || |
| 594 | !timestamps)) | ||
| 593 | ret = false; | 595 | ret = false; |
| 594 | else | 596 | else |
| 595 | ret = true; | 597 | ret = true; |
| @@ -1093,7 +1095,6 @@ static const struct genl_ops tcp_metrics_nl_ops[] = { | |||
| 1093 | .doit = tcp_metrics_nl_cmd_get, | 1095 | .doit = tcp_metrics_nl_cmd_get, |
| 1094 | .dumpit = tcp_metrics_nl_dump, | 1096 | .dumpit = tcp_metrics_nl_dump, |
| 1095 | .policy = tcp_metrics_nl_policy, | 1097 | .policy = tcp_metrics_nl_policy, |
| 1096 | .flags = GENL_ADMIN_PERM, | ||
| 1097 | }, | 1098 | }, |
| 1098 | { | 1099 | { |
| 1099 | .cmd = TCP_METRICS_CMD_DEL, | 1100 | .cmd = TCP_METRICS_CMD_DEL, |
diff --git a/net/ipv4/tcp_minisocks.c b/net/ipv4/tcp_minisocks.c index e68e0d4af6c9..1649988bd1b6 100644 --- a/net/ipv4/tcp_minisocks.c +++ b/net/ipv4/tcp_minisocks.c | |||
| @@ -298,7 +298,7 @@ void tcp_time_wait(struct sock *sk, int state, int timeo) | |||
| 298 | tw->tw_v6_rcv_saddr = sk->sk_v6_rcv_saddr; | 298 | tw->tw_v6_rcv_saddr = sk->sk_v6_rcv_saddr; |
| 299 | tw->tw_tclass = np->tclass; | 299 | tw->tw_tclass = np->tclass; |
| 300 | tw->tw_flowlabel = np->flow_label >> 12; | 300 | tw->tw_flowlabel = np->flow_label >> 12; |
| 301 | tw->tw_ipv6only = np->ipv6only; | 301 | tw->tw_ipv6only = sk->sk_ipv6only; |
| 302 | } | 302 | } |
| 303 | #endif | 303 | #endif |
| 304 | 304 | ||
diff --git a/net/ipv4/tcp_offload.c b/net/ipv4/tcp_offload.c index 55046ecd083e..bc1b83cb8309 100644 --- a/net/ipv4/tcp_offload.c +++ b/net/ipv4/tcp_offload.c | |||
| @@ -14,6 +14,21 @@ | |||
| 14 | #include <net/tcp.h> | 14 | #include <net/tcp.h> |
| 15 | #include <net/protocol.h> | 15 | #include <net/protocol.h> |
| 16 | 16 | ||
| 17 | static void tcp_gso_tstamp(struct sk_buff *skb, unsigned int ts_seq, | ||
| 18 | unsigned int seq, unsigned int mss) | ||
| 19 | { | ||
| 20 | while (skb) { | ||
| 21 | if (before(ts_seq, seq + mss)) { | ||
| 22 | skb_shinfo(skb)->tx_flags |= SKBTX_SW_TSTAMP; | ||
| 23 | skb_shinfo(skb)->tskey = ts_seq; | ||
| 24 | return; | ||
| 25 | } | ||
| 26 | |||
| 27 | skb = skb->next; | ||
| 28 | seq += mss; | ||
| 29 | } | ||
| 30 | } | ||
| 31 | |||
| 17 | struct sk_buff *tcp_gso_segment(struct sk_buff *skb, | 32 | struct sk_buff *tcp_gso_segment(struct sk_buff *skb, |
| 18 | netdev_features_t features) | 33 | netdev_features_t features) |
| 19 | { | 34 | { |
| @@ -91,6 +106,9 @@ struct sk_buff *tcp_gso_segment(struct sk_buff *skb, | |||
| 91 | th = tcp_hdr(skb); | 106 | th = tcp_hdr(skb); |
| 92 | seq = ntohl(th->seq); | 107 | seq = ntohl(th->seq); |
| 93 | 108 | ||
| 109 | if (unlikely(skb_shinfo(gso_skb)->tx_flags & SKBTX_SW_TSTAMP)) | ||
| 110 | tcp_gso_tstamp(segs, skb_shinfo(gso_skb)->tskey, seq, mss); | ||
| 111 | |||
| 94 | newcheck = ~csum_fold((__force __wsum)((__force u32)th->check + | 112 | newcheck = ~csum_fold((__force __wsum)((__force u32)th->check + |
| 95 | (__force u32)delta)); | 113 | (__force u32)delta)); |
| 96 | 114 | ||
diff --git a/net/ipv4/tcp_output.c b/net/ipv4/tcp_output.c index 179b51e6bda3..5a7c41fbc6d3 100644 --- a/net/ipv4/tcp_output.c +++ b/net/ipv4/tcp_output.c | |||
| @@ -800,7 +800,7 @@ void tcp_release_cb(struct sock *sk) | |||
| 800 | __sock_put(sk); | 800 | __sock_put(sk); |
| 801 | } | 801 | } |
| 802 | if (flags & (1UL << TCP_MTU_REDUCED_DEFERRED)) { | 802 | if (flags & (1UL << TCP_MTU_REDUCED_DEFERRED)) { |
| 803 | sk->sk_prot->mtu_reduced(sk); | 803 | inet_csk(sk)->icsk_af_ops->mtu_reduced(sk); |
| 804 | __sock_put(sk); | 804 | __sock_put(sk); |
| 805 | } | 805 | } |
| 806 | } | 806 | } |
| @@ -916,6 +916,7 @@ static int tcp_transmit_skb(struct sock *sk, struct sk_buff *skb, int clone_it, | |||
| 916 | skb_orphan(skb); | 916 | skb_orphan(skb); |
| 917 | skb->sk = sk; | 917 | skb->sk = sk; |
| 918 | skb->destructor = tcp_wfree; | 918 | skb->destructor = tcp_wfree; |
| 919 | skb_set_hash_from_sk(skb, sk); | ||
| 919 | atomic_add(skb->truesize, &sk->sk_wmem_alloc); | 920 | atomic_add(skb->truesize, &sk->sk_wmem_alloc); |
| 920 | 921 | ||
| 921 | /* Build TCP header and checksum it. */ | 922 | /* Build TCP header and checksum it. */ |
| @@ -978,7 +979,7 @@ static int tcp_transmit_skb(struct sock *sk, struct sk_buff *skb, int clone_it, | |||
| 978 | if (likely(err <= 0)) | 979 | if (likely(err <= 0)) |
| 979 | return err; | 980 | return err; |
| 980 | 981 | ||
| 981 | tcp_enter_cwr(sk, 1); | 982 | tcp_enter_cwr(sk); |
| 982 | 983 | ||
| 983 | return net_xmit_eval(err); | 984 | return net_xmit_eval(err); |
| 984 | } | 985 | } |
| @@ -1068,6 +1069,21 @@ static void tcp_adjust_pcount(struct sock *sk, const struct sk_buff *skb, int de | |||
| 1068 | tcp_verify_left_out(tp); | 1069 | tcp_verify_left_out(tp); |
| 1069 | } | 1070 | } |
| 1070 | 1071 | ||
| 1072 | static void tcp_fragment_tstamp(struct sk_buff *skb, struct sk_buff *skb2) | ||
| 1073 | { | ||
| 1074 | struct skb_shared_info *shinfo = skb_shinfo(skb); | ||
| 1075 | |||
| 1076 | if (unlikely(shinfo->tx_flags & SKBTX_ANY_TSTAMP) && | ||
| 1077 | !before(shinfo->tskey, TCP_SKB_CB(skb2)->seq)) { | ||
| 1078 | struct skb_shared_info *shinfo2 = skb_shinfo(skb2); | ||
| 1079 | u8 tsflags = shinfo->tx_flags & SKBTX_ANY_TSTAMP; | ||
| 1080 | |||
| 1081 | shinfo->tx_flags &= ~tsflags; | ||
| 1082 | shinfo2->tx_flags |= tsflags; | ||
| 1083 | swap(shinfo->tskey, shinfo2->tskey); | ||
| 1084 | } | ||
| 1085 | } | ||
| 1086 | |||
| 1071 | /* Function to create two new TCP segments. Shrinks the given segment | 1087 | /* Function to create two new TCP segments. Shrinks the given segment |
| 1072 | * to the specified size and appends a new segment with the rest of the | 1088 | * to the specified size and appends a new segment with the rest of the |
| 1073 | * packet to the list. This won't be called frequently, I hope. | 1089 | * packet to the list. This won't be called frequently, I hope. |
| @@ -1135,6 +1151,7 @@ int tcp_fragment(struct sock *sk, struct sk_buff *skb, u32 len, | |||
| 1135 | */ | 1151 | */ |
| 1136 | TCP_SKB_CB(buff)->when = TCP_SKB_CB(skb)->when; | 1152 | TCP_SKB_CB(buff)->when = TCP_SKB_CB(skb)->when; |
| 1137 | buff->tstamp = skb->tstamp; | 1153 | buff->tstamp = skb->tstamp; |
| 1154 | tcp_fragment_tstamp(skb, buff); | ||
| 1138 | 1155 | ||
| 1139 | old_factor = tcp_skb_pcount(skb); | 1156 | old_factor = tcp_skb_pcount(skb); |
| 1140 | 1157 | ||
| @@ -1651,6 +1668,7 @@ static int tso_fragment(struct sock *sk, struct sk_buff *skb, unsigned int len, | |||
| 1651 | 1668 | ||
| 1652 | buff->ip_summed = skb->ip_summed = CHECKSUM_PARTIAL; | 1669 | buff->ip_summed = skb->ip_summed = CHECKSUM_PARTIAL; |
| 1653 | skb_split(skb, buff, len); | 1670 | skb_split(skb, buff, len); |
| 1671 | tcp_fragment_tstamp(skb, buff); | ||
| 1654 | 1672 | ||
| 1655 | /* Fix up tso_factor for both original and new SKB. */ | 1673 | /* Fix up tso_factor for both original and new SKB. */ |
| 1656 | tcp_set_skb_tso_segs(sk, skb, mss_now); | 1674 | tcp_set_skb_tso_segs(sk, skb, mss_now); |
| @@ -1916,8 +1934,11 @@ static bool tcp_write_xmit(struct sock *sk, unsigned int mss_now, int nonagle, | |||
| 1916 | tso_segs = tcp_init_tso_segs(sk, skb, mss_now); | 1934 | tso_segs = tcp_init_tso_segs(sk, skb, mss_now); |
| 1917 | BUG_ON(!tso_segs); | 1935 | BUG_ON(!tso_segs); |
| 1918 | 1936 | ||
| 1919 | if (unlikely(tp->repair) && tp->repair_queue == TCP_SEND_QUEUE) | 1937 | if (unlikely(tp->repair) && tp->repair_queue == TCP_SEND_QUEUE) { |
| 1938 | /* "when" is used as a start point for the retransmit timer */ | ||
| 1939 | TCP_SKB_CB(skb)->when = tcp_time_stamp; | ||
| 1920 | goto repair; /* Skip network transmission */ | 1940 | goto repair; /* Skip network transmission */ |
| 1941 | } | ||
| 1921 | 1942 | ||
| 1922 | cwnd_quota = tcp_cwnd_test(tp, skb); | 1943 | cwnd_quota = tcp_cwnd_test(tp, skb); |
| 1923 | if (!cwnd_quota) { | 1944 | if (!cwnd_quota) { |
| @@ -3301,3 +3322,18 @@ void tcp_send_probe0(struct sock *sk) | |||
| 3301 | TCP_RTO_MAX); | 3322 | TCP_RTO_MAX); |
| 3302 | } | 3323 | } |
| 3303 | } | 3324 | } |
| 3325 | |||
| 3326 | int tcp_rtx_synack(struct sock *sk, struct request_sock *req) | ||
| 3327 | { | ||
| 3328 | const struct tcp_request_sock_ops *af_ops = tcp_rsk(req)->af_specific; | ||
| 3329 | struct flowi fl; | ||
| 3330 | int res; | ||
| 3331 | |||
| 3332 | res = af_ops->send_synack(sk, NULL, &fl, req, 0, NULL); | ||
| 3333 | if (!res) { | ||
| 3334 | TCP_INC_STATS_BH(sock_net(sk), TCP_MIB_RETRANSSEGS); | ||
| 3335 | NET_INC_STATS_BH(sock_net(sk), LINUX_MIB_TCPSYNRETRANS); | ||
| 3336 | } | ||
| 3337 | return res; | ||
| 3338 | } | ||
| 3339 | EXPORT_SYMBOL(tcp_rtx_synack); | ||
diff --git a/net/ipv4/tcp_timer.c b/net/ipv4/tcp_timer.c index 286227abed10..df90cd1ce37f 100644 --- a/net/ipv4/tcp_timer.c +++ b/net/ipv4/tcp_timer.c | |||
| @@ -391,7 +391,7 @@ void tcp_retransmit_timer(struct sock *sk) | |||
| 391 | tcp_write_err(sk); | 391 | tcp_write_err(sk); |
| 392 | goto out; | 392 | goto out; |
| 393 | } | 393 | } |
| 394 | tcp_enter_loss(sk, 0); | 394 | tcp_enter_loss(sk); |
| 395 | tcp_retransmit_skb(sk, tcp_write_queue_head(sk)); | 395 | tcp_retransmit_skb(sk, tcp_write_queue_head(sk)); |
| 396 | __sk_dst_reset(sk); | 396 | __sk_dst_reset(sk); |
| 397 | goto out_reset_timer; | 397 | goto out_reset_timer; |
| @@ -422,7 +422,7 @@ void tcp_retransmit_timer(struct sock *sk) | |||
| 422 | NET_INC_STATS_BH(sock_net(sk), mib_idx); | 422 | NET_INC_STATS_BH(sock_net(sk), mib_idx); |
| 423 | } | 423 | } |
| 424 | 424 | ||
| 425 | tcp_enter_loss(sk, 0); | 425 | tcp_enter_loss(sk); |
| 426 | 426 | ||
| 427 | if (tcp_retransmit_skb(sk, tcp_write_queue_head(sk)) > 0) { | 427 | if (tcp_retransmit_skb(sk, tcp_write_queue_head(sk)) > 0) { |
| 428 | /* Retransmission failed because of local congestion, | 428 | /* Retransmission failed because of local congestion, |
diff --git a/net/ipv4/tcp_vegas.c b/net/ipv4/tcp_vegas.c index 9a5e05f27f4f..b40ad897f945 100644 --- a/net/ipv4/tcp_vegas.c +++ b/net/ipv4/tcp_vegas.c | |||
| @@ -218,7 +218,8 @@ static void tcp_vegas_cong_avoid(struct sock *sk, u32 ack, u32 acked) | |||
| 218 | * This is: | 218 | * This is: |
| 219 | * (actual rate in segments) * baseRTT | 219 | * (actual rate in segments) * baseRTT |
| 220 | */ | 220 | */ |
| 221 | target_cwnd = tp->snd_cwnd * vegas->baseRTT / rtt; | 221 | target_cwnd = (u64)tp->snd_cwnd * vegas->baseRTT; |
| 222 | do_div(target_cwnd, rtt); | ||
| 222 | 223 | ||
| 223 | /* Calculate the difference between the window we had, | 224 | /* Calculate the difference between the window we had, |
| 224 | * and the window we would like to have. This quantity | 225 | * and the window we would like to have. This quantity |
diff --git a/net/ipv4/tcp_veno.c b/net/ipv4/tcp_veno.c index 27b9825753d1..8276977d2c85 100644 --- a/net/ipv4/tcp_veno.c +++ b/net/ipv4/tcp_veno.c | |||
| @@ -144,7 +144,7 @@ static void tcp_veno_cong_avoid(struct sock *sk, u32 ack, u32 acked) | |||
| 144 | 144 | ||
| 145 | rtt = veno->minrtt; | 145 | rtt = veno->minrtt; |
| 146 | 146 | ||
| 147 | target_cwnd = (tp->snd_cwnd * veno->basertt); | 147 | target_cwnd = (u64)tp->snd_cwnd * veno->basertt; |
| 148 | target_cwnd <<= V_PARAM_SHIFT; | 148 | target_cwnd <<= V_PARAM_SHIFT; |
| 149 | do_div(target_cwnd, rtt); | 149 | do_div(target_cwnd, rtt); |
| 150 | 150 | ||
diff --git a/net/ipv4/udp.c b/net/ipv4/udp.c index 7d5a8661df76..f57c0e4c2326 100644 --- a/net/ipv4/udp.c +++ b/net/ipv4/udp.c | |||
| @@ -594,27 +594,6 @@ static inline bool __udp_is_mcast_sock(struct net *net, struct sock *sk, | |||
| 594 | return true; | 594 | return true; |
| 595 | } | 595 | } |
| 596 | 596 | ||
| 597 | static inline struct sock *udp_v4_mcast_next(struct net *net, struct sock *sk, | ||
| 598 | __be16 loc_port, __be32 loc_addr, | ||
| 599 | __be16 rmt_port, __be32 rmt_addr, | ||
| 600 | int dif) | ||
| 601 | { | ||
| 602 | struct hlist_nulls_node *node; | ||
| 603 | struct sock *s = sk; | ||
| 604 | unsigned short hnum = ntohs(loc_port); | ||
| 605 | |||
| 606 | sk_nulls_for_each_from(s, node) { | ||
| 607 | if (__udp_is_mcast_sock(net, s, | ||
| 608 | loc_port, loc_addr, | ||
| 609 | rmt_port, rmt_addr, | ||
| 610 | dif, hnum)) | ||
| 611 | goto found; | ||
| 612 | } | ||
| 613 | s = NULL; | ||
| 614 | found: | ||
| 615 | return s; | ||
| 616 | } | ||
| 617 | |||
| 618 | /* | 597 | /* |
| 619 | * This routine is called by the ICMP module when it gets some | 598 | * This routine is called by the ICMP module when it gets some |
| 620 | * sort of error condition. If err < 0 then the socket should | 599 | * sort of error condition. If err < 0 then the socket should |
| @@ -1588,7 +1567,7 @@ int udp_queue_rcv_skb(struct sock *sk, struct sk_buff *skb) | |||
| 1588 | goto csum_error; | 1567 | goto csum_error; |
| 1589 | 1568 | ||
| 1590 | 1569 | ||
| 1591 | if (sk_rcvqueues_full(sk, skb, sk->sk_rcvbuf)) { | 1570 | if (sk_rcvqueues_full(sk, sk->sk_rcvbuf)) { |
| 1592 | UDP_INC_STATS_BH(sock_net(sk), UDP_MIB_RCVBUFERRORS, | 1571 | UDP_INC_STATS_BH(sock_net(sk), UDP_MIB_RCVBUFERRORS, |
| 1593 | is_udplite); | 1572 | is_udplite); |
| 1594 | goto drop; | 1573 | goto drop; |
| @@ -1640,6 +1619,8 @@ static void flush_stack(struct sock **stack, unsigned int count, | |||
| 1640 | 1619 | ||
| 1641 | if (skb1 && udp_queue_rcv_skb(sk, skb1) <= 0) | 1620 | if (skb1 && udp_queue_rcv_skb(sk, skb1) <= 0) |
| 1642 | skb1 = NULL; | 1621 | skb1 = NULL; |
| 1622 | |||
| 1623 | sock_put(sk); | ||
| 1643 | } | 1624 | } |
| 1644 | if (unlikely(skb1)) | 1625 | if (unlikely(skb1)) |
| 1645 | kfree_skb(skb1); | 1626 | kfree_skb(skb1); |
| @@ -1668,41 +1649,50 @@ static int __udp4_lib_mcast_deliver(struct net *net, struct sk_buff *skb, | |||
| 1668 | struct udp_table *udptable) | 1649 | struct udp_table *udptable) |
| 1669 | { | 1650 | { |
| 1670 | struct sock *sk, *stack[256 / sizeof(struct sock *)]; | 1651 | struct sock *sk, *stack[256 / sizeof(struct sock *)]; |
| 1671 | struct udp_hslot *hslot = udp_hashslot(udptable, net, ntohs(uh->dest)); | 1652 | struct hlist_nulls_node *node; |
| 1672 | int dif; | 1653 | unsigned short hnum = ntohs(uh->dest); |
| 1673 | unsigned int i, count = 0; | 1654 | struct udp_hslot *hslot = udp_hashslot(udptable, net, hnum); |
| 1655 | int dif = skb->dev->ifindex; | ||
| 1656 | unsigned int count = 0, offset = offsetof(typeof(*sk), sk_nulls_node); | ||
| 1657 | unsigned int hash2 = 0, hash2_any = 0, use_hash2 = (hslot->count > 10); | ||
| 1658 | |||
| 1659 | if (use_hash2) { | ||
| 1660 | hash2_any = udp4_portaddr_hash(net, htonl(INADDR_ANY), hnum) & | ||
| 1661 | udp_table.mask; | ||
| 1662 | hash2 = udp4_portaddr_hash(net, daddr, hnum) & udp_table.mask; | ||
| 1663 | start_lookup: | ||
| 1664 | hslot = &udp_table.hash2[hash2]; | ||
| 1665 | offset = offsetof(typeof(*sk), __sk_common.skc_portaddr_node); | ||
| 1666 | } | ||
| 1674 | 1667 | ||
| 1675 | spin_lock(&hslot->lock); | 1668 | spin_lock(&hslot->lock); |
| 1676 | sk = sk_nulls_head(&hslot->head); | 1669 | sk_nulls_for_each_entry_offset(sk, node, &hslot->head, offset) { |
| 1677 | dif = skb->dev->ifindex; | 1670 | if (__udp_is_mcast_sock(net, sk, |
| 1678 | sk = udp_v4_mcast_next(net, sk, uh->dest, daddr, uh->source, saddr, dif); | 1671 | uh->dest, daddr, |
| 1679 | while (sk) { | 1672 | uh->source, saddr, |
| 1680 | stack[count++] = sk; | 1673 | dif, hnum)) { |
| 1681 | sk = udp_v4_mcast_next(net, sk_nulls_next(sk), uh->dest, | 1674 | if (unlikely(count == ARRAY_SIZE(stack))) { |
| 1682 | daddr, uh->source, saddr, dif); | 1675 | flush_stack(stack, count, skb, ~0); |
| 1683 | if (unlikely(count == ARRAY_SIZE(stack))) { | 1676 | count = 0; |
| 1684 | if (!sk) | 1677 | } |
| 1685 | break; | 1678 | stack[count++] = sk; |
| 1686 | flush_stack(stack, count, skb, ~0); | 1679 | sock_hold(sk); |
| 1687 | count = 0; | ||
| 1688 | } | 1680 | } |
| 1689 | } | 1681 | } |
| 1690 | /* | ||
| 1691 | * before releasing chain lock, we must take a reference on sockets | ||
| 1692 | */ | ||
| 1693 | for (i = 0; i < count; i++) | ||
| 1694 | sock_hold(stack[i]); | ||
| 1695 | 1682 | ||
| 1696 | spin_unlock(&hslot->lock); | 1683 | spin_unlock(&hslot->lock); |
| 1697 | 1684 | ||
| 1685 | /* Also lookup *:port if we are using hash2 and haven't done so yet. */ | ||
| 1686 | if (use_hash2 && hash2 != hash2_any) { | ||
| 1687 | hash2 = hash2_any; | ||
| 1688 | goto start_lookup; | ||
| 1689 | } | ||
| 1690 | |||
| 1698 | /* | 1691 | /* |
| 1699 | * do the slow work with no lock held | 1692 | * do the slow work with no lock held |
| 1700 | */ | 1693 | */ |
| 1701 | if (count) { | 1694 | if (count) { |
| 1702 | flush_stack(stack, count, skb, count - 1); | 1695 | flush_stack(stack, count, skb, count - 1); |
| 1703 | |||
| 1704 | for (i = 0; i < count; i++) | ||
| 1705 | sock_put(stack[i]); | ||
| 1706 | } else { | 1696 | } else { |
| 1707 | kfree_skb(skb); | 1697 | kfree_skb(skb); |
| 1708 | } | 1698 | } |
| @@ -2526,79 +2516,3 @@ void __init udp_init(void) | |||
| 2526 | sysctl_udp_rmem_min = SK_MEM_QUANTUM; | 2516 | sysctl_udp_rmem_min = SK_MEM_QUANTUM; |
| 2527 | sysctl_udp_wmem_min = SK_MEM_QUANTUM; | 2517 | sysctl_udp_wmem_min = SK_MEM_QUANTUM; |
| 2528 | } | 2518 | } |
| 2529 | |||
| 2530 | struct sk_buff *skb_udp_tunnel_segment(struct sk_buff *skb, | ||
| 2531 | netdev_features_t features) | ||
| 2532 | { | ||
| 2533 | struct sk_buff *segs = ERR_PTR(-EINVAL); | ||
| 2534 | u16 mac_offset = skb->mac_header; | ||
| 2535 | int mac_len = skb->mac_len; | ||
| 2536 | int tnl_hlen = skb_inner_mac_header(skb) - skb_transport_header(skb); | ||
| 2537 | __be16 protocol = skb->protocol; | ||
| 2538 | netdev_features_t enc_features; | ||
| 2539 | int udp_offset, outer_hlen; | ||
| 2540 | unsigned int oldlen; | ||
| 2541 | bool need_csum; | ||
| 2542 | |||
| 2543 | oldlen = (u16)~skb->len; | ||
| 2544 | |||
| 2545 | if (unlikely(!pskb_may_pull(skb, tnl_hlen))) | ||
| 2546 | goto out; | ||
| 2547 | |||
| 2548 | skb->encapsulation = 0; | ||
| 2549 | __skb_pull(skb, tnl_hlen); | ||
| 2550 | skb_reset_mac_header(skb); | ||
| 2551 | skb_set_network_header(skb, skb_inner_network_offset(skb)); | ||
| 2552 | skb->mac_len = skb_inner_network_offset(skb); | ||
| 2553 | skb->protocol = htons(ETH_P_TEB); | ||
| 2554 | |||
| 2555 | need_csum = !!(skb_shinfo(skb)->gso_type & SKB_GSO_UDP_TUNNEL_CSUM); | ||
| 2556 | if (need_csum) | ||
| 2557 | skb->encap_hdr_csum = 1; | ||
| 2558 | |||
| 2559 | /* segment inner packet. */ | ||
| 2560 | enc_features = skb->dev->hw_enc_features & netif_skb_features(skb); | ||
| 2561 | segs = skb_mac_gso_segment(skb, enc_features); | ||
| 2562 | if (!segs || IS_ERR(segs)) { | ||
| 2563 | skb_gso_error_unwind(skb, protocol, tnl_hlen, mac_offset, | ||
| 2564 | mac_len); | ||
| 2565 | goto out; | ||
| 2566 | } | ||
| 2567 | |||
| 2568 | outer_hlen = skb_tnl_header_len(skb); | ||
| 2569 | udp_offset = outer_hlen - tnl_hlen; | ||
| 2570 | skb = segs; | ||
| 2571 | do { | ||
| 2572 | struct udphdr *uh; | ||
| 2573 | int len; | ||
| 2574 | |||
| 2575 | skb_reset_inner_headers(skb); | ||
| 2576 | skb->encapsulation = 1; | ||
| 2577 | |||
| 2578 | skb->mac_len = mac_len; | ||
| 2579 | |||
| 2580 | skb_push(skb, outer_hlen); | ||
| 2581 | skb_reset_mac_header(skb); | ||
| 2582 | skb_set_network_header(skb, mac_len); | ||
| 2583 | skb_set_transport_header(skb, udp_offset); | ||
| 2584 | len = skb->len - udp_offset; | ||
| 2585 | uh = udp_hdr(skb); | ||
| 2586 | uh->len = htons(len); | ||
| 2587 | |||
| 2588 | if (need_csum) { | ||
| 2589 | __be32 delta = htonl(oldlen + len); | ||
| 2590 | |||
| 2591 | uh->check = ~csum_fold((__force __wsum) | ||
| 2592 | ((__force u32)uh->check + | ||
| 2593 | (__force u32)delta)); | ||
| 2594 | uh->check = gso_make_checksum(skb, ~uh->check); | ||
| 2595 | |||
| 2596 | if (uh->check == 0) | ||
| 2597 | uh->check = CSUM_MANGLED_0; | ||
| 2598 | } | ||
| 2599 | |||
| 2600 | skb->protocol = protocol; | ||
| 2601 | } while ((skb = skb->next)); | ||
| 2602 | out: | ||
| 2603 | return segs; | ||
| 2604 | } | ||
diff --git a/net/ipv4/udp_offload.c b/net/ipv4/udp_offload.c index 546d2d439dda..59035bc3008d 100644 --- a/net/ipv4/udp_offload.c +++ b/net/ipv4/udp_offload.c | |||
| @@ -47,6 +47,82 @@ static int udp4_ufo_send_check(struct sk_buff *skb) | |||
| 47 | return 0; | 47 | return 0; |
| 48 | } | 48 | } |
| 49 | 49 | ||
| 50 | struct sk_buff *skb_udp_tunnel_segment(struct sk_buff *skb, | ||
| 51 | netdev_features_t features) | ||
| 52 | { | ||
| 53 | struct sk_buff *segs = ERR_PTR(-EINVAL); | ||
| 54 | u16 mac_offset = skb->mac_header; | ||
| 55 | int mac_len = skb->mac_len; | ||
| 56 | int tnl_hlen = skb_inner_mac_header(skb) - skb_transport_header(skb); | ||
| 57 | __be16 protocol = skb->protocol; | ||
| 58 | netdev_features_t enc_features; | ||
| 59 | int udp_offset, outer_hlen; | ||
| 60 | unsigned int oldlen; | ||
| 61 | bool need_csum; | ||
| 62 | |||
| 63 | oldlen = (u16)~skb->len; | ||
| 64 | |||
| 65 | if (unlikely(!pskb_may_pull(skb, tnl_hlen))) | ||
| 66 | goto out; | ||
| 67 | |||
| 68 | skb->encapsulation = 0; | ||
| 69 | __skb_pull(skb, tnl_hlen); | ||
| 70 | skb_reset_mac_header(skb); | ||
| 71 | skb_set_network_header(skb, skb_inner_network_offset(skb)); | ||
| 72 | skb->mac_len = skb_inner_network_offset(skb); | ||
| 73 | skb->protocol = htons(ETH_P_TEB); | ||
| 74 | |||
| 75 | need_csum = !!(skb_shinfo(skb)->gso_type & SKB_GSO_UDP_TUNNEL_CSUM); | ||
| 76 | if (need_csum) | ||
| 77 | skb->encap_hdr_csum = 1; | ||
| 78 | |||
| 79 | /* segment inner packet. */ | ||
| 80 | enc_features = skb->dev->hw_enc_features & netif_skb_features(skb); | ||
| 81 | segs = skb_mac_gso_segment(skb, enc_features); | ||
| 82 | if (IS_ERR_OR_NULL(segs)) { | ||
| 83 | skb_gso_error_unwind(skb, protocol, tnl_hlen, mac_offset, | ||
| 84 | mac_len); | ||
| 85 | goto out; | ||
| 86 | } | ||
| 87 | |||
| 88 | outer_hlen = skb_tnl_header_len(skb); | ||
| 89 | udp_offset = outer_hlen - tnl_hlen; | ||
| 90 | skb = segs; | ||
| 91 | do { | ||
| 92 | struct udphdr *uh; | ||
| 93 | int len; | ||
| 94 | |||
| 95 | skb_reset_inner_headers(skb); | ||
| 96 | skb->encapsulation = 1; | ||
| 97 | |||
| 98 | skb->mac_len = mac_len; | ||
| 99 | |||
| 100 | skb_push(skb, outer_hlen); | ||
| 101 | skb_reset_mac_header(skb); | ||
| 102 | skb_set_network_header(skb, mac_len); | ||
| 103 | skb_set_transport_header(skb, udp_offset); | ||
| 104 | len = skb->len - udp_offset; | ||
| 105 | uh = udp_hdr(skb); | ||
| 106 | uh->len = htons(len); | ||
| 107 | |||
| 108 | if (need_csum) { | ||
| 109 | __be32 delta = htonl(oldlen + len); | ||
| 110 | |||
| 111 | uh->check = ~csum_fold((__force __wsum) | ||
| 112 | ((__force u32)uh->check + | ||
| 113 | (__force u32)delta)); | ||
| 114 | uh->check = gso_make_checksum(skb, ~uh->check); | ||
| 115 | |||
| 116 | if (uh->check == 0) | ||
| 117 | uh->check = CSUM_MANGLED_0; | ||
| 118 | } | ||
| 119 | |||
| 120 | skb->protocol = protocol; | ||
| 121 | } while ((skb = skb->next)); | ||
| 122 | out: | ||
| 123 | return segs; | ||
| 124 | } | ||
| 125 | |||
| 50 | static struct sk_buff *udp4_ufo_fragment(struct sk_buff *skb, | 126 | static struct sk_buff *udp4_ufo_fragment(struct sk_buff *skb, |
| 51 | netdev_features_t features) | 127 | netdev_features_t features) |
| 52 | { | 128 | { |
diff --git a/net/ipv4/udp_tunnel.c b/net/ipv4/udp_tunnel.c new file mode 100644 index 000000000000..61ec1a65207e --- /dev/null +++ b/net/ipv4/udp_tunnel.c | |||
| @@ -0,0 +1,100 @@ | |||
| 1 | #include <linux/module.h> | ||
| 2 | #include <linux/errno.h> | ||
| 3 | #include <linux/socket.h> | ||
| 4 | #include <linux/udp.h> | ||
| 5 | #include <linux/types.h> | ||
| 6 | #include <linux/kernel.h> | ||
| 7 | #include <net/udp.h> | ||
| 8 | #include <net/udp_tunnel.h> | ||
| 9 | #include <net/net_namespace.h> | ||
| 10 | |||
| 11 | int udp_sock_create(struct net *net, struct udp_port_cfg *cfg, | ||
| 12 | struct socket **sockp) | ||
| 13 | { | ||
| 14 | int err = -EINVAL; | ||
| 15 | struct socket *sock = NULL; | ||
| 16 | |||
| 17 | #if IS_ENABLED(CONFIG_IPV6) | ||
| 18 | if (cfg->family == AF_INET6) { | ||
| 19 | struct sockaddr_in6 udp6_addr; | ||
| 20 | |||
| 21 | err = sock_create_kern(AF_INET6, SOCK_DGRAM, 0, &sock); | ||
| 22 | if (err < 0) | ||
| 23 | goto error; | ||
| 24 | |||
| 25 | sk_change_net(sock->sk, net); | ||
| 26 | |||
| 27 | udp6_addr.sin6_family = AF_INET6; | ||
| 28 | memcpy(&udp6_addr.sin6_addr, &cfg->local_ip6, | ||
| 29 | sizeof(udp6_addr.sin6_addr)); | ||
| 30 | udp6_addr.sin6_port = cfg->local_udp_port; | ||
| 31 | err = kernel_bind(sock, (struct sockaddr *)&udp6_addr, | ||
| 32 | sizeof(udp6_addr)); | ||
| 33 | if (err < 0) | ||
| 34 | goto error; | ||
| 35 | |||
| 36 | if (cfg->peer_udp_port) { | ||
| 37 | udp6_addr.sin6_family = AF_INET6; | ||
| 38 | memcpy(&udp6_addr.sin6_addr, &cfg->peer_ip6, | ||
| 39 | sizeof(udp6_addr.sin6_addr)); | ||
| 40 | udp6_addr.sin6_port = cfg->peer_udp_port; | ||
| 41 | err = kernel_connect(sock, | ||
| 42 | (struct sockaddr *)&udp6_addr, | ||
| 43 | sizeof(udp6_addr), 0); | ||
| 44 | } | ||
| 45 | if (err < 0) | ||
| 46 | goto error; | ||
| 47 | |||
| 48 | udp_set_no_check6_tx(sock->sk, !cfg->use_udp6_tx_checksums); | ||
| 49 | udp_set_no_check6_rx(sock->sk, !cfg->use_udp6_rx_checksums); | ||
| 50 | } else | ||
| 51 | #endif | ||
| 52 | if (cfg->family == AF_INET) { | ||
| 53 | struct sockaddr_in udp_addr; | ||
| 54 | |||
| 55 | err = sock_create_kern(AF_INET, SOCK_DGRAM, 0, &sock); | ||
| 56 | if (err < 0) | ||
| 57 | goto error; | ||
| 58 | |||
| 59 | sk_change_net(sock->sk, net); | ||
| 60 | |||
| 61 | udp_addr.sin_family = AF_INET; | ||
| 62 | udp_addr.sin_addr = cfg->local_ip; | ||
| 63 | udp_addr.sin_port = cfg->local_udp_port; | ||
| 64 | err = kernel_bind(sock, (struct sockaddr *)&udp_addr, | ||
| 65 | sizeof(udp_addr)); | ||
| 66 | if (err < 0) | ||
| 67 | goto error; | ||
| 68 | |||
| 69 | if (cfg->peer_udp_port) { | ||
| 70 | udp_addr.sin_family = AF_INET; | ||
| 71 | udp_addr.sin_addr = cfg->peer_ip; | ||
| 72 | udp_addr.sin_port = cfg->peer_udp_port; | ||
| 73 | err = kernel_connect(sock, | ||
| 74 | (struct sockaddr *)&udp_addr, | ||
| 75 | sizeof(udp_addr), 0); | ||
| 76 | if (err < 0) | ||
| 77 | goto error; | ||
| 78 | } | ||
| 79 | |||
| 80 | sock->sk->sk_no_check_tx = !cfg->use_udp_checksums; | ||
| 81 | } else { | ||
| 82 | return -EPFNOSUPPORT; | ||
| 83 | } | ||
| 84 | |||
| 85 | |||
| 86 | *sockp = sock; | ||
| 87 | |||
| 88 | return 0; | ||
| 89 | |||
| 90 | error: | ||
| 91 | if (sock) { | ||
| 92 | kernel_sock_shutdown(sock, SHUT_RDWR); | ||
| 93 | sk_release_kernel(sock->sk); | ||
| 94 | } | ||
| 95 | *sockp = NULL; | ||
| 96 | return err; | ||
| 97 | } | ||
| 98 | EXPORT_SYMBOL(udp_sock_create); | ||
| 99 | |||
| 100 | MODULE_LICENSE("GPL"); | ||
diff --git a/net/ipv4/xfrm4_protocol.c b/net/ipv4/xfrm4_protocol.c index a2ce0101eaac..dccefa9d84cf 100644 --- a/net/ipv4/xfrm4_protocol.c +++ b/net/ipv4/xfrm4_protocol.c | |||
| @@ -124,7 +124,7 @@ static int xfrm4_ah_rcv(struct sk_buff *skb) | |||
| 124 | 124 | ||
| 125 | for_each_protocol_rcu(ah4_handlers, handler) | 125 | for_each_protocol_rcu(ah4_handlers, handler) |
| 126 | if ((ret = handler->handler(skb)) != -EINVAL) | 126 | if ((ret = handler->handler(skb)) != -EINVAL) |
| 127 | return ret;; | 127 | return ret; |
| 128 | 128 | ||
| 129 | icmp_send(skb, ICMP_DEST_UNREACH, ICMP_PORT_UNREACH, 0); | 129 | icmp_send(skb, ICMP_DEST_UNREACH, ICMP_PORT_UNREACH, 0); |
| 130 | 130 | ||
diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c index 5667b3003af9..0b239fc1816e 100644 --- a/net/ipv6/addrconf.c +++ b/net/ipv6/addrconf.c | |||
| @@ -108,11 +108,12 @@ static inline u32 cstamp_delta(unsigned long cstamp) | |||
| 108 | } | 108 | } |
| 109 | 109 | ||
| 110 | #ifdef CONFIG_SYSCTL | 110 | #ifdef CONFIG_SYSCTL |
| 111 | static void addrconf_sysctl_register(struct inet6_dev *idev); | 111 | static int addrconf_sysctl_register(struct inet6_dev *idev); |
| 112 | static void addrconf_sysctl_unregister(struct inet6_dev *idev); | 112 | static void addrconf_sysctl_unregister(struct inet6_dev *idev); |
| 113 | #else | 113 | #else |
| 114 | static inline void addrconf_sysctl_register(struct inet6_dev *idev) | 114 | static inline int addrconf_sysctl_register(struct inet6_dev *idev) |
| 115 | { | 115 | { |
| 116 | return 0; | ||
| 116 | } | 117 | } |
| 117 | 118 | ||
| 118 | static inline void addrconf_sysctl_unregister(struct inet6_dev *idev) | 119 | static inline void addrconf_sysctl_unregister(struct inet6_dev *idev) |
| @@ -186,6 +187,7 @@ static struct ipv6_devconf ipv6_devconf __read_mostly = { | |||
| 186 | .max_desync_factor = MAX_DESYNC_FACTOR, | 187 | .max_desync_factor = MAX_DESYNC_FACTOR, |
| 187 | .max_addresses = IPV6_MAX_ADDRESSES, | 188 | .max_addresses = IPV6_MAX_ADDRESSES, |
| 188 | .accept_ra_defrtr = 1, | 189 | .accept_ra_defrtr = 1, |
| 190 | .accept_ra_from_local = 0, | ||
| 189 | .accept_ra_pinfo = 1, | 191 | .accept_ra_pinfo = 1, |
| 190 | #ifdef CONFIG_IPV6_ROUTER_PREF | 192 | #ifdef CONFIG_IPV6_ROUTER_PREF |
| 191 | .accept_ra_rtr_pref = 1, | 193 | .accept_ra_rtr_pref = 1, |
| @@ -222,6 +224,7 @@ static struct ipv6_devconf ipv6_devconf_dflt __read_mostly = { | |||
| 222 | .max_desync_factor = MAX_DESYNC_FACTOR, | 224 | .max_desync_factor = MAX_DESYNC_FACTOR, |
| 223 | .max_addresses = IPV6_MAX_ADDRESSES, | 225 | .max_addresses = IPV6_MAX_ADDRESSES, |
| 224 | .accept_ra_defrtr = 1, | 226 | .accept_ra_defrtr = 1, |
| 227 | .accept_ra_from_local = 0, | ||
| 225 | .accept_ra_pinfo = 1, | 228 | .accept_ra_pinfo = 1, |
| 226 | #ifdef CONFIG_IPV6_ROUTER_PREF | 229 | #ifdef CONFIG_IPV6_ROUTER_PREF |
| 227 | .accept_ra_rtr_pref = 1, | 230 | .accept_ra_rtr_pref = 1, |
| @@ -308,16 +311,16 @@ err_ip: | |||
| 308 | static struct inet6_dev *ipv6_add_dev(struct net_device *dev) | 311 | static struct inet6_dev *ipv6_add_dev(struct net_device *dev) |
| 309 | { | 312 | { |
| 310 | struct inet6_dev *ndev; | 313 | struct inet6_dev *ndev; |
| 314 | int err = -ENOMEM; | ||
| 311 | 315 | ||
| 312 | ASSERT_RTNL(); | 316 | ASSERT_RTNL(); |
| 313 | 317 | ||
| 314 | if (dev->mtu < IPV6_MIN_MTU) | 318 | if (dev->mtu < IPV6_MIN_MTU) |
| 315 | return NULL; | 319 | return ERR_PTR(-EINVAL); |
| 316 | 320 | ||
| 317 | ndev = kzalloc(sizeof(struct inet6_dev), GFP_KERNEL); | 321 | ndev = kzalloc(sizeof(struct inet6_dev), GFP_KERNEL); |
| 318 | |||
| 319 | if (ndev == NULL) | 322 | if (ndev == NULL) |
| 320 | return NULL; | 323 | return ERR_PTR(err); |
| 321 | 324 | ||
| 322 | rwlock_init(&ndev->lock); | 325 | rwlock_init(&ndev->lock); |
| 323 | ndev->dev = dev; | 326 | ndev->dev = dev; |
| @@ -330,7 +333,7 @@ static struct inet6_dev *ipv6_add_dev(struct net_device *dev) | |||
| 330 | ndev->nd_parms = neigh_parms_alloc(dev, &nd_tbl); | 333 | ndev->nd_parms = neigh_parms_alloc(dev, &nd_tbl); |
| 331 | if (ndev->nd_parms == NULL) { | 334 | if (ndev->nd_parms == NULL) { |
| 332 | kfree(ndev); | 335 | kfree(ndev); |
| 333 | return NULL; | 336 | return ERR_PTR(err); |
| 334 | } | 337 | } |
| 335 | if (ndev->cnf.forwarding) | 338 | if (ndev->cnf.forwarding) |
| 336 | dev_disable_lro(dev); | 339 | dev_disable_lro(dev); |
| @@ -344,17 +347,14 @@ static struct inet6_dev *ipv6_add_dev(struct net_device *dev) | |||
| 344 | neigh_parms_release(&nd_tbl, ndev->nd_parms); | 347 | neigh_parms_release(&nd_tbl, ndev->nd_parms); |
| 345 | dev_put(dev); | 348 | dev_put(dev); |
| 346 | kfree(ndev); | 349 | kfree(ndev); |
| 347 | return NULL; | 350 | return ERR_PTR(err); |
| 348 | } | 351 | } |
| 349 | 352 | ||
| 350 | if (snmp6_register_dev(ndev) < 0) { | 353 | if (snmp6_register_dev(ndev) < 0) { |
| 351 | ADBG(KERN_WARNING | 354 | ADBG(KERN_WARNING |
| 352 | "%s: cannot create /proc/net/dev_snmp6/%s\n", | 355 | "%s: cannot create /proc/net/dev_snmp6/%s\n", |
| 353 | __func__, dev->name); | 356 | __func__, dev->name); |
| 354 | neigh_parms_release(&nd_tbl, ndev->nd_parms); | 357 | goto err_release; |
| 355 | ndev->dead = 1; | ||
| 356 | in6_dev_finish_destroy(ndev); | ||
| 357 | return NULL; | ||
| 358 | } | 358 | } |
| 359 | 359 | ||
| 360 | /* One reference from device. We must do this before | 360 | /* One reference from device. We must do this before |
| @@ -392,7 +392,12 @@ static struct inet6_dev *ipv6_add_dev(struct net_device *dev) | |||
| 392 | 392 | ||
| 393 | ipv6_mc_init_dev(ndev); | 393 | ipv6_mc_init_dev(ndev); |
| 394 | ndev->tstamp = jiffies; | 394 | ndev->tstamp = jiffies; |
| 395 | addrconf_sysctl_register(ndev); | 395 | err = addrconf_sysctl_register(ndev); |
| 396 | if (err) { | ||
| 397 | ipv6_mc_destroy_dev(ndev); | ||
| 398 | del_timer(&ndev->regen_timer); | ||
| 399 | goto err_release; | ||
| 400 | } | ||
| 396 | /* protected by rtnl_lock */ | 401 | /* protected by rtnl_lock */ |
| 397 | rcu_assign_pointer(dev->ip6_ptr, ndev); | 402 | rcu_assign_pointer(dev->ip6_ptr, ndev); |
| 398 | 403 | ||
| @@ -407,6 +412,12 @@ static struct inet6_dev *ipv6_add_dev(struct net_device *dev) | |||
| 407 | ipv6_dev_mc_inc(dev, &in6addr_linklocal_allrouters); | 412 | ipv6_dev_mc_inc(dev, &in6addr_linklocal_allrouters); |
| 408 | 413 | ||
| 409 | return ndev; | 414 | return ndev; |
| 415 | |||
| 416 | err_release: | ||
| 417 | neigh_parms_release(&nd_tbl, ndev->nd_parms); | ||
| 418 | ndev->dead = 1; | ||
| 419 | in6_dev_finish_destroy(ndev); | ||
| 420 | return ERR_PTR(err); | ||
| 410 | } | 421 | } |
| 411 | 422 | ||
| 412 | static struct inet6_dev *ipv6_find_idev(struct net_device *dev) | 423 | static struct inet6_dev *ipv6_find_idev(struct net_device *dev) |
| @@ -418,7 +429,7 @@ static struct inet6_dev *ipv6_find_idev(struct net_device *dev) | |||
| 418 | idev = __in6_dev_get(dev); | 429 | idev = __in6_dev_get(dev); |
| 419 | if (!idev) { | 430 | if (!idev) { |
| 420 | idev = ipv6_add_dev(dev); | 431 | idev = ipv6_add_dev(dev); |
| 421 | if (!idev) | 432 | if (IS_ERR(idev)) |
| 422 | return NULL; | 433 | return NULL; |
| 423 | } | 434 | } |
| 424 | 435 | ||
| @@ -2728,9 +2739,25 @@ static void addrconf_add_linklocal(struct inet6_dev *idev, const struct in6_addr | |||
| 2728 | } | 2739 | } |
| 2729 | } | 2740 | } |
| 2730 | 2741 | ||
| 2742 | static void addrconf_addr_gen(struct inet6_dev *idev, bool prefix_route) | ||
| 2743 | { | ||
| 2744 | if (idev->addr_gen_mode == IN6_ADDR_GEN_MODE_EUI64) { | ||
| 2745 | struct in6_addr addr; | ||
| 2746 | |||
| 2747 | ipv6_addr_set(&addr, htonl(0xFE800000), 0, 0, 0); | ||
| 2748 | /* addrconf_add_linklocal also adds a prefix_route and we | ||
| 2749 | * only need to care about prefix routes if ipv6_generate_eui64 | ||
| 2750 | * couldn't generate one. | ||
| 2751 | */ | ||
| 2752 | if (ipv6_generate_eui64(addr.s6_addr + 8, idev->dev) == 0) | ||
| 2753 | addrconf_add_linklocal(idev, &addr); | ||
| 2754 | else if (prefix_route) | ||
| 2755 | addrconf_prefix_route(&addr, 64, idev->dev, 0, 0); | ||
| 2756 | } | ||
| 2757 | } | ||
| 2758 | |||
| 2731 | static void addrconf_dev_config(struct net_device *dev) | 2759 | static void addrconf_dev_config(struct net_device *dev) |
| 2732 | { | 2760 | { |
| 2733 | struct in6_addr addr; | ||
| 2734 | struct inet6_dev *idev; | 2761 | struct inet6_dev *idev; |
| 2735 | 2762 | ||
| 2736 | ASSERT_RTNL(); | 2763 | ASSERT_RTNL(); |
| @@ -2751,11 +2778,7 @@ static void addrconf_dev_config(struct net_device *dev) | |||
| 2751 | if (IS_ERR(idev)) | 2778 | if (IS_ERR(idev)) |
| 2752 | return; | 2779 | return; |
| 2753 | 2780 | ||
| 2754 | memset(&addr, 0, sizeof(struct in6_addr)); | 2781 | addrconf_addr_gen(idev, false); |
| 2755 | addr.s6_addr32[0] = htonl(0xFE800000); | ||
| 2756 | |||
| 2757 | if (ipv6_generate_eui64(addr.s6_addr + 8, dev) == 0) | ||
| 2758 | addrconf_add_linklocal(idev, &addr); | ||
| 2759 | } | 2782 | } |
| 2760 | 2783 | ||
| 2761 | #if IS_ENABLED(CONFIG_IPV6_SIT) | 2784 | #if IS_ENABLED(CONFIG_IPV6_SIT) |
| @@ -2777,11 +2800,7 @@ static void addrconf_sit_config(struct net_device *dev) | |||
| 2777 | } | 2800 | } |
| 2778 | 2801 | ||
| 2779 | if (dev->priv_flags & IFF_ISATAP) { | 2802 | if (dev->priv_flags & IFF_ISATAP) { |
| 2780 | struct in6_addr addr; | 2803 | addrconf_addr_gen(idev, false); |
| 2781 | |||
| 2782 | ipv6_addr_set(&addr, htonl(0xFE800000), 0, 0, 0); | ||
| 2783 | if (!ipv6_generate_eui64(addr.s6_addr + 8, dev)) | ||
| 2784 | addrconf_add_linklocal(idev, &addr); | ||
| 2785 | return; | 2804 | return; |
| 2786 | } | 2805 | } |
| 2787 | 2806 | ||
| @@ -2796,7 +2815,6 @@ static void addrconf_sit_config(struct net_device *dev) | |||
| 2796 | static void addrconf_gre_config(struct net_device *dev) | 2815 | static void addrconf_gre_config(struct net_device *dev) |
| 2797 | { | 2816 | { |
| 2798 | struct inet6_dev *idev; | 2817 | struct inet6_dev *idev; |
| 2799 | struct in6_addr addr; | ||
| 2800 | 2818 | ||
| 2801 | ASSERT_RTNL(); | 2819 | ASSERT_RTNL(); |
| 2802 | 2820 | ||
| @@ -2805,11 +2823,7 @@ static void addrconf_gre_config(struct net_device *dev) | |||
| 2805 | return; | 2823 | return; |
| 2806 | } | 2824 | } |
| 2807 | 2825 | ||
| 2808 | ipv6_addr_set(&addr, htonl(0xFE800000), 0, 0, 0); | 2826 | addrconf_addr_gen(idev, true); |
| 2809 | if (!ipv6_generate_eui64(addr.s6_addr + 8, dev)) | ||
| 2810 | addrconf_add_linklocal(idev, &addr); | ||
| 2811 | else | ||
| 2812 | addrconf_prefix_route(&addr, 64, dev, 0, 0); | ||
| 2813 | } | 2827 | } |
| 2814 | #endif | 2828 | #endif |
| 2815 | 2829 | ||
| @@ -2825,8 +2839,8 @@ static int addrconf_notify(struct notifier_block *this, unsigned long event, | |||
| 2825 | case NETDEV_REGISTER: | 2839 | case NETDEV_REGISTER: |
| 2826 | if (!idev && dev->mtu >= IPV6_MIN_MTU) { | 2840 | if (!idev && dev->mtu >= IPV6_MIN_MTU) { |
| 2827 | idev = ipv6_add_dev(dev); | 2841 | idev = ipv6_add_dev(dev); |
| 2828 | if (!idev) | 2842 | if (IS_ERR(idev)) |
| 2829 | return notifier_from_errno(-ENOMEM); | 2843 | return notifier_from_errno(PTR_ERR(idev)); |
| 2830 | } | 2844 | } |
| 2831 | break; | 2845 | break; |
| 2832 | 2846 | ||
| @@ -2846,7 +2860,7 @@ static int addrconf_notify(struct notifier_block *this, unsigned long event, | |||
| 2846 | if (!idev && dev->mtu >= IPV6_MIN_MTU) | 2860 | if (!idev && dev->mtu >= IPV6_MIN_MTU) |
| 2847 | idev = ipv6_add_dev(dev); | 2861 | idev = ipv6_add_dev(dev); |
| 2848 | 2862 | ||
| 2849 | if (idev) { | 2863 | if (!IS_ERR_OR_NULL(idev)) { |
| 2850 | idev->if_flags |= IF_READY; | 2864 | idev->if_flags |= IF_READY; |
| 2851 | run_pending = 1; | 2865 | run_pending = 1; |
| 2852 | } | 2866 | } |
| @@ -2889,7 +2903,7 @@ static int addrconf_notify(struct notifier_block *this, unsigned long event, | |||
| 2889 | break; | 2903 | break; |
| 2890 | } | 2904 | } |
| 2891 | 2905 | ||
| 2892 | if (idev) { | 2906 | if (!IS_ERR_OR_NULL(idev)) { |
| 2893 | if (run_pending) | 2907 | if (run_pending) |
| 2894 | addrconf_dad_run(idev); | 2908 | addrconf_dad_run(idev); |
| 2895 | 2909 | ||
| @@ -2924,7 +2938,7 @@ static int addrconf_notify(struct notifier_block *this, unsigned long event, | |||
| 2924 | 2938 | ||
| 2925 | if (!idev && dev->mtu >= IPV6_MIN_MTU) { | 2939 | if (!idev && dev->mtu >= IPV6_MIN_MTU) { |
| 2926 | idev = ipv6_add_dev(dev); | 2940 | idev = ipv6_add_dev(dev); |
| 2927 | if (idev) | 2941 | if (!IS_ERR(idev)) |
| 2928 | break; | 2942 | break; |
| 2929 | } | 2943 | } |
| 2930 | 2944 | ||
| @@ -2945,10 +2959,14 @@ static int addrconf_notify(struct notifier_block *this, unsigned long event, | |||
| 2945 | if (idev) { | 2959 | if (idev) { |
| 2946 | snmp6_unregister_dev(idev); | 2960 | snmp6_unregister_dev(idev); |
| 2947 | addrconf_sysctl_unregister(idev); | 2961 | addrconf_sysctl_unregister(idev); |
| 2948 | addrconf_sysctl_register(idev); | 2962 | err = addrconf_sysctl_register(idev); |
| 2949 | err = snmp6_register_dev(idev); | ||
| 2950 | if (err) | 2963 | if (err) |
| 2951 | return notifier_from_errno(err); | 2964 | return notifier_from_errno(err); |
| 2965 | err = snmp6_register_dev(idev); | ||
| 2966 | if (err) { | ||
| 2967 | addrconf_sysctl_unregister(idev); | ||
| 2968 | return notifier_from_errno(err); | ||
| 2969 | } | ||
| 2952 | } | 2970 | } |
| 2953 | break; | 2971 | break; |
| 2954 | 2972 | ||
| @@ -4321,6 +4339,7 @@ static inline void ipv6_store_devconf(struct ipv6_devconf *cnf, | |||
| 4321 | array[DEVCONF_FORCE_TLLAO] = cnf->force_tllao; | 4339 | array[DEVCONF_FORCE_TLLAO] = cnf->force_tllao; |
| 4322 | array[DEVCONF_NDISC_NOTIFY] = cnf->ndisc_notify; | 4340 | array[DEVCONF_NDISC_NOTIFY] = cnf->ndisc_notify; |
| 4323 | array[DEVCONF_SUPPRESS_FRAG_NDISC] = cnf->suppress_frag_ndisc; | 4341 | array[DEVCONF_SUPPRESS_FRAG_NDISC] = cnf->suppress_frag_ndisc; |
| 4342 | array[DEVCONF_ACCEPT_RA_FROM_LOCAL] = cnf->accept_ra_from_local; | ||
| 4324 | } | 4343 | } |
| 4325 | 4344 | ||
| 4326 | static inline size_t inet6_ifla6_size(void) | 4345 | static inline size_t inet6_ifla6_size(void) |
| @@ -4420,6 +4439,10 @@ static int inet6_fill_ifla6_attrs(struct sk_buff *skb, struct inet6_dev *idev) | |||
| 4420 | nla = nla_reserve(skb, IFLA_INET6_TOKEN, sizeof(struct in6_addr)); | 4439 | nla = nla_reserve(skb, IFLA_INET6_TOKEN, sizeof(struct in6_addr)); |
| 4421 | if (nla == NULL) | 4440 | if (nla == NULL) |
| 4422 | goto nla_put_failure; | 4441 | goto nla_put_failure; |
| 4442 | |||
| 4443 | if (nla_put_u8(skb, IFLA_INET6_ADDR_GEN_MODE, idev->addr_gen_mode)) | ||
| 4444 | goto nla_put_failure; | ||
| 4445 | |||
| 4423 | read_lock_bh(&idev->lock); | 4446 | read_lock_bh(&idev->lock); |
| 4424 | memcpy(nla_data(nla), idev->token.s6_addr, nla_len(nla)); | 4447 | memcpy(nla_data(nla), idev->token.s6_addr, nla_len(nla)); |
| 4425 | read_unlock_bh(&idev->lock); | 4448 | read_unlock_bh(&idev->lock); |
| @@ -4524,8 +4547,21 @@ static int inet6_set_link_af(struct net_device *dev, const struct nlattr *nla) | |||
| 4524 | if (nla_parse_nested(tb, IFLA_INET6_MAX, nla, NULL) < 0) | 4547 | if (nla_parse_nested(tb, IFLA_INET6_MAX, nla, NULL) < 0) |
| 4525 | BUG(); | 4548 | BUG(); |
| 4526 | 4549 | ||
| 4527 | if (tb[IFLA_INET6_TOKEN]) | 4550 | if (tb[IFLA_INET6_TOKEN]) { |
| 4528 | err = inet6_set_iftoken(idev, nla_data(tb[IFLA_INET6_TOKEN])); | 4551 | err = inet6_set_iftoken(idev, nla_data(tb[IFLA_INET6_TOKEN])); |
| 4552 | if (err) | ||
| 4553 | return err; | ||
| 4554 | } | ||
| 4555 | |||
| 4556 | if (tb[IFLA_INET6_ADDR_GEN_MODE]) { | ||
| 4557 | u8 mode = nla_get_u8(tb[IFLA_INET6_ADDR_GEN_MODE]); | ||
| 4558 | |||
| 4559 | if (mode != IN6_ADDR_GEN_MODE_EUI64 && | ||
| 4560 | mode != IN6_ADDR_GEN_MODE_NONE) | ||
| 4561 | return -EINVAL; | ||
| 4562 | idev->addr_gen_mode = mode; | ||
| 4563 | err = 0; | ||
| 4564 | } | ||
| 4529 | 4565 | ||
| 4530 | return err; | 4566 | return err; |
| 4531 | } | 4567 | } |
| @@ -5168,6 +5204,13 @@ static struct addrconf_sysctl_table | |||
| 5168 | .proc_handler = proc_dointvec | 5204 | .proc_handler = proc_dointvec |
| 5169 | }, | 5205 | }, |
| 5170 | { | 5206 | { |
| 5207 | .procname = "accept_ra_from_local", | ||
| 5208 | .data = &ipv6_devconf.accept_ra_from_local, | ||
| 5209 | .maxlen = sizeof(int), | ||
| 5210 | .mode = 0644, | ||
| 5211 | .proc_handler = proc_dointvec, | ||
| 5212 | }, | ||
| 5213 | { | ||
| 5171 | /* sentinel */ | 5214 | /* sentinel */ |
| 5172 | } | 5215 | } |
| 5173 | }, | 5216 | }, |
| @@ -5218,12 +5261,23 @@ static void __addrconf_sysctl_unregister(struct ipv6_devconf *p) | |||
| 5218 | kfree(t); | 5261 | kfree(t); |
| 5219 | } | 5262 | } |
| 5220 | 5263 | ||
| 5221 | static void addrconf_sysctl_register(struct inet6_dev *idev) | 5264 | static int addrconf_sysctl_register(struct inet6_dev *idev) |
| 5222 | { | 5265 | { |
| 5223 | neigh_sysctl_register(idev->dev, idev->nd_parms, | 5266 | int err; |
| 5224 | &ndisc_ifinfo_sysctl_change); | 5267 | |
| 5225 | __addrconf_sysctl_register(dev_net(idev->dev), idev->dev->name, | 5268 | if (!sysctl_dev_name_is_allowed(idev->dev->name)) |
| 5226 | idev, &idev->cnf); | 5269 | return -EINVAL; |
| 5270 | |||
| 5271 | err = neigh_sysctl_register(idev->dev, idev->nd_parms, | ||
| 5272 | &ndisc_ifinfo_sysctl_change); | ||
| 5273 | if (err) | ||
| 5274 | return err; | ||
| 5275 | err = __addrconf_sysctl_register(dev_net(idev->dev), idev->dev->name, | ||
| 5276 | idev, &idev->cnf); | ||
| 5277 | if (err) | ||
| 5278 | neigh_sysctl_unregister(idev->nd_parms); | ||
| 5279 | |||
| 5280 | return err; | ||
| 5227 | } | 5281 | } |
| 5228 | 5282 | ||
| 5229 | static void addrconf_sysctl_unregister(struct inet6_dev *idev) | 5283 | static void addrconf_sysctl_unregister(struct inet6_dev *idev) |
| @@ -5308,6 +5362,7 @@ static struct rtnl_af_ops inet6_ops = { | |||
| 5308 | 5362 | ||
| 5309 | int __init addrconf_init(void) | 5363 | int __init addrconf_init(void) |
| 5310 | { | 5364 | { |
| 5365 | struct inet6_dev *idev; | ||
| 5311 | int i, err; | 5366 | int i, err; |
| 5312 | 5367 | ||
| 5313 | err = ipv6_addr_label_init(); | 5368 | err = ipv6_addr_label_init(); |
| @@ -5346,11 +5401,12 @@ int __init addrconf_init(void) | |||
| 5346 | * device and it being up should be removed. | 5401 | * device and it being up should be removed. |
| 5347 | */ | 5402 | */ |
| 5348 | rtnl_lock(); | 5403 | rtnl_lock(); |
| 5349 | if (!ipv6_add_dev(init_net.loopback_dev)) | 5404 | idev = ipv6_add_dev(init_net.loopback_dev); |
| 5350 | err = -ENOMEM; | ||
| 5351 | rtnl_unlock(); | 5405 | rtnl_unlock(); |
| 5352 | if (err) | 5406 | if (IS_ERR(idev)) { |
| 5407 | err = PTR_ERR(idev); | ||
| 5353 | goto errlo; | 5408 | goto errlo; |
| 5409 | } | ||
| 5354 | 5410 | ||
| 5355 | for (i = 0; i < IN6_ADDR_HSIZE; i++) | 5411 | for (i = 0; i < IN6_ADDR_HSIZE; i++) |
| 5356 | INIT_HLIST_HEAD(&inet6_addr_lst[i]); | 5412 | INIT_HLIST_HEAD(&inet6_addr_lst[i]); |
diff --git a/net/ipv6/addrlabel.c b/net/ipv6/addrlabel.c index 731e1e1722d9..fd0dc47f471d 100644 --- a/net/ipv6/addrlabel.c +++ b/net/ipv6/addrlabel.c | |||
| @@ -277,7 +277,7 @@ static int __ip6addrlbl_add(struct ip6addrlbl_entry *newp, int replace) | |||
| 277 | last = p; | 277 | last = p; |
| 278 | } | 278 | } |
| 279 | if (last) | 279 | if (last) |
| 280 | hlist_add_after_rcu(&last->list, &newp->list); | 280 | hlist_add_behind_rcu(&newp->list, &last->list); |
| 281 | else | 281 | else |
| 282 | hlist_add_head_rcu(&newp->list, &ip6addrlbl_table.head); | 282 | hlist_add_head_rcu(&newp->list, &ip6addrlbl_table.head); |
| 283 | out: | 283 | out: |
diff --git a/net/ipv6/af_inet6.c b/net/ipv6/af_inet6.c index 7cb4392690dd..2daa3a133e49 100644 --- a/net/ipv6/af_inet6.c +++ b/net/ipv6/af_inet6.c | |||
| @@ -197,7 +197,7 @@ lookup_protocol: | |||
| 197 | np->mcast_hops = IPV6_DEFAULT_MCASTHOPS; | 197 | np->mcast_hops = IPV6_DEFAULT_MCASTHOPS; |
| 198 | np->mc_loop = 1; | 198 | np->mc_loop = 1; |
| 199 | np->pmtudisc = IPV6_PMTUDISC_WANT; | 199 | np->pmtudisc = IPV6_PMTUDISC_WANT; |
| 200 | np->ipv6only = net->ipv6.sysctl.bindv6only; | 200 | sk->sk_ipv6only = net->ipv6.sysctl.bindv6only; |
| 201 | 201 | ||
| 202 | /* Init the ipv4 part of the socket since we can have sockets | 202 | /* Init the ipv4 part of the socket since we can have sockets |
| 203 | * using v6 API for ipv4. | 203 | * using v6 API for ipv4. |
| @@ -294,7 +294,7 @@ int inet6_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len) | |||
| 294 | /* Binding to v4-mapped address on a v6-only socket | 294 | /* Binding to v4-mapped address on a v6-only socket |
| 295 | * makes no sense | 295 | * makes no sense |
| 296 | */ | 296 | */ |
| 297 | if (np->ipv6only) { | 297 | if (sk->sk_ipv6only) { |
| 298 | err = -EINVAL; | 298 | err = -EINVAL; |
| 299 | goto out; | 299 | goto out; |
| 300 | } | 300 | } |
| @@ -371,7 +371,7 @@ int inet6_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len) | |||
| 371 | if (addr_type != IPV6_ADDR_ANY) { | 371 | if (addr_type != IPV6_ADDR_ANY) { |
| 372 | sk->sk_userlocks |= SOCK_BINDADDR_LOCK; | 372 | sk->sk_userlocks |= SOCK_BINDADDR_LOCK; |
| 373 | if (addr_type != IPV6_ADDR_MAPPED) | 373 | if (addr_type != IPV6_ADDR_MAPPED) |
| 374 | np->ipv6only = 1; | 374 | sk->sk_ipv6only = 1; |
| 375 | } | 375 | } |
| 376 | if (snum) | 376 | if (snum) |
| 377 | sk->sk_userlocks |= SOCK_BINDPORT_LOCK; | 377 | sk->sk_userlocks |= SOCK_BINDPORT_LOCK; |
| @@ -765,6 +765,7 @@ static int __net_init inet6_net_init(struct net *net) | |||
| 765 | net->ipv6.sysctl.bindv6only = 0; | 765 | net->ipv6.sysctl.bindv6only = 0; |
| 766 | net->ipv6.sysctl.icmpv6_time = 1*HZ; | 766 | net->ipv6.sysctl.icmpv6_time = 1*HZ; |
| 767 | net->ipv6.sysctl.flowlabel_consistency = 1; | 767 | net->ipv6.sysctl.flowlabel_consistency = 1; |
| 768 | net->ipv6.sysctl.auto_flowlabels = 0; | ||
| 768 | atomic_set(&net->ipv6.rt_genid, 0); | 769 | atomic_set(&net->ipv6.rt_genid, 0); |
| 769 | 770 | ||
| 770 | err = ipv6_init_mibs(net); | 771 | err = ipv6_init_mibs(net); |
diff --git a/net/ipv6/datagram.c b/net/ipv6/datagram.c index c3bf2d2e519e..2753319524f1 100644 --- a/net/ipv6/datagram.c +++ b/net/ipv6/datagram.c | |||
| @@ -199,6 +199,7 @@ ipv4_connected: | |||
| 199 | NULL); | 199 | NULL); |
| 200 | 200 | ||
| 201 | sk->sk_state = TCP_ESTABLISHED; | 201 | sk->sk_state = TCP_ESTABLISHED; |
| 202 | ip6_set_txhash(sk); | ||
| 202 | out: | 203 | out: |
| 203 | fl6_sock_release(flowlabel); | 204 | fl6_sock_release(flowlabel); |
| 204 | return err; | 205 | return err; |
diff --git a/net/ipv6/icmp.c b/net/ipv6/icmp.c index f6c84a6eb238..06ba3e58320b 100644 --- a/net/ipv6/icmp.c +++ b/net/ipv6/icmp.c | |||
| @@ -626,9 +626,10 @@ void icmpv6_notify(struct sk_buff *skb, u8 type, u8 code, __be32 info) | |||
| 626 | int inner_offset; | 626 | int inner_offset; |
| 627 | __be16 frag_off; | 627 | __be16 frag_off; |
| 628 | u8 nexthdr; | 628 | u8 nexthdr; |
| 629 | struct net *net = dev_net(skb->dev); | ||
| 629 | 630 | ||
| 630 | if (!pskb_may_pull(skb, sizeof(struct ipv6hdr))) | 631 | if (!pskb_may_pull(skb, sizeof(struct ipv6hdr))) |
| 631 | return; | 632 | goto out; |
| 632 | 633 | ||
| 633 | nexthdr = ((struct ipv6hdr *)skb->data)->nexthdr; | 634 | nexthdr = ((struct ipv6hdr *)skb->data)->nexthdr; |
| 634 | if (ipv6_ext_hdr(nexthdr)) { | 635 | if (ipv6_ext_hdr(nexthdr)) { |
| @@ -636,14 +637,14 @@ void icmpv6_notify(struct sk_buff *skb, u8 type, u8 code, __be32 info) | |||
| 636 | inner_offset = ipv6_skip_exthdr(skb, sizeof(struct ipv6hdr), | 637 | inner_offset = ipv6_skip_exthdr(skb, sizeof(struct ipv6hdr), |
| 637 | &nexthdr, &frag_off); | 638 | &nexthdr, &frag_off); |
| 638 | if (inner_offset<0) | 639 | if (inner_offset<0) |
| 639 | return; | 640 | goto out; |
| 640 | } else { | 641 | } else { |
| 641 | inner_offset = sizeof(struct ipv6hdr); | 642 | inner_offset = sizeof(struct ipv6hdr); |
| 642 | } | 643 | } |
| 643 | 644 | ||
| 644 | /* Checkin header including 8 bytes of inner protocol header. */ | 645 | /* Checkin header including 8 bytes of inner protocol header. */ |
| 645 | if (!pskb_may_pull(skb, inner_offset+8)) | 646 | if (!pskb_may_pull(skb, inner_offset+8)) |
| 646 | return; | 647 | goto out; |
| 647 | 648 | ||
| 648 | /* BUGGG_FUTURE: we should try to parse exthdrs in this packet. | 649 | /* BUGGG_FUTURE: we should try to parse exthdrs in this packet. |
| 649 | Without this we will not able f.e. to make source routed | 650 | Without this we will not able f.e. to make source routed |
| @@ -652,13 +653,15 @@ void icmpv6_notify(struct sk_buff *skb, u8 type, u8 code, __be32 info) | |||
| 652 | --ANK (980726) | 653 | --ANK (980726) |
| 653 | */ | 654 | */ |
| 654 | 655 | ||
| 655 | rcu_read_lock(); | ||
| 656 | ipprot = rcu_dereference(inet6_protos[nexthdr]); | 656 | ipprot = rcu_dereference(inet6_protos[nexthdr]); |
| 657 | if (ipprot && ipprot->err_handler) | 657 | if (ipprot && ipprot->err_handler) |
| 658 | ipprot->err_handler(skb, NULL, type, code, inner_offset, info); | 658 | ipprot->err_handler(skb, NULL, type, code, inner_offset, info); |
| 659 | rcu_read_unlock(); | ||
| 660 | 659 | ||
| 661 | raw6_icmp_error(skb, nexthdr, type, code, inner_offset, info); | 660 | raw6_icmp_error(skb, nexthdr, type, code, inner_offset, info); |
| 661 | return; | ||
| 662 | |||
| 663 | out: | ||
| 664 | ICMP6_INC_STATS_BH(net, __in6_dev_get(skb->dev), ICMP6_MIB_INERRORS); | ||
| 662 | } | 665 | } |
| 663 | 666 | ||
| 664 | /* | 667 | /* |
diff --git a/net/ipv6/ip6_gre.c b/net/ipv6/ip6_gre.c index 3873181ed856..5f19dfbc4c6a 100644 --- a/net/ipv6/ip6_gre.c +++ b/net/ipv6/ip6_gre.c | |||
| @@ -322,7 +322,8 @@ static struct ip6_tnl *ip6gre_tunnel_locate(struct net *net, | |||
| 322 | else | 322 | else |
| 323 | strcpy(name, "ip6gre%d"); | 323 | strcpy(name, "ip6gre%d"); |
| 324 | 324 | ||
| 325 | dev = alloc_netdev(sizeof(*t), name, ip6gre_tunnel_setup); | 325 | dev = alloc_netdev(sizeof(*t), name, NET_NAME_UNKNOWN, |
| 326 | ip6gre_tunnel_setup); | ||
| 326 | if (!dev) | 327 | if (!dev) |
| 327 | return NULL; | 328 | return NULL; |
| 328 | 329 | ||
| @@ -723,7 +724,8 @@ static netdev_tx_t ip6gre_xmit2(struct sk_buff *skb, | |||
| 723 | * Push down and install the IP header. | 724 | * Push down and install the IP header. |
| 724 | */ | 725 | */ |
| 725 | ipv6h = ipv6_hdr(skb); | 726 | ipv6h = ipv6_hdr(skb); |
| 726 | ip6_flow_hdr(ipv6h, INET_ECN_encapsulate(0, dsfield), fl6->flowlabel); | 727 | ip6_flow_hdr(ipv6h, INET_ECN_encapsulate(0, dsfield), |
| 728 | ip6_make_flowlabel(net, skb, fl6->flowlabel, false)); | ||
| 727 | ipv6h->hop_limit = tunnel->parms.hop_limit; | 729 | ipv6h->hop_limit = tunnel->parms.hop_limit; |
| 728 | ipv6h->nexthdr = proto; | 730 | ipv6h->nexthdr = proto; |
| 729 | ipv6h->saddr = fl6->saddr; | 731 | ipv6h->saddr = fl6->saddr; |
| @@ -1174,7 +1176,9 @@ static int ip6gre_header(struct sk_buff *skb, struct net_device *dev, | |||
| 1174 | struct ipv6hdr *ipv6h = (struct ipv6hdr *)skb_push(skb, t->hlen); | 1176 | struct ipv6hdr *ipv6h = (struct ipv6hdr *)skb_push(skb, t->hlen); |
| 1175 | __be16 *p = (__be16 *)(ipv6h+1); | 1177 | __be16 *p = (__be16 *)(ipv6h+1); |
| 1176 | 1178 | ||
| 1177 | ip6_flow_hdr(ipv6h, 0, t->fl.u.ip6.flowlabel); | 1179 | ip6_flow_hdr(ipv6h, 0, |
| 1180 | ip6_make_flowlabel(dev_net(dev), skb, | ||
| 1181 | t->fl.u.ip6.flowlabel, false)); | ||
| 1178 | ipv6h->hop_limit = t->parms.hop_limit; | 1182 | ipv6h->hop_limit = t->parms.hop_limit; |
| 1179 | ipv6h->nexthdr = NEXTHDR_GRE; | 1183 | ipv6h->nexthdr = NEXTHDR_GRE; |
| 1180 | ipv6h->saddr = t->parms.laddr; | 1184 | ipv6h->saddr = t->parms.laddr; |
| @@ -1323,7 +1327,8 @@ static int __net_init ip6gre_init_net(struct net *net) | |||
| 1323 | int err; | 1327 | int err; |
| 1324 | 1328 | ||
| 1325 | ign->fb_tunnel_dev = alloc_netdev(sizeof(struct ip6_tnl), "ip6gre0", | 1329 | ign->fb_tunnel_dev = alloc_netdev(sizeof(struct ip6_tnl), "ip6gre0", |
| 1326 | ip6gre_tunnel_setup); | 1330 | NET_NAME_UNKNOWN, |
| 1331 | ip6gre_tunnel_setup); | ||
| 1327 | if (!ign->fb_tunnel_dev) { | 1332 | if (!ign->fb_tunnel_dev) { |
| 1328 | err = -ENOMEM; | 1333 | err = -ENOMEM; |
| 1329 | goto err_alloc_dev; | 1334 | goto err_alloc_dev; |
diff --git a/net/ipv6/ip6_output.c b/net/ipv6/ip6_output.c index 45702b8cd141..315a55d66079 100644 --- a/net/ipv6/ip6_output.c +++ b/net/ipv6/ip6_output.c | |||
| @@ -205,7 +205,8 @@ int ip6_xmit(struct sock *sk, struct sk_buff *skb, struct flowi6 *fl6, | |||
| 205 | if (hlimit < 0) | 205 | if (hlimit < 0) |
| 206 | hlimit = ip6_dst_hoplimit(dst); | 206 | hlimit = ip6_dst_hoplimit(dst); |
| 207 | 207 | ||
| 208 | ip6_flow_hdr(hdr, tclass, fl6->flowlabel); | 208 | ip6_flow_hdr(hdr, tclass, ip6_make_flowlabel(net, skb, fl6->flowlabel, |
| 209 | np->autoflowlabel)); | ||
| 209 | 210 | ||
| 210 | hdr->payload_len = htons(seg_len); | 211 | hdr->payload_len = htons(seg_len); |
| 211 | hdr->nexthdr = proto; | 212 | hdr->nexthdr = proto; |
| @@ -802,8 +803,8 @@ slow_path: | |||
| 802 | /* | 803 | /* |
| 803 | * Copy a block of the IP datagram. | 804 | * Copy a block of the IP datagram. |
| 804 | */ | 805 | */ |
| 805 | if (skb_copy_bits(skb, ptr, skb_transport_header(frag), len)) | 806 | BUG_ON(skb_copy_bits(skb, ptr, skb_transport_header(frag), |
| 806 | BUG(); | 807 | len)); |
| 807 | left -= len; | 808 | left -= len; |
| 808 | 809 | ||
| 809 | fh->frag_off = htons(offset); | 810 | fh->frag_off = htons(offset); |
| @@ -1156,6 +1157,7 @@ int ip6_append_data(struct sock *sk, int getfrag(void *from, char *to, | |||
| 1156 | int err; | 1157 | int err; |
| 1157 | int offset = 0; | 1158 | int offset = 0; |
| 1158 | __u8 tx_flags = 0; | 1159 | __u8 tx_flags = 0; |
| 1160 | u32 tskey = 0; | ||
| 1159 | 1161 | ||
| 1160 | if (flags&MSG_PROBE) | 1162 | if (flags&MSG_PROBE) |
| 1161 | return 0; | 1163 | return 0; |
| @@ -1271,9 +1273,12 @@ emsgsize: | |||
| 1271 | } | 1273 | } |
| 1272 | } | 1274 | } |
| 1273 | 1275 | ||
| 1274 | /* For UDP, check if TX timestamp is enabled */ | 1276 | if (sk->sk_type == SOCK_DGRAM || sk->sk_type == SOCK_RAW) { |
| 1275 | if (sk->sk_type == SOCK_DGRAM) | ||
| 1276 | sock_tx_timestamp(sk, &tx_flags); | 1277 | sock_tx_timestamp(sk, &tx_flags); |
| 1278 | if (tx_flags & SKBTX_ANY_SW_TSTAMP && | ||
| 1279 | sk->sk_tsflags & SOF_TIMESTAMPING_OPT_ID) | ||
| 1280 | tskey = sk->sk_tskey++; | ||
| 1281 | } | ||
| 1277 | 1282 | ||
| 1278 | /* | 1283 | /* |
| 1279 | * Let's try using as much space as possible. | 1284 | * Let's try using as much space as possible. |
| @@ -1381,12 +1386,6 @@ alloc_new_skb: | |||
| 1381 | sk->sk_allocation); | 1386 | sk->sk_allocation); |
| 1382 | if (unlikely(skb == NULL)) | 1387 | if (unlikely(skb == NULL)) |
| 1383 | err = -ENOBUFS; | 1388 | err = -ENOBUFS; |
| 1384 | else { | ||
| 1385 | /* Only the initial fragment | ||
| 1386 | * is time stamped. | ||
| 1387 | */ | ||
| 1388 | tx_flags = 0; | ||
| 1389 | } | ||
| 1390 | } | 1389 | } |
| 1391 | if (skb == NULL) | 1390 | if (skb == NULL) |
| 1392 | goto error; | 1391 | goto error; |
| @@ -1400,8 +1399,11 @@ alloc_new_skb: | |||
| 1400 | skb_reserve(skb, hh_len + sizeof(struct frag_hdr) + | 1399 | skb_reserve(skb, hh_len + sizeof(struct frag_hdr) + |
| 1401 | dst_exthdrlen); | 1400 | dst_exthdrlen); |
| 1402 | 1401 | ||
| 1403 | if (sk->sk_type == SOCK_DGRAM) | 1402 | /* Only the initial fragment is time stamped */ |
| 1404 | skb_shinfo(skb)->tx_flags = tx_flags; | 1403 | skb_shinfo(skb)->tx_flags = tx_flags; |
| 1404 | tx_flags = 0; | ||
| 1405 | skb_shinfo(skb)->tskey = tskey; | ||
| 1406 | tskey = 0; | ||
| 1405 | 1407 | ||
| 1406 | /* | 1408 | /* |
| 1407 | * Find where to start putting bytes | 1409 | * Find where to start putting bytes |
| @@ -1571,7 +1573,9 @@ int ip6_push_pending_frames(struct sock *sk) | |||
| 1571 | skb_reset_network_header(skb); | 1573 | skb_reset_network_header(skb); |
| 1572 | hdr = ipv6_hdr(skb); | 1574 | hdr = ipv6_hdr(skb); |
| 1573 | 1575 | ||
| 1574 | ip6_flow_hdr(hdr, np->cork.tclass, fl6->flowlabel); | 1576 | ip6_flow_hdr(hdr, np->cork.tclass, |
| 1577 | ip6_make_flowlabel(net, skb, fl6->flowlabel, | ||
| 1578 | np->autoflowlabel)); | ||
| 1575 | hdr->hop_limit = np->cork.hop_limit; | 1579 | hdr->hop_limit = np->cork.hop_limit; |
| 1576 | hdr->nexthdr = proto; | 1580 | hdr->nexthdr = proto; |
| 1577 | hdr->saddr = fl6->saddr; | 1581 | hdr->saddr = fl6->saddr; |
diff --git a/net/ipv6/ip6_tunnel.c b/net/ipv6/ip6_tunnel.c index afa082458360..f9de5a695072 100644 --- a/net/ipv6/ip6_tunnel.c +++ b/net/ipv6/ip6_tunnel.c | |||
| @@ -315,7 +315,8 @@ static struct ip6_tnl *ip6_tnl_create(struct net *net, struct __ip6_tnl_parm *p) | |||
| 315 | else | 315 | else |
| 316 | sprintf(name, "ip6tnl%%d"); | 316 | sprintf(name, "ip6tnl%%d"); |
| 317 | 317 | ||
| 318 | dev = alloc_netdev(sizeof (*t), name, ip6_tnl_dev_setup); | 318 | dev = alloc_netdev(sizeof(*t), name, NET_NAME_UNKNOWN, |
| 319 | ip6_tnl_dev_setup); | ||
| 319 | if (dev == NULL) | 320 | if (dev == NULL) |
| 320 | goto failed; | 321 | goto failed; |
| 321 | 322 | ||
| @@ -1046,7 +1047,8 @@ static int ip6_tnl_xmit2(struct sk_buff *skb, | |||
| 1046 | skb_push(skb, sizeof(struct ipv6hdr)); | 1047 | skb_push(skb, sizeof(struct ipv6hdr)); |
| 1047 | skb_reset_network_header(skb); | 1048 | skb_reset_network_header(skb); |
| 1048 | ipv6h = ipv6_hdr(skb); | 1049 | ipv6h = ipv6_hdr(skb); |
| 1049 | ip6_flow_hdr(ipv6h, INET_ECN_encapsulate(0, dsfield), fl6->flowlabel); | 1050 | ip6_flow_hdr(ipv6h, INET_ECN_encapsulate(0, dsfield), |
| 1051 | ip6_make_flowlabel(net, skb, fl6->flowlabel, false)); | ||
| 1050 | ipv6h->hop_limit = t->parms.hop_limit; | 1052 | ipv6h->hop_limit = t->parms.hop_limit; |
| 1051 | ipv6h->nexthdr = proto; | 1053 | ipv6h->nexthdr = proto; |
| 1052 | ipv6h->saddr = fl6->saddr; | 1054 | ipv6h->saddr = fl6->saddr; |
| @@ -1772,7 +1774,7 @@ static int __net_init ip6_tnl_init_net(struct net *net) | |||
| 1772 | 1774 | ||
| 1773 | err = -ENOMEM; | 1775 | err = -ENOMEM; |
| 1774 | ip6n->fb_tnl_dev = alloc_netdev(sizeof(struct ip6_tnl), "ip6tnl0", | 1776 | ip6n->fb_tnl_dev = alloc_netdev(sizeof(struct ip6_tnl), "ip6tnl0", |
| 1775 | ip6_tnl_dev_setup); | 1777 | NET_NAME_UNKNOWN, ip6_tnl_dev_setup); |
| 1776 | 1778 | ||
| 1777 | if (!ip6n->fb_tnl_dev) | 1779 | if (!ip6n->fb_tnl_dev) |
| 1778 | goto err_alloc_dev; | 1780 | goto err_alloc_dev; |
diff --git a/net/ipv6/ip6_vti.c b/net/ipv6/ip6_vti.c index 9aaa6bb229e4..7f52fd9fa7b0 100644 --- a/net/ipv6/ip6_vti.c +++ b/net/ipv6/ip6_vti.c | |||
| @@ -204,7 +204,7 @@ static struct ip6_tnl *vti6_tnl_create(struct net *net, struct __ip6_tnl_parm *p | |||
| 204 | else | 204 | else |
| 205 | sprintf(name, "ip6_vti%%d"); | 205 | sprintf(name, "ip6_vti%%d"); |
| 206 | 206 | ||
| 207 | dev = alloc_netdev(sizeof(*t), name, vti6_dev_setup); | 207 | dev = alloc_netdev(sizeof(*t), name, NET_NAME_UNKNOWN, vti6_dev_setup); |
| 208 | if (dev == NULL) | 208 | if (dev == NULL) |
| 209 | goto failed; | 209 | goto failed; |
| 210 | 210 | ||
| @@ -1020,7 +1020,7 @@ static int __net_init vti6_init_net(struct net *net) | |||
| 1020 | 1020 | ||
| 1021 | err = -ENOMEM; | 1021 | err = -ENOMEM; |
| 1022 | ip6n->fb_tnl_dev = alloc_netdev(sizeof(struct ip6_tnl), "ip6_vti0", | 1022 | ip6n->fb_tnl_dev = alloc_netdev(sizeof(struct ip6_tnl), "ip6_vti0", |
| 1023 | vti6_dev_setup); | 1023 | NET_NAME_UNKNOWN, vti6_dev_setup); |
| 1024 | 1024 | ||
| 1025 | if (!ip6n->fb_tnl_dev) | 1025 | if (!ip6n->fb_tnl_dev) |
| 1026 | goto err_alloc_dev; | 1026 | goto err_alloc_dev; |
| @@ -1089,36 +1089,26 @@ static struct xfrm6_protocol vti_ipcomp6_protocol __read_mostly = { | |||
| 1089 | **/ | 1089 | **/ |
| 1090 | static int __init vti6_tunnel_init(void) | 1090 | static int __init vti6_tunnel_init(void) |
| 1091 | { | 1091 | { |
| 1092 | int err; | 1092 | const char *msg; |
| 1093 | int err; | ||
| 1093 | 1094 | ||
| 1095 | msg = "tunnel device"; | ||
| 1094 | err = register_pernet_device(&vti6_net_ops); | 1096 | err = register_pernet_device(&vti6_net_ops); |
| 1095 | if (err < 0) | 1097 | if (err < 0) |
| 1096 | goto out_pernet; | 1098 | goto pernet_dev_failed; |
| 1097 | 1099 | ||
| 1100 | msg = "tunnel protocols"; | ||
| 1098 | err = xfrm6_protocol_register(&vti_esp6_protocol, IPPROTO_ESP); | 1101 | err = xfrm6_protocol_register(&vti_esp6_protocol, IPPROTO_ESP); |
| 1099 | if (err < 0) { | 1102 | if (err < 0) |
| 1100 | pr_err("%s: can't register vti6 protocol\n", __func__); | 1103 | goto xfrm_proto_esp_failed; |
| 1101 | |||
| 1102 | goto out; | ||
| 1103 | } | ||
| 1104 | |||
| 1105 | err = xfrm6_protocol_register(&vti_ah6_protocol, IPPROTO_AH); | 1104 | err = xfrm6_protocol_register(&vti_ah6_protocol, IPPROTO_AH); |
| 1106 | if (err < 0) { | 1105 | if (err < 0) |
| 1107 | xfrm6_protocol_deregister(&vti_esp6_protocol, IPPROTO_ESP); | 1106 | goto xfrm_proto_ah_failed; |
| 1108 | pr_err("%s: can't register vti6 protocol\n", __func__); | ||
| 1109 | |||
| 1110 | goto out; | ||
| 1111 | } | ||
| 1112 | |||
| 1113 | err = xfrm6_protocol_register(&vti_ipcomp6_protocol, IPPROTO_COMP); | 1107 | err = xfrm6_protocol_register(&vti_ipcomp6_protocol, IPPROTO_COMP); |
| 1114 | if (err < 0) { | 1108 | if (err < 0) |
| 1115 | xfrm6_protocol_deregister(&vti_ah6_protocol, IPPROTO_AH); | 1109 | goto xfrm_proto_comp_failed; |
| 1116 | xfrm6_protocol_deregister(&vti_esp6_protocol, IPPROTO_ESP); | ||
| 1117 | pr_err("%s: can't register vti6 protocol\n", __func__); | ||
| 1118 | |||
| 1119 | goto out; | ||
| 1120 | } | ||
| 1121 | 1110 | ||
| 1111 | msg = "netlink interface"; | ||
| 1122 | err = rtnl_link_register(&vti6_link_ops); | 1112 | err = rtnl_link_register(&vti6_link_ops); |
| 1123 | if (err < 0) | 1113 | if (err < 0) |
| 1124 | goto rtnl_link_failed; | 1114 | goto rtnl_link_failed; |
| @@ -1127,11 +1117,14 @@ static int __init vti6_tunnel_init(void) | |||
| 1127 | 1117 | ||
| 1128 | rtnl_link_failed: | 1118 | rtnl_link_failed: |
| 1129 | xfrm6_protocol_deregister(&vti_ipcomp6_protocol, IPPROTO_COMP); | 1119 | xfrm6_protocol_deregister(&vti_ipcomp6_protocol, IPPROTO_COMP); |
| 1120 | xfrm_proto_comp_failed: | ||
| 1130 | xfrm6_protocol_deregister(&vti_ah6_protocol, IPPROTO_AH); | 1121 | xfrm6_protocol_deregister(&vti_ah6_protocol, IPPROTO_AH); |
| 1122 | xfrm_proto_ah_failed: | ||
| 1131 | xfrm6_protocol_deregister(&vti_esp6_protocol, IPPROTO_ESP); | 1123 | xfrm6_protocol_deregister(&vti_esp6_protocol, IPPROTO_ESP); |
| 1132 | out: | 1124 | xfrm_proto_esp_failed: |
| 1133 | unregister_pernet_device(&vti6_net_ops); | 1125 | unregister_pernet_device(&vti6_net_ops); |
| 1134 | out_pernet: | 1126 | pernet_dev_failed: |
| 1127 | pr_err("vti6 init: failed to register %s\n", msg); | ||
| 1135 | return err; | 1128 | return err; |
| 1136 | } | 1129 | } |
| 1137 | 1130 | ||
| @@ -1141,13 +1134,9 @@ out_pernet: | |||
| 1141 | static void __exit vti6_tunnel_cleanup(void) | 1134 | static void __exit vti6_tunnel_cleanup(void) |
| 1142 | { | 1135 | { |
| 1143 | rtnl_link_unregister(&vti6_link_ops); | 1136 | rtnl_link_unregister(&vti6_link_ops); |
| 1144 | if (xfrm6_protocol_deregister(&vti_ipcomp6_protocol, IPPROTO_COMP)) | 1137 | xfrm6_protocol_deregister(&vti_ipcomp6_protocol, IPPROTO_COMP); |
| 1145 | pr_info("%s: can't deregister protocol\n", __func__); | 1138 | xfrm6_protocol_deregister(&vti_ah6_protocol, IPPROTO_AH); |
| 1146 | if (xfrm6_protocol_deregister(&vti_ah6_protocol, IPPROTO_AH)) | 1139 | xfrm6_protocol_deregister(&vti_esp6_protocol, IPPROTO_ESP); |
| 1147 | pr_info("%s: can't deregister protocol\n", __func__); | ||
| 1148 | if (xfrm6_protocol_deregister(&vti_esp6_protocol, IPPROTO_ESP)) | ||
| 1149 | pr_info("%s: can't deregister protocol\n", __func__); | ||
| 1150 | |||
| 1151 | unregister_pernet_device(&vti6_net_ops); | 1140 | unregister_pernet_device(&vti6_net_ops); |
| 1152 | } | 1141 | } |
| 1153 | 1142 | ||
diff --git a/net/ipv6/ip6mr.c b/net/ipv6/ip6mr.c index 8250474ab7dc..f9a3fd320d1d 100644 --- a/net/ipv6/ip6mr.c +++ b/net/ipv6/ip6mr.c | |||
| @@ -744,7 +744,7 @@ static struct net_device *ip6mr_reg_vif(struct net *net, struct mr6_table *mrt) | |||
| 744 | else | 744 | else |
| 745 | sprintf(name, "pim6reg%u", mrt->id); | 745 | sprintf(name, "pim6reg%u", mrt->id); |
| 746 | 746 | ||
| 747 | dev = alloc_netdev(0, name, reg_vif_setup); | 747 | dev = alloc_netdev(0, name, NET_NAME_UNKNOWN, reg_vif_setup); |
| 748 | if (dev == NULL) | 748 | if (dev == NULL) |
| 749 | return NULL; | 749 | return NULL; |
| 750 | 750 | ||
diff --git a/net/ipv6/ipv6_sockglue.c b/net/ipv6/ipv6_sockglue.c index edb58aff4ae7..0c289982796d 100644 --- a/net/ipv6/ipv6_sockglue.c +++ b/net/ipv6/ipv6_sockglue.c | |||
| @@ -235,7 +235,7 @@ static int do_ipv6_setsockopt(struct sock *sk, int level, int optname, | |||
| 235 | if (optlen < sizeof(int) || | 235 | if (optlen < sizeof(int) || |
| 236 | inet_sk(sk)->inet_num) | 236 | inet_sk(sk)->inet_num) |
| 237 | goto e_inval; | 237 | goto e_inval; |
| 238 | np->ipv6only = valbool; | 238 | sk->sk_ipv6only = valbool; |
| 239 | retv = 0; | 239 | retv = 0; |
| 240 | break; | 240 | break; |
| 241 | 241 | ||
| @@ -834,6 +834,10 @@ pref_skip_coa: | |||
| 834 | np->dontfrag = valbool; | 834 | np->dontfrag = valbool; |
| 835 | retv = 0; | 835 | retv = 0; |
| 836 | break; | 836 | break; |
| 837 | case IPV6_AUTOFLOWLABEL: | ||
| 838 | np->autoflowlabel = valbool; | ||
| 839 | retv = 0; | ||
| 840 | break; | ||
| 837 | } | 841 | } |
| 838 | 842 | ||
| 839 | release_sock(sk); | 843 | release_sock(sk); |
| @@ -1058,7 +1062,7 @@ static int do_ipv6_getsockopt(struct sock *sk, int level, int optname, | |||
| 1058 | } | 1062 | } |
| 1059 | 1063 | ||
| 1060 | case IPV6_V6ONLY: | 1064 | case IPV6_V6ONLY: |
| 1061 | val = np->ipv6only; | 1065 | val = sk->sk_ipv6only; |
| 1062 | break; | 1066 | break; |
| 1063 | 1067 | ||
| 1064 | case IPV6_RECVPKTINFO: | 1068 | case IPV6_RECVPKTINFO: |
| @@ -1158,7 +1162,6 @@ static int do_ipv6_getsockopt(struct sock *sk, int level, int optname, | |||
| 1158 | return -EFAULT; | 1162 | return -EFAULT; |
| 1159 | 1163 | ||
| 1160 | return 0; | 1164 | return 0; |
| 1161 | break; | ||
| 1162 | } | 1165 | } |
| 1163 | 1166 | ||
| 1164 | case IPV6_TRANSPARENT: | 1167 | case IPV6_TRANSPARENT: |
| @@ -1273,6 +1276,10 @@ static int do_ipv6_getsockopt(struct sock *sk, int level, int optname, | |||
| 1273 | val = np->dontfrag; | 1276 | val = np->dontfrag; |
| 1274 | break; | 1277 | break; |
| 1275 | 1278 | ||
| 1279 | case IPV6_AUTOFLOWLABEL: | ||
| 1280 | val = np->autoflowlabel; | ||
| 1281 | break; | ||
| 1282 | |||
| 1276 | default: | 1283 | default: |
| 1277 | return -ENOPROTOOPT; | 1284 | return -ENOPROTOOPT; |
| 1278 | } | 1285 | } |
diff --git a/net/ipv6/ndisc.c b/net/ipv6/ndisc.c index ca8d4ea48a5d..339078f95d1b 100644 --- a/net/ipv6/ndisc.c +++ b/net/ipv6/ndisc.c | |||
| @@ -1070,6 +1070,9 @@ static void ndisc_router_discovery(struct sk_buff *skb) | |||
| 1070 | optlen = (skb_tail_pointer(skb) - skb_transport_header(skb)) - | 1070 | optlen = (skb_tail_pointer(skb) - skb_transport_header(skb)) - |
| 1071 | sizeof(struct ra_msg); | 1071 | sizeof(struct ra_msg); |
| 1072 | 1072 | ||
| 1073 | ND_PRINTK(2, info, | ||
| 1074 | "RA: %s, dev: %s\n", | ||
| 1075 | __func__, skb->dev->name); | ||
| 1073 | if (!(ipv6_addr_type(&ipv6_hdr(skb)->saddr) & IPV6_ADDR_LINKLOCAL)) { | 1076 | if (!(ipv6_addr_type(&ipv6_hdr(skb)->saddr) & IPV6_ADDR_LINKLOCAL)) { |
| 1074 | ND_PRINTK(2, warn, "RA: source address is not link-local\n"); | 1077 | ND_PRINTK(2, warn, "RA: source address is not link-local\n"); |
| 1075 | return; | 1078 | return; |
| @@ -1102,13 +1105,21 @@ static void ndisc_router_discovery(struct sk_buff *skb) | |||
| 1102 | return; | 1105 | return; |
| 1103 | } | 1106 | } |
| 1104 | 1107 | ||
| 1105 | if (!ipv6_accept_ra(in6_dev)) | 1108 | if (!ipv6_accept_ra(in6_dev)) { |
| 1109 | ND_PRINTK(2, info, | ||
| 1110 | "RA: %s, did not accept ra for dev: %s\n", | ||
| 1111 | __func__, skb->dev->name); | ||
| 1106 | goto skip_linkparms; | 1112 | goto skip_linkparms; |
| 1113 | } | ||
| 1107 | 1114 | ||
| 1108 | #ifdef CONFIG_IPV6_NDISC_NODETYPE | 1115 | #ifdef CONFIG_IPV6_NDISC_NODETYPE |
| 1109 | /* skip link-specific parameters from interior routers */ | 1116 | /* skip link-specific parameters from interior routers */ |
| 1110 | if (skb->ndisc_nodetype == NDISC_NODETYPE_NODEFAULT) | 1117 | if (skb->ndisc_nodetype == NDISC_NODETYPE_NODEFAULT) { |
| 1118 | ND_PRINTK(2, info, | ||
| 1119 | "RA: %s, nodetype is NODEFAULT, dev: %s\n", | ||
| 1120 | __func__, skb->dev->name); | ||
| 1111 | goto skip_linkparms; | 1121 | goto skip_linkparms; |
| 1122 | } | ||
| 1112 | #endif | 1123 | #endif |
| 1113 | 1124 | ||
| 1114 | if (in6_dev->if_flags & IF_RS_SENT) { | 1125 | if (in6_dev->if_flags & IF_RS_SENT) { |
| @@ -1130,11 +1141,24 @@ static void ndisc_router_discovery(struct sk_buff *skb) | |||
| 1130 | (ra_msg->icmph.icmp6_addrconf_other ? | 1141 | (ra_msg->icmph.icmp6_addrconf_other ? |
| 1131 | IF_RA_OTHERCONF : 0); | 1142 | IF_RA_OTHERCONF : 0); |
| 1132 | 1143 | ||
| 1133 | if (!in6_dev->cnf.accept_ra_defrtr) | 1144 | if (!in6_dev->cnf.accept_ra_defrtr) { |
| 1145 | ND_PRINTK(2, info, | ||
| 1146 | "RA: %s, defrtr is false for dev: %s\n", | ||
| 1147 | __func__, skb->dev->name); | ||
| 1134 | goto skip_defrtr; | 1148 | goto skip_defrtr; |
| 1149 | } | ||
| 1135 | 1150 | ||
| 1136 | if (ipv6_chk_addr(dev_net(in6_dev->dev), &ipv6_hdr(skb)->saddr, NULL, 0)) | 1151 | /* Do not accept RA with source-addr found on local machine unless |
| 1152 | * accept_ra_from_local is set to true. | ||
| 1153 | */ | ||
| 1154 | if (!in6_dev->cnf.accept_ra_from_local && | ||
| 1155 | ipv6_chk_addr(dev_net(in6_dev->dev), &ipv6_hdr(skb)->saddr, | ||
| 1156 | NULL, 0)) { | ||
| 1157 | ND_PRINTK(2, info, | ||
| 1158 | "RA from local address detected on dev: %s: default router ignored\n", | ||
| 1159 | skb->dev->name); | ||
| 1137 | goto skip_defrtr; | 1160 | goto skip_defrtr; |
| 1161 | } | ||
| 1138 | 1162 | ||
| 1139 | lifetime = ntohs(ra_msg->icmph.icmp6_rt_lifetime); | 1163 | lifetime = ntohs(ra_msg->icmph.icmp6_rt_lifetime); |
| 1140 | 1164 | ||
| @@ -1163,8 +1187,10 @@ static void ndisc_router_discovery(struct sk_buff *skb) | |||
| 1163 | rt = NULL; | 1187 | rt = NULL; |
| 1164 | } | 1188 | } |
| 1165 | 1189 | ||
| 1190 | ND_PRINTK(3, info, "RA: rt: %p lifetime: %d, for dev: %s\n", | ||
| 1191 | rt, lifetime, skb->dev->name); | ||
| 1166 | if (rt == NULL && lifetime) { | 1192 | if (rt == NULL && lifetime) { |
| 1167 | ND_PRINTK(3, dbg, "RA: adding default router\n"); | 1193 | ND_PRINTK(3, info, "RA: adding default router\n"); |
| 1168 | 1194 | ||
| 1169 | rt = rt6_add_dflt_router(&ipv6_hdr(skb)->saddr, skb->dev, pref); | 1195 | rt = rt6_add_dflt_router(&ipv6_hdr(skb)->saddr, skb->dev, pref); |
| 1170 | if (rt == NULL) { | 1196 | if (rt == NULL) { |
| @@ -1260,12 +1286,22 @@ skip_linkparms: | |||
| 1260 | NEIGH_UPDATE_F_ISROUTER); | 1286 | NEIGH_UPDATE_F_ISROUTER); |
| 1261 | } | 1287 | } |
| 1262 | 1288 | ||
| 1263 | if (!ipv6_accept_ra(in6_dev)) | 1289 | if (!ipv6_accept_ra(in6_dev)) { |
| 1290 | ND_PRINTK(2, info, | ||
| 1291 | "RA: %s, accept_ra is false for dev: %s\n", | ||
| 1292 | __func__, skb->dev->name); | ||
| 1264 | goto out; | 1293 | goto out; |
| 1294 | } | ||
| 1265 | 1295 | ||
| 1266 | #ifdef CONFIG_IPV6_ROUTE_INFO | 1296 | #ifdef CONFIG_IPV6_ROUTE_INFO |
| 1267 | if (ipv6_chk_addr(dev_net(in6_dev->dev), &ipv6_hdr(skb)->saddr, NULL, 0)) | 1297 | if (!in6_dev->cnf.accept_ra_from_local && |
| 1298 | ipv6_chk_addr(dev_net(in6_dev->dev), &ipv6_hdr(skb)->saddr, | ||
| 1299 | NULL, 0)) { | ||
| 1300 | ND_PRINTK(2, info, | ||
| 1301 | "RA from local address detected on dev: %s: router info ignored.\n", | ||
| 1302 | skb->dev->name); | ||
| 1268 | goto skip_routeinfo; | 1303 | goto skip_routeinfo; |
| 1304 | } | ||
| 1269 | 1305 | ||
| 1270 | if (in6_dev->cnf.accept_ra_rtr_pref && ndopts.nd_opts_ri) { | 1306 | if (in6_dev->cnf.accept_ra_rtr_pref && ndopts.nd_opts_ri) { |
| 1271 | struct nd_opt_hdr *p; | 1307 | struct nd_opt_hdr *p; |
| @@ -1293,8 +1329,12 @@ skip_routeinfo: | |||
| 1293 | 1329 | ||
| 1294 | #ifdef CONFIG_IPV6_NDISC_NODETYPE | 1330 | #ifdef CONFIG_IPV6_NDISC_NODETYPE |
| 1295 | /* skip link-specific ndopts from interior routers */ | 1331 | /* skip link-specific ndopts from interior routers */ |
| 1296 | if (skb->ndisc_nodetype == NDISC_NODETYPE_NODEFAULT) | 1332 | if (skb->ndisc_nodetype == NDISC_NODETYPE_NODEFAULT) { |
| 1333 | ND_PRINTK(2, info, | ||
| 1334 | "RA: %s, nodetype is NODEFAULT (interior routes), dev: %s\n", | ||
| 1335 | __func__, skb->dev->name); | ||
| 1297 | goto out; | 1336 | goto out; |
| 1337 | } | ||
| 1298 | #endif | 1338 | #endif |
| 1299 | 1339 | ||
| 1300 | if (in6_dev->cnf.accept_ra_pinfo && ndopts.nd_opts_pi) { | 1340 | if (in6_dev->cnf.accept_ra_pinfo && ndopts.nd_opts_pi) { |
| @@ -1728,7 +1768,7 @@ int __init ndisc_init(void) | |||
| 1728 | 1768 | ||
| 1729 | #ifdef CONFIG_SYSCTL | 1769 | #ifdef CONFIG_SYSCTL |
| 1730 | err = neigh_sysctl_register(NULL, &nd_tbl.parms, | 1770 | err = neigh_sysctl_register(NULL, &nd_tbl.parms, |
| 1731 | &ndisc_ifinfo_sysctl_change); | 1771 | ndisc_ifinfo_sysctl_change); |
| 1732 | if (err) | 1772 | if (err) |
| 1733 | goto out_unregister_pernet; | 1773 | goto out_unregister_pernet; |
| 1734 | out: | 1774 | out: |
diff --git a/net/ipv6/netfilter/Kconfig b/net/ipv6/netfilter/Kconfig index 4bff1f297e39..ac93df16f5af 100644 --- a/net/ipv6/netfilter/Kconfig +++ b/net/ipv6/netfilter/Kconfig | |||
| @@ -55,6 +55,11 @@ config NFT_REJECT_IPV6 | |||
| 55 | default NFT_REJECT | 55 | default NFT_REJECT |
| 56 | tristate | 56 | tristate |
| 57 | 57 | ||
| 58 | config NF_LOG_IPV6 | ||
| 59 | tristate "IPv6 packet logging" | ||
| 60 | depends on NETFILTER_ADVANCED | ||
| 61 | select NF_LOG_COMMON | ||
| 62 | |||
| 58 | config IP6_NF_IPTABLES | 63 | config IP6_NF_IPTABLES |
| 59 | tristate "IP6 tables support (required for filtering)" | 64 | tristate "IP6 tables support (required for filtering)" |
| 60 | depends on INET && IPV6 | 65 | depends on INET && IPV6 |
diff --git a/net/ipv6/netfilter/Makefile b/net/ipv6/netfilter/Makefile index 70d3dd66f2cd..c0b263104ed2 100644 --- a/net/ipv6/netfilter/Makefile +++ b/net/ipv6/netfilter/Makefile | |||
| @@ -23,6 +23,9 @@ obj-$(CONFIG_NF_NAT_IPV6) += nf_nat_ipv6.o | |||
| 23 | nf_defrag_ipv6-y := nf_defrag_ipv6_hooks.o nf_conntrack_reasm.o | 23 | nf_defrag_ipv6-y := nf_defrag_ipv6_hooks.o nf_conntrack_reasm.o |
| 24 | obj-$(CONFIG_NF_DEFRAG_IPV6) += nf_defrag_ipv6.o | 24 | obj-$(CONFIG_NF_DEFRAG_IPV6) += nf_defrag_ipv6.o |
| 25 | 25 | ||
| 26 | # logging | ||
| 27 | obj-$(CONFIG_NF_LOG_IPV6) += nf_log_ipv6.o | ||
| 28 | |||
| 26 | # nf_tables | 29 | # nf_tables |
| 27 | obj-$(CONFIG_NF_TABLES_IPV6) += nf_tables_ipv6.o | 30 | obj-$(CONFIG_NF_TABLES_IPV6) += nf_tables_ipv6.o |
| 28 | obj-$(CONFIG_NFT_CHAIN_ROUTE_IPV6) += nft_chain_route_ipv6.o | 31 | obj-$(CONFIG_NFT_CHAIN_ROUTE_IPV6) += nft_chain_route_ipv6.o |
diff --git a/net/ipv6/netfilter/ip6t_ipv6header.c b/net/ipv6/netfilter/ip6t_ipv6header.c index 54bd9790603f..8b147440fbdc 100644 --- a/net/ipv6/netfilter/ip6t_ipv6header.c +++ b/net/ipv6/netfilter/ip6t_ipv6header.c | |||
| @@ -94,7 +94,6 @@ ipv6header_mt6(const struct sk_buff *skb, struct xt_action_param *par) | |||
| 94 | break; | 94 | break; |
| 95 | default: | 95 | default: |
| 96 | return false; | 96 | return false; |
| 97 | break; | ||
| 98 | } | 97 | } |
| 99 | 98 | ||
| 100 | nexthdr = hp->nexthdr; | 99 | nexthdr = hp->nexthdr; |
diff --git a/net/ipv6/netfilter/nf_conntrack_reasm.c b/net/ipv6/netfilter/nf_conntrack_reasm.c index 0d5279fd852a..6f187c8d8a1b 100644 --- a/net/ipv6/netfilter/nf_conntrack_reasm.c +++ b/net/ipv6/netfilter/nf_conntrack_reasm.c | |||
| @@ -50,6 +50,7 @@ | |||
| 50 | #include <linux/module.h> | 50 | #include <linux/module.h> |
| 51 | #include <net/netfilter/ipv6/nf_defrag_ipv6.h> | 51 | #include <net/netfilter/ipv6/nf_defrag_ipv6.h> |
| 52 | 52 | ||
| 53 | static const char nf_frags_cache_name[] = "nf-frags"; | ||
| 53 | 54 | ||
| 54 | struct nf_ct_frag6_skb_cb | 55 | struct nf_ct_frag6_skb_cb |
| 55 | { | 56 | { |
| @@ -63,6 +64,8 @@ struct nf_ct_frag6_skb_cb | |||
| 63 | static struct inet_frags nf_frags; | 64 | static struct inet_frags nf_frags; |
| 64 | 65 | ||
| 65 | #ifdef CONFIG_SYSCTL | 66 | #ifdef CONFIG_SYSCTL |
| 67 | static int zero; | ||
| 68 | |||
| 66 | static struct ctl_table nf_ct_frag6_sysctl_table[] = { | 69 | static struct ctl_table nf_ct_frag6_sysctl_table[] = { |
| 67 | { | 70 | { |
| 68 | .procname = "nf_conntrack_frag6_timeout", | 71 | .procname = "nf_conntrack_frag6_timeout", |
| @@ -76,14 +79,17 @@ static struct ctl_table nf_ct_frag6_sysctl_table[] = { | |||
| 76 | .data = &init_net.nf_frag.frags.low_thresh, | 79 | .data = &init_net.nf_frag.frags.low_thresh, |
| 77 | .maxlen = sizeof(unsigned int), | 80 | .maxlen = sizeof(unsigned int), |
| 78 | .mode = 0644, | 81 | .mode = 0644, |
| 79 | .proc_handler = proc_dointvec, | 82 | .proc_handler = proc_dointvec_minmax, |
| 83 | .extra1 = &zero, | ||
| 84 | .extra2 = &init_net.nf_frag.frags.high_thresh | ||
| 80 | }, | 85 | }, |
| 81 | { | 86 | { |
| 82 | .procname = "nf_conntrack_frag6_high_thresh", | 87 | .procname = "nf_conntrack_frag6_high_thresh", |
| 83 | .data = &init_net.nf_frag.frags.high_thresh, | 88 | .data = &init_net.nf_frag.frags.high_thresh, |
| 84 | .maxlen = sizeof(unsigned int), | 89 | .maxlen = sizeof(unsigned int), |
| 85 | .mode = 0644, | 90 | .mode = 0644, |
| 86 | .proc_handler = proc_dointvec, | 91 | .proc_handler = proc_dointvec_minmax, |
| 92 | .extra1 = &init_net.nf_frag.frags.low_thresh | ||
| 87 | }, | 93 | }, |
| 88 | { } | 94 | { } |
| 89 | }; | 95 | }; |
| @@ -102,7 +108,10 @@ static int nf_ct_frag6_sysctl_register(struct net *net) | |||
| 102 | 108 | ||
| 103 | table[0].data = &net->nf_frag.frags.timeout; | 109 | table[0].data = &net->nf_frag.frags.timeout; |
| 104 | table[1].data = &net->nf_frag.frags.low_thresh; | 110 | table[1].data = &net->nf_frag.frags.low_thresh; |
| 111 | table[1].extra2 = &net->nf_frag.frags.high_thresh; | ||
| 105 | table[2].data = &net->nf_frag.frags.high_thresh; | 112 | table[2].data = &net->nf_frag.frags.high_thresh; |
| 113 | table[2].extra1 = &net->nf_frag.frags.low_thresh; | ||
| 114 | table[2].extra2 = &init_net.nf_frag.frags.high_thresh; | ||
| 106 | } | 115 | } |
| 107 | 116 | ||
| 108 | hdr = register_net_sysctl(net, "net/netfilter", table); | 117 | hdr = register_net_sysctl(net, "net/netfilter", table); |
| @@ -147,16 +156,13 @@ static inline u8 ip6_frag_ecn(const struct ipv6hdr *ipv6h) | |||
| 147 | static unsigned int nf_hash_frag(__be32 id, const struct in6_addr *saddr, | 156 | static unsigned int nf_hash_frag(__be32 id, const struct in6_addr *saddr, |
| 148 | const struct in6_addr *daddr) | 157 | const struct in6_addr *daddr) |
| 149 | { | 158 | { |
| 150 | u32 c; | ||
| 151 | |||
| 152 | net_get_random_once(&nf_frags.rnd, sizeof(nf_frags.rnd)); | 159 | net_get_random_once(&nf_frags.rnd, sizeof(nf_frags.rnd)); |
| 153 | c = jhash_3words(ipv6_addr_hash(saddr), ipv6_addr_hash(daddr), | 160 | return jhash_3words(ipv6_addr_hash(saddr), ipv6_addr_hash(daddr), |
| 154 | (__force u32)id, nf_frags.rnd); | 161 | (__force u32)id, nf_frags.rnd); |
| 155 | return c & (INETFRAGS_HASHSZ - 1); | ||
| 156 | } | 162 | } |
| 157 | 163 | ||
| 158 | 164 | ||
| 159 | static unsigned int nf_hashfn(struct inet_frag_queue *q) | 165 | static unsigned int nf_hashfn(const struct inet_frag_queue *q) |
| 160 | { | 166 | { |
| 161 | const struct frag_queue *nq; | 167 | const struct frag_queue *nq; |
| 162 | 168 | ||
| @@ -196,7 +202,7 @@ static inline struct frag_queue *fq_find(struct net *net, __be32 id, | |||
| 196 | arg.dst = dst; | 202 | arg.dst = dst; |
| 197 | arg.ecn = ecn; | 203 | arg.ecn = ecn; |
| 198 | 204 | ||
| 199 | read_lock_bh(&nf_frags.lock); | 205 | local_bh_disable(); |
| 200 | hash = nf_hash_frag(id, src, dst); | 206 | hash = nf_hash_frag(id, src, dst); |
| 201 | 207 | ||
| 202 | q = inet_frag_find(&net->nf_frag.frags, &nf_frags, &arg, hash); | 208 | q = inet_frag_find(&net->nf_frag.frags, &nf_frags, &arg, hash); |
| @@ -217,7 +223,7 @@ static int nf_ct_frag6_queue(struct frag_queue *fq, struct sk_buff *skb, | |||
| 217 | int offset, end; | 223 | int offset, end; |
| 218 | u8 ecn; | 224 | u8 ecn; |
| 219 | 225 | ||
| 220 | if (fq->q.last_in & INET_FRAG_COMPLETE) { | 226 | if (fq->q.flags & INET_FRAG_COMPLETE) { |
| 221 | pr_debug("Already completed\n"); | 227 | pr_debug("Already completed\n"); |
| 222 | goto err; | 228 | goto err; |
| 223 | } | 229 | } |
| @@ -248,11 +254,11 @@ static int nf_ct_frag6_queue(struct frag_queue *fq, struct sk_buff *skb, | |||
| 248 | * or have different end, the segment is corrupted. | 254 | * or have different end, the segment is corrupted. |
| 249 | */ | 255 | */ |
| 250 | if (end < fq->q.len || | 256 | if (end < fq->q.len || |
| 251 | ((fq->q.last_in & INET_FRAG_LAST_IN) && end != fq->q.len)) { | 257 | ((fq->q.flags & INET_FRAG_LAST_IN) && end != fq->q.len)) { |
| 252 | pr_debug("already received last fragment\n"); | 258 | pr_debug("already received last fragment\n"); |
| 253 | goto err; | 259 | goto err; |
| 254 | } | 260 | } |
| 255 | fq->q.last_in |= INET_FRAG_LAST_IN; | 261 | fq->q.flags |= INET_FRAG_LAST_IN; |
| 256 | fq->q.len = end; | 262 | fq->q.len = end; |
| 257 | } else { | 263 | } else { |
| 258 | /* Check if the fragment is rounded to 8 bytes. | 264 | /* Check if the fragment is rounded to 8 bytes. |
| @@ -267,7 +273,7 @@ static int nf_ct_frag6_queue(struct frag_queue *fq, struct sk_buff *skb, | |||
| 267 | } | 273 | } |
| 268 | if (end > fq->q.len) { | 274 | if (end > fq->q.len) { |
| 269 | /* Some bits beyond end -> corruption. */ | 275 | /* Some bits beyond end -> corruption. */ |
| 270 | if (fq->q.last_in & INET_FRAG_LAST_IN) { | 276 | if (fq->q.flags & INET_FRAG_LAST_IN) { |
| 271 | pr_debug("last packet already reached.\n"); | 277 | pr_debug("last packet already reached.\n"); |
| 272 | goto err; | 278 | goto err; |
| 273 | } | 279 | } |
| @@ -349,10 +355,9 @@ found: | |||
| 349 | */ | 355 | */ |
| 350 | if (offset == 0) { | 356 | if (offset == 0) { |
| 351 | fq->nhoffset = nhoff; | 357 | fq->nhoffset = nhoff; |
| 352 | fq->q.last_in |= INET_FRAG_FIRST_IN; | 358 | fq->q.flags |= INET_FRAG_FIRST_IN; |
| 353 | } | 359 | } |
| 354 | 360 | ||
| 355 | inet_frag_lru_move(&fq->q); | ||
| 356 | return 0; | 361 | return 0; |
| 357 | 362 | ||
| 358 | discard_fq: | 363 | discard_fq: |
| @@ -597,10 +602,6 @@ struct sk_buff *nf_ct_frag6_gather(struct sk_buff *skb, u32 user) | |||
| 597 | hdr = ipv6_hdr(clone); | 602 | hdr = ipv6_hdr(clone); |
| 598 | fhdr = (struct frag_hdr *)skb_transport_header(clone); | 603 | fhdr = (struct frag_hdr *)skb_transport_header(clone); |
| 599 | 604 | ||
| 600 | local_bh_disable(); | ||
| 601 | inet_frag_evictor(&net->nf_frag.frags, &nf_frags, false); | ||
| 602 | local_bh_enable(); | ||
| 603 | |||
| 604 | fq = fq_find(net, fhdr->identification, user, &hdr->saddr, &hdr->daddr, | 605 | fq = fq_find(net, fhdr->identification, user, &hdr->saddr, &hdr->daddr, |
| 605 | ip6_frag_ecn(hdr)); | 606 | ip6_frag_ecn(hdr)); |
| 606 | if (fq == NULL) { | 607 | if (fq == NULL) { |
| @@ -617,7 +618,7 @@ struct sk_buff *nf_ct_frag6_gather(struct sk_buff *skb, u32 user) | |||
| 617 | goto ret_orig; | 618 | goto ret_orig; |
| 618 | } | 619 | } |
| 619 | 620 | ||
| 620 | if (fq->q.last_in == (INET_FRAG_FIRST_IN | INET_FRAG_LAST_IN) && | 621 | if (fq->q.flags == (INET_FRAG_FIRST_IN | INET_FRAG_LAST_IN) && |
| 621 | fq->q.meat == fq->q.len) { | 622 | fq->q.meat == fq->q.len) { |
| 622 | ret_skb = nf_ct_frag6_reasm(fq, dev); | 623 | ret_skb = nf_ct_frag6_reasm(fq, dev); |
| 623 | if (ret_skb == NULL) | 624 | if (ret_skb == NULL) |
| @@ -677,13 +678,15 @@ int nf_ct_frag6_init(void) | |||
| 677 | nf_frags.qsize = sizeof(struct frag_queue); | 678 | nf_frags.qsize = sizeof(struct frag_queue); |
| 678 | nf_frags.match = ip6_frag_match; | 679 | nf_frags.match = ip6_frag_match; |
| 679 | nf_frags.frag_expire = nf_ct_frag6_expire; | 680 | nf_frags.frag_expire = nf_ct_frag6_expire; |
| 680 | nf_frags.secret_interval = 10 * 60 * HZ; | 681 | nf_frags.frags_cache_name = nf_frags_cache_name; |
| 681 | inet_frags_init(&nf_frags); | 682 | ret = inet_frags_init(&nf_frags); |
| 682 | 683 | if (ret) | |
| 684 | goto out; | ||
| 683 | ret = register_pernet_subsys(&nf_ct_net_ops); | 685 | ret = register_pernet_subsys(&nf_ct_net_ops); |
| 684 | if (ret) | 686 | if (ret) |
| 685 | inet_frags_fini(&nf_frags); | 687 | inet_frags_fini(&nf_frags); |
| 686 | 688 | ||
| 689 | out: | ||
| 687 | return ret; | 690 | return ret; |
| 688 | } | 691 | } |
| 689 | 692 | ||
diff --git a/net/ipv6/netfilter/nf_log_ipv6.c b/net/ipv6/netfilter/nf_log_ipv6.c new file mode 100644 index 000000000000..7b17a0be93e7 --- /dev/null +++ b/net/ipv6/netfilter/nf_log_ipv6.c | |||
| @@ -0,0 +1,417 @@ | |||
| 1 | /* (C) 1999-2001 Paul `Rusty' Russell | ||
| 2 | * (C) 2002-2004 Netfilter Core Team <coreteam@netfilter.org> | ||
| 3 | * | ||
| 4 | * This program is free software; you can redistribute it and/or modify | ||
| 5 | * it under the terms of the GNU General Public License version 2 as | ||
| 6 | * published by the Free Software Foundation. | ||
| 7 | */ | ||
| 8 | |||
| 9 | #include <linux/module.h> | ||
| 10 | #include <linux/spinlock.h> | ||
| 11 | #include <linux/skbuff.h> | ||
| 12 | #include <linux/if_arp.h> | ||
| 13 | #include <linux/ip.h> | ||
| 14 | #include <net/ipv6.h> | ||
| 15 | #include <net/icmp.h> | ||
| 16 | #include <net/udp.h> | ||
| 17 | #include <net/tcp.h> | ||
| 18 | #include <net/route.h> | ||
| 19 | |||
| 20 | #include <linux/netfilter.h> | ||
| 21 | #include <linux/netfilter_ipv6/ip6_tables.h> | ||
| 22 | #include <linux/netfilter/xt_LOG.h> | ||
| 23 | #include <net/netfilter/nf_log.h> | ||
| 24 | |||
| 25 | static struct nf_loginfo default_loginfo = { | ||
| 26 | .type = NF_LOG_TYPE_LOG, | ||
| 27 | .u = { | ||
| 28 | .log = { | ||
| 29 | .level = 5, | ||
| 30 | .logflags = NF_LOG_MASK, | ||
| 31 | }, | ||
| 32 | }, | ||
| 33 | }; | ||
| 34 | |||
| 35 | /* One level of recursion won't kill us */ | ||
| 36 | static void dump_ipv6_packet(struct nf_log_buf *m, | ||
| 37 | const struct nf_loginfo *info, | ||
| 38 | const struct sk_buff *skb, unsigned int ip6hoff, | ||
| 39 | int recurse) | ||
| 40 | { | ||
| 41 | u_int8_t currenthdr; | ||
| 42 | int fragment; | ||
| 43 | struct ipv6hdr _ip6h; | ||
| 44 | const struct ipv6hdr *ih; | ||
| 45 | unsigned int ptr; | ||
| 46 | unsigned int hdrlen = 0; | ||
| 47 | unsigned int logflags; | ||
| 48 | |||
| 49 | if (info->type == NF_LOG_TYPE_LOG) | ||
| 50 | logflags = info->u.log.logflags; | ||
| 51 | else | ||
| 52 | logflags = NF_LOG_MASK; | ||
| 53 | |||
| 54 | ih = skb_header_pointer(skb, ip6hoff, sizeof(_ip6h), &_ip6h); | ||
| 55 | if (ih == NULL) { | ||
| 56 | nf_log_buf_add(m, "TRUNCATED"); | ||
| 57 | return; | ||
| 58 | } | ||
| 59 | |||
| 60 | /* Max length: 88 "SRC=0000.0000.0000.0000.0000.0000.0000.0000 DST=0000.0000.0000.0000.0000.0000.0000.0000 " */ | ||
| 61 | nf_log_buf_add(m, "SRC=%pI6 DST=%pI6 ", &ih->saddr, &ih->daddr); | ||
| 62 | |||
| 63 | /* Max length: 44 "LEN=65535 TC=255 HOPLIMIT=255 FLOWLBL=FFFFF " */ | ||
| 64 | nf_log_buf_add(m, "LEN=%Zu TC=%u HOPLIMIT=%u FLOWLBL=%u ", | ||
| 65 | ntohs(ih->payload_len) + sizeof(struct ipv6hdr), | ||
| 66 | (ntohl(*(__be32 *)ih) & 0x0ff00000) >> 20, | ||
| 67 | ih->hop_limit, | ||
| 68 | (ntohl(*(__be32 *)ih) & 0x000fffff)); | ||
| 69 | |||
| 70 | fragment = 0; | ||
| 71 | ptr = ip6hoff + sizeof(struct ipv6hdr); | ||
| 72 | currenthdr = ih->nexthdr; | ||
| 73 | while (currenthdr != NEXTHDR_NONE && ip6t_ext_hdr(currenthdr)) { | ||
| 74 | struct ipv6_opt_hdr _hdr; | ||
| 75 | const struct ipv6_opt_hdr *hp; | ||
| 76 | |||
| 77 | hp = skb_header_pointer(skb, ptr, sizeof(_hdr), &_hdr); | ||
| 78 | if (hp == NULL) { | ||
| 79 | nf_log_buf_add(m, "TRUNCATED"); | ||
| 80 | return; | ||
| 81 | } | ||
| 82 | |||
| 83 | /* Max length: 48 "OPT (...) " */ | ||
| 84 | if (logflags & XT_LOG_IPOPT) | ||
| 85 | nf_log_buf_add(m, "OPT ( "); | ||
| 86 | |||
| 87 | switch (currenthdr) { | ||
| 88 | case IPPROTO_FRAGMENT: { | ||
| 89 | struct frag_hdr _fhdr; | ||
| 90 | const struct frag_hdr *fh; | ||
| 91 | |||
| 92 | nf_log_buf_add(m, "FRAG:"); | ||
| 93 | fh = skb_header_pointer(skb, ptr, sizeof(_fhdr), | ||
| 94 | &_fhdr); | ||
| 95 | if (fh == NULL) { | ||
| 96 | nf_log_buf_add(m, "TRUNCATED "); | ||
| 97 | return; | ||
| 98 | } | ||
| 99 | |||
| 100 | /* Max length: 6 "65535 " */ | ||
| 101 | nf_log_buf_add(m, "%u ", ntohs(fh->frag_off) & 0xFFF8); | ||
| 102 | |||
| 103 | /* Max length: 11 "INCOMPLETE " */ | ||
| 104 | if (fh->frag_off & htons(0x0001)) | ||
| 105 | nf_log_buf_add(m, "INCOMPLETE "); | ||
| 106 | |||
| 107 | nf_log_buf_add(m, "ID:%08x ", | ||
| 108 | ntohl(fh->identification)); | ||
| 109 | |||
| 110 | if (ntohs(fh->frag_off) & 0xFFF8) | ||
| 111 | fragment = 1; | ||
| 112 | |||
| 113 | hdrlen = 8; | ||
| 114 | |||
| 115 | break; | ||
| 116 | } | ||
| 117 | case IPPROTO_DSTOPTS: | ||
| 118 | case IPPROTO_ROUTING: | ||
| 119 | case IPPROTO_HOPOPTS: | ||
| 120 | if (fragment) { | ||
| 121 | if (logflags & XT_LOG_IPOPT) | ||
| 122 | nf_log_buf_add(m, ")"); | ||
| 123 | return; | ||
| 124 | } | ||
| 125 | hdrlen = ipv6_optlen(hp); | ||
| 126 | break; | ||
| 127 | /* Max Length */ | ||
| 128 | case IPPROTO_AH: | ||
| 129 | if (logflags & XT_LOG_IPOPT) { | ||
| 130 | struct ip_auth_hdr _ahdr; | ||
| 131 | const struct ip_auth_hdr *ah; | ||
| 132 | |||
| 133 | /* Max length: 3 "AH " */ | ||
| 134 | nf_log_buf_add(m, "AH "); | ||
| 135 | |||
| 136 | if (fragment) { | ||
| 137 | nf_log_buf_add(m, ")"); | ||
| 138 | return; | ||
| 139 | } | ||
| 140 | |||
| 141 | ah = skb_header_pointer(skb, ptr, sizeof(_ahdr), | ||
| 142 | &_ahdr); | ||
| 143 | if (ah == NULL) { | ||
| 144 | /* | ||
| 145 | * Max length: 26 "INCOMPLETE [65535 | ||
| 146 | * bytes] )" | ||
| 147 | */ | ||
| 148 | nf_log_buf_add(m, "INCOMPLETE [%u bytes] )", | ||
| 149 | skb->len - ptr); | ||
| 150 | return; | ||
| 151 | } | ||
| 152 | |||
| 153 | /* Length: 15 "SPI=0xF1234567 */ | ||
| 154 | nf_log_buf_add(m, "SPI=0x%x ", ntohl(ah->spi)); | ||
| 155 | |||
| 156 | } | ||
| 157 | |||
| 158 | hdrlen = (hp->hdrlen+2)<<2; | ||
| 159 | break; | ||
| 160 | case IPPROTO_ESP: | ||
| 161 | if (logflags & XT_LOG_IPOPT) { | ||
| 162 | struct ip_esp_hdr _esph; | ||
| 163 | const struct ip_esp_hdr *eh; | ||
| 164 | |||
| 165 | /* Max length: 4 "ESP " */ | ||
| 166 | nf_log_buf_add(m, "ESP "); | ||
| 167 | |||
| 168 | if (fragment) { | ||
| 169 | nf_log_buf_add(m, ")"); | ||
| 170 | return; | ||
| 171 | } | ||
| 172 | |||
| 173 | /* | ||
| 174 | * Max length: 26 "INCOMPLETE [65535 bytes] )" | ||
| 175 | */ | ||
| 176 | eh = skb_header_pointer(skb, ptr, sizeof(_esph), | ||
| 177 | &_esph); | ||
| 178 | if (eh == NULL) { | ||
| 179 | nf_log_buf_add(m, "INCOMPLETE [%u bytes] )", | ||
| 180 | skb->len - ptr); | ||
| 181 | return; | ||
| 182 | } | ||
| 183 | |||
| 184 | /* Length: 16 "SPI=0xF1234567 )" */ | ||
| 185 | nf_log_buf_add(m, "SPI=0x%x )", | ||
| 186 | ntohl(eh->spi)); | ||
| 187 | } | ||
| 188 | return; | ||
| 189 | default: | ||
| 190 | /* Max length: 20 "Unknown Ext Hdr 255" */ | ||
| 191 | nf_log_buf_add(m, "Unknown Ext Hdr %u", currenthdr); | ||
| 192 | return; | ||
| 193 | } | ||
| 194 | if (logflags & XT_LOG_IPOPT) | ||
| 195 | nf_log_buf_add(m, ") "); | ||
| 196 | |||
| 197 | currenthdr = hp->nexthdr; | ||
| 198 | ptr += hdrlen; | ||
| 199 | } | ||
| 200 | |||
| 201 | switch (currenthdr) { | ||
| 202 | case IPPROTO_TCP: | ||
| 203 | if (nf_log_dump_tcp_header(m, skb, currenthdr, fragment, | ||
| 204 | ptr, logflags)) | ||
| 205 | return; | ||
| 206 | break; | ||
| 207 | case IPPROTO_UDP: | ||
| 208 | case IPPROTO_UDPLITE: | ||
| 209 | if (nf_log_dump_udp_header(m, skb, currenthdr, fragment, ptr)) | ||
| 210 | return; | ||
| 211 | break; | ||
| 212 | case IPPROTO_ICMPV6: { | ||
| 213 | struct icmp6hdr _icmp6h; | ||
| 214 | const struct icmp6hdr *ic; | ||
| 215 | |||
| 216 | /* Max length: 13 "PROTO=ICMPv6 " */ | ||
| 217 | nf_log_buf_add(m, "PROTO=ICMPv6 "); | ||
| 218 | |||
| 219 | if (fragment) | ||
| 220 | break; | ||
| 221 | |||
| 222 | /* Max length: 25 "INCOMPLETE [65535 bytes] " */ | ||
| 223 | ic = skb_header_pointer(skb, ptr, sizeof(_icmp6h), &_icmp6h); | ||
| 224 | if (ic == NULL) { | ||
| 225 | nf_log_buf_add(m, "INCOMPLETE [%u bytes] ", | ||
| 226 | skb->len - ptr); | ||
| 227 | return; | ||
| 228 | } | ||
| 229 | |||
| 230 | /* Max length: 18 "TYPE=255 CODE=255 " */ | ||
| 231 | nf_log_buf_add(m, "TYPE=%u CODE=%u ", | ||
| 232 | ic->icmp6_type, ic->icmp6_code); | ||
| 233 | |||
| 234 | switch (ic->icmp6_type) { | ||
| 235 | case ICMPV6_ECHO_REQUEST: | ||
| 236 | case ICMPV6_ECHO_REPLY: | ||
| 237 | /* Max length: 19 "ID=65535 SEQ=65535 " */ | ||
| 238 | nf_log_buf_add(m, "ID=%u SEQ=%u ", | ||
| 239 | ntohs(ic->icmp6_identifier), | ||
| 240 | ntohs(ic->icmp6_sequence)); | ||
| 241 | break; | ||
| 242 | case ICMPV6_MGM_QUERY: | ||
| 243 | case ICMPV6_MGM_REPORT: | ||
| 244 | case ICMPV6_MGM_REDUCTION: | ||
| 245 | break; | ||
| 246 | |||
| 247 | case ICMPV6_PARAMPROB: | ||
| 248 | /* Max length: 17 "POINTER=ffffffff " */ | ||
| 249 | nf_log_buf_add(m, "POINTER=%08x ", | ||
| 250 | ntohl(ic->icmp6_pointer)); | ||
| 251 | /* Fall through */ | ||
| 252 | case ICMPV6_DEST_UNREACH: | ||
| 253 | case ICMPV6_PKT_TOOBIG: | ||
| 254 | case ICMPV6_TIME_EXCEED: | ||
| 255 | /* Max length: 3+maxlen */ | ||
| 256 | if (recurse) { | ||
| 257 | nf_log_buf_add(m, "["); | ||
| 258 | dump_ipv6_packet(m, info, skb, | ||
| 259 | ptr + sizeof(_icmp6h), 0); | ||
| 260 | nf_log_buf_add(m, "] "); | ||
| 261 | } | ||
| 262 | |||
| 263 | /* Max length: 10 "MTU=65535 " */ | ||
| 264 | if (ic->icmp6_type == ICMPV6_PKT_TOOBIG) { | ||
| 265 | nf_log_buf_add(m, "MTU=%u ", | ||
| 266 | ntohl(ic->icmp6_mtu)); | ||
| 267 | } | ||
| 268 | } | ||
| 269 | break; | ||
| 270 | } | ||
| 271 | /* Max length: 10 "PROTO=255 " */ | ||
| 272 | default: | ||
| 273 | nf_log_buf_add(m, "PROTO=%u ", currenthdr); | ||
| 274 | } | ||
| 275 | |||
| 276 | /* Max length: 15 "UID=4294967295 " */ | ||
| 277 | if ((logflags & XT_LOG_UID) && recurse) | ||
| 278 | nf_log_dump_sk_uid_gid(m, skb->sk); | ||
| 279 | |||
| 280 | /* Max length: 16 "MARK=0xFFFFFFFF " */ | ||
| 281 | if (recurse && skb->mark) | ||
| 282 | nf_log_buf_add(m, "MARK=0x%x ", skb->mark); | ||
| 283 | } | ||
| 284 | |||
| 285 | static void dump_ipv6_mac_header(struct nf_log_buf *m, | ||
| 286 | const struct nf_loginfo *info, | ||
| 287 | const struct sk_buff *skb) | ||
| 288 | { | ||
| 289 | struct net_device *dev = skb->dev; | ||
| 290 | unsigned int logflags = 0; | ||
| 291 | |||
| 292 | if (info->type == NF_LOG_TYPE_LOG) | ||
| 293 | logflags = info->u.log.logflags; | ||
| 294 | |||
| 295 | if (!(logflags & XT_LOG_MACDECODE)) | ||
| 296 | goto fallback; | ||
| 297 | |||
| 298 | switch (dev->type) { | ||
| 299 | case ARPHRD_ETHER: | ||
| 300 | nf_log_buf_add(m, "MACSRC=%pM MACDST=%pM MACPROTO=%04x ", | ||
| 301 | eth_hdr(skb)->h_source, eth_hdr(skb)->h_dest, | ||
| 302 | ntohs(eth_hdr(skb)->h_proto)); | ||
| 303 | return; | ||
| 304 | default: | ||
| 305 | break; | ||
| 306 | } | ||
| 307 | |||
| 308 | fallback: | ||
| 309 | nf_log_buf_add(m, "MAC="); | ||
| 310 | if (dev->hard_header_len && | ||
| 311 | skb->mac_header != skb->network_header) { | ||
| 312 | const unsigned char *p = skb_mac_header(skb); | ||
| 313 | unsigned int len = dev->hard_header_len; | ||
| 314 | unsigned int i; | ||
| 315 | |||
| 316 | if (dev->type == ARPHRD_SIT) { | ||
| 317 | p -= ETH_HLEN; | ||
| 318 | |||
| 319 | if (p < skb->head) | ||
| 320 | p = NULL; | ||
| 321 | } | ||
| 322 | |||
| 323 | if (p != NULL) { | ||
| 324 | nf_log_buf_add(m, "%02x", *p++); | ||
| 325 | for (i = 1; i < len; i++) | ||
| 326 | nf_log_buf_add(m, ":%02x", *p++); | ||
| 327 | } | ||
| 328 | nf_log_buf_add(m, " "); | ||
| 329 | |||
| 330 | if (dev->type == ARPHRD_SIT) { | ||
| 331 | const struct iphdr *iph = | ||
| 332 | (struct iphdr *)skb_mac_header(skb); | ||
| 333 | nf_log_buf_add(m, "TUNNEL=%pI4->%pI4 ", &iph->saddr, | ||
| 334 | &iph->daddr); | ||
| 335 | } | ||
| 336 | } else { | ||
| 337 | nf_log_buf_add(m, " "); | ||
| 338 | } | ||
| 339 | } | ||
| 340 | |||
| 341 | static void nf_log_ip6_packet(struct net *net, u_int8_t pf, | ||
| 342 | unsigned int hooknum, const struct sk_buff *skb, | ||
| 343 | const struct net_device *in, | ||
| 344 | const struct net_device *out, | ||
| 345 | const struct nf_loginfo *loginfo, | ||
| 346 | const char *prefix) | ||
| 347 | { | ||
| 348 | struct nf_log_buf *m; | ||
| 349 | |||
| 350 | /* FIXME: Disabled from containers until syslog ns is supported */ | ||
| 351 | if (!net_eq(net, &init_net)) | ||
| 352 | return; | ||
| 353 | |||
| 354 | m = nf_log_buf_open(); | ||
| 355 | |||
| 356 | if (!loginfo) | ||
| 357 | loginfo = &default_loginfo; | ||
| 358 | |||
| 359 | nf_log_dump_packet_common(m, pf, hooknum, skb, in, out, | ||
| 360 | loginfo, prefix); | ||
| 361 | |||
| 362 | if (in != NULL) | ||
| 363 | dump_ipv6_mac_header(m, loginfo, skb); | ||
| 364 | |||
| 365 | dump_ipv6_packet(m, loginfo, skb, skb_network_offset(skb), 1); | ||
| 366 | |||
| 367 | nf_log_buf_close(m); | ||
| 368 | } | ||
| 369 | |||
| 370 | static struct nf_logger nf_ip6_logger __read_mostly = { | ||
| 371 | .name = "nf_log_ipv6", | ||
| 372 | .type = NF_LOG_TYPE_LOG, | ||
| 373 | .logfn = nf_log_ip6_packet, | ||
| 374 | .me = THIS_MODULE, | ||
| 375 | }; | ||
| 376 | |||
| 377 | static int __net_init nf_log_ipv6_net_init(struct net *net) | ||
| 378 | { | ||
| 379 | nf_log_set(net, NFPROTO_IPV6, &nf_ip6_logger); | ||
| 380 | return 0; | ||
| 381 | } | ||
| 382 | |||
| 383 | static void __net_exit nf_log_ipv6_net_exit(struct net *net) | ||
| 384 | { | ||
| 385 | nf_log_unset(net, &nf_ip6_logger); | ||
| 386 | } | ||
| 387 | |||
| 388 | static struct pernet_operations nf_log_ipv6_net_ops = { | ||
| 389 | .init = nf_log_ipv6_net_init, | ||
| 390 | .exit = nf_log_ipv6_net_exit, | ||
| 391 | }; | ||
| 392 | |||
| 393 | static int __init nf_log_ipv6_init(void) | ||
| 394 | { | ||
| 395 | int ret; | ||
| 396 | |||
| 397 | ret = register_pernet_subsys(&nf_log_ipv6_net_ops); | ||
| 398 | if (ret < 0) | ||
| 399 | return ret; | ||
| 400 | |||
| 401 | nf_log_register(NFPROTO_IPV6, &nf_ip6_logger); | ||
| 402 | return 0; | ||
| 403 | } | ||
| 404 | |||
| 405 | static void __exit nf_log_ipv6_exit(void) | ||
| 406 | { | ||
| 407 | unregister_pernet_subsys(&nf_log_ipv6_net_ops); | ||
| 408 | nf_log_unregister(&nf_ip6_logger); | ||
| 409 | } | ||
| 410 | |||
| 411 | module_init(nf_log_ipv6_init); | ||
| 412 | module_exit(nf_log_ipv6_exit); | ||
| 413 | |||
| 414 | MODULE_AUTHOR("Netfilter Core Team <coreteam@netfilter.org>"); | ||
| 415 | MODULE_DESCRIPTION("Netfilter IPv4 packet logging"); | ||
| 416 | MODULE_LICENSE("GPL"); | ||
| 417 | MODULE_ALIAS_NF_LOGGER(AF_INET6, 0); | ||
diff --git a/net/ipv6/netfilter/nf_nat_l3proto_ipv6.c b/net/ipv6/netfilter/nf_nat_l3proto_ipv6.c index abfe75a2e316..fc8e49b2ff3e 100644 --- a/net/ipv6/netfilter/nf_nat_l3proto_ipv6.c +++ b/net/ipv6/netfilter/nf_nat_l3proto_ipv6.c | |||
| @@ -158,6 +158,7 @@ static void nf_nat_ipv6_csum_recalc(struct sk_buff *skb, | |||
| 158 | htons(oldlen), htons(datalen), 1); | 158 | htons(oldlen), htons(datalen), 1); |
| 159 | } | 159 | } |
| 160 | 160 | ||
| 161 | #if IS_ENABLED(CONFIG_NF_CT_NETLINK) | ||
| 161 | static int nf_nat_ipv6_nlattr_to_range(struct nlattr *tb[], | 162 | static int nf_nat_ipv6_nlattr_to_range(struct nlattr *tb[], |
| 162 | struct nf_nat_range *range) | 163 | struct nf_nat_range *range) |
| 163 | { | 164 | { |
| @@ -175,6 +176,7 @@ static int nf_nat_ipv6_nlattr_to_range(struct nlattr *tb[], | |||
| 175 | 176 | ||
| 176 | return 0; | 177 | return 0; |
| 177 | } | 178 | } |
| 179 | #endif | ||
| 178 | 180 | ||
| 179 | static const struct nf_nat_l3proto nf_nat_l3proto_ipv6 = { | 181 | static const struct nf_nat_l3proto nf_nat_l3proto_ipv6 = { |
| 180 | .l3proto = NFPROTO_IPV6, | 182 | .l3proto = NFPROTO_IPV6, |
| @@ -183,7 +185,9 @@ static const struct nf_nat_l3proto nf_nat_l3proto_ipv6 = { | |||
| 183 | .manip_pkt = nf_nat_ipv6_manip_pkt, | 185 | .manip_pkt = nf_nat_ipv6_manip_pkt, |
| 184 | .csum_update = nf_nat_ipv6_csum_update, | 186 | .csum_update = nf_nat_ipv6_csum_update, |
| 185 | .csum_recalc = nf_nat_ipv6_csum_recalc, | 187 | .csum_recalc = nf_nat_ipv6_csum_recalc, |
| 188 | #if IS_ENABLED(CONFIG_NF_CT_NETLINK) | ||
| 186 | .nlattr_to_range = nf_nat_ipv6_nlattr_to_range, | 189 | .nlattr_to_range = nf_nat_ipv6_nlattr_to_range, |
| 190 | #endif | ||
| 187 | #ifdef CONFIG_XFRM | 191 | #ifdef CONFIG_XFRM |
| 188 | .decode_session = nf_nat_ipv6_decode_session, | 192 | .decode_session = nf_nat_ipv6_decode_session, |
| 189 | #endif | 193 | #endif |
diff --git a/net/ipv6/proc.c b/net/ipv6/proc.c index 3317440ea341..2d6f860e5c1e 100644 --- a/net/ipv6/proc.c +++ b/net/ipv6/proc.c | |||
| @@ -33,6 +33,7 @@ | |||
| 33 | static int sockstat6_seq_show(struct seq_file *seq, void *v) | 33 | static int sockstat6_seq_show(struct seq_file *seq, void *v) |
| 34 | { | 34 | { |
| 35 | struct net *net = seq->private; | 35 | struct net *net = seq->private; |
| 36 | unsigned int frag_mem = ip6_frag_mem(net); | ||
| 36 | 37 | ||
| 37 | seq_printf(seq, "TCP6: inuse %d\n", | 38 | seq_printf(seq, "TCP6: inuse %d\n", |
| 38 | sock_prot_inuse_get(net, &tcpv6_prot)); | 39 | sock_prot_inuse_get(net, &tcpv6_prot)); |
| @@ -42,8 +43,7 @@ static int sockstat6_seq_show(struct seq_file *seq, void *v) | |||
| 42 | sock_prot_inuse_get(net, &udplitev6_prot)); | 43 | sock_prot_inuse_get(net, &udplitev6_prot)); |
| 43 | seq_printf(seq, "RAW6: inuse %d\n", | 44 | seq_printf(seq, "RAW6: inuse %d\n", |
| 44 | sock_prot_inuse_get(net, &rawv6_prot)); | 45 | sock_prot_inuse_get(net, &rawv6_prot)); |
| 45 | seq_printf(seq, "FRAG6: inuse %d memory %d\n", | 46 | seq_printf(seq, "FRAG6: inuse %u memory %u\n", !!frag_mem, frag_mem); |
| 46 | ip6_frag_nqueues(net), ip6_frag_mem(net)); | ||
| 47 | return 0; | 47 | return 0; |
| 48 | } | 48 | } |
| 49 | 49 | ||
diff --git a/net/ipv6/raw.c b/net/ipv6/raw.c index b2dc60b0c764..39d44226e402 100644 --- a/net/ipv6/raw.c +++ b/net/ipv6/raw.c | |||
| @@ -176,7 +176,7 @@ static bool ipv6_raw_deliver(struct sk_buff *skb, int nexthdr) | |||
| 176 | goto out; | 176 | goto out; |
| 177 | 177 | ||
| 178 | net = dev_net(skb->dev); | 178 | net = dev_net(skb->dev); |
| 179 | sk = __raw_v6_lookup(net, sk, nexthdr, daddr, saddr, IP6CB(skb)->iif); | 179 | sk = __raw_v6_lookup(net, sk, nexthdr, daddr, saddr, inet6_iif(skb)); |
| 180 | 180 | ||
| 181 | while (sk) { | 181 | while (sk) { |
| 182 | int filtered; | 182 | int filtered; |
| @@ -220,7 +220,7 @@ static bool ipv6_raw_deliver(struct sk_buff *skb, int nexthdr) | |||
| 220 | } | 220 | } |
| 221 | } | 221 | } |
| 222 | sk = __raw_v6_lookup(net, sk_next(sk), nexthdr, daddr, saddr, | 222 | sk = __raw_v6_lookup(net, sk_next(sk), nexthdr, daddr, saddr, |
| 223 | IP6CB(skb)->iif); | 223 | inet6_iif(skb)); |
| 224 | } | 224 | } |
| 225 | out: | 225 | out: |
| 226 | read_unlock(&raw_v6_hashinfo.lock); | 226 | read_unlock(&raw_v6_hashinfo.lock); |
| @@ -375,7 +375,7 @@ void raw6_icmp_error(struct sk_buff *skb, int nexthdr, | |||
| 375 | net = dev_net(skb->dev); | 375 | net = dev_net(skb->dev); |
| 376 | 376 | ||
| 377 | while ((sk = __raw_v6_lookup(net, sk, nexthdr, saddr, daddr, | 377 | while ((sk = __raw_v6_lookup(net, sk, nexthdr, saddr, daddr, |
| 378 | IP6CB(skb)->iif))) { | 378 | inet6_iif(skb)))) { |
| 379 | rawv6_err(sk, skb, NULL, type, code, | 379 | rawv6_err(sk, skb, NULL, type, code, |
| 380 | inner_offset, info); | 380 | inner_offset, info); |
| 381 | sk = sk_next(sk); | 381 | sk = sk_next(sk); |
| @@ -506,7 +506,7 @@ static int rawv6_recvmsg(struct kiocb *iocb, struct sock *sk, | |||
| 506 | sin6->sin6_addr = ipv6_hdr(skb)->saddr; | 506 | sin6->sin6_addr = ipv6_hdr(skb)->saddr; |
| 507 | sin6->sin6_flowinfo = 0; | 507 | sin6->sin6_flowinfo = 0; |
| 508 | sin6->sin6_scope_id = ipv6_iface_scope_id(&sin6->sin6_addr, | 508 | sin6->sin6_scope_id = ipv6_iface_scope_id(&sin6->sin6_addr, |
| 509 | IP6CB(skb)->iif); | 509 | inet6_iif(skb)); |
| 510 | *addr_len = sizeof(*sin6); | 510 | *addr_len = sizeof(*sin6); |
| 511 | } | 511 | } |
| 512 | 512 | ||
| @@ -588,8 +588,7 @@ static int rawv6_push_pending_frames(struct sock *sk, struct flowi6 *fl6, | |||
| 588 | } | 588 | } |
| 589 | 589 | ||
| 590 | offset += skb_transport_offset(skb); | 590 | offset += skb_transport_offset(skb); |
| 591 | if (skb_copy_bits(skb, offset, &csum, 2)) | 591 | BUG_ON(skb_copy_bits(skb, offset, &csum, 2)); |
| 592 | BUG(); | ||
| 593 | 592 | ||
| 594 | /* in case cksum was not initialized */ | 593 | /* in case cksum was not initialized */ |
| 595 | if (unlikely(csum)) | 594 | if (unlikely(csum)) |
| @@ -601,8 +600,7 @@ static int rawv6_push_pending_frames(struct sock *sk, struct flowi6 *fl6, | |||
| 601 | if (csum == 0 && fl6->flowi6_proto == IPPROTO_UDP) | 600 | if (csum == 0 && fl6->flowi6_proto == IPPROTO_UDP) |
| 602 | csum = CSUM_MANGLED_0; | 601 | csum = CSUM_MANGLED_0; |
| 603 | 602 | ||
| 604 | if (skb_store_bits(skb, offset, &csum, 2)) | 603 | BUG_ON(skb_store_bits(skb, offset, &csum, 2)); |
| 605 | BUG(); | ||
| 606 | 604 | ||
| 607 | send: | 605 | send: |
| 608 | err = ip6_push_pending_frames(sk); | 606 | err = ip6_push_pending_frames(sk); |
diff --git a/net/ipv6/reassembly.c b/net/ipv6/reassembly.c index cc85a9ba5010..c6557d9f7808 100644 --- a/net/ipv6/reassembly.c +++ b/net/ipv6/reassembly.c | |||
| @@ -60,6 +60,8 @@ | |||
| 60 | #include <net/inet_frag.h> | 60 | #include <net/inet_frag.h> |
| 61 | #include <net/inet_ecn.h> | 61 | #include <net/inet_ecn.h> |
| 62 | 62 | ||
| 63 | static const char ip6_frag_cache_name[] = "ip6-frags"; | ||
| 64 | |||
| 63 | struct ip6frag_skb_cb | 65 | struct ip6frag_skb_cb |
| 64 | { | 66 | { |
| 65 | struct inet6_skb_parm h; | 67 | struct inet6_skb_parm h; |
| @@ -85,27 +87,23 @@ static int ip6_frag_reasm(struct frag_queue *fq, struct sk_buff *prev, | |||
| 85 | static unsigned int inet6_hash_frag(__be32 id, const struct in6_addr *saddr, | 87 | static unsigned int inet6_hash_frag(__be32 id, const struct in6_addr *saddr, |
| 86 | const struct in6_addr *daddr) | 88 | const struct in6_addr *daddr) |
| 87 | { | 89 | { |
| 88 | u32 c; | ||
| 89 | |||
| 90 | net_get_random_once(&ip6_frags.rnd, sizeof(ip6_frags.rnd)); | 90 | net_get_random_once(&ip6_frags.rnd, sizeof(ip6_frags.rnd)); |
| 91 | c = jhash_3words(ipv6_addr_hash(saddr), ipv6_addr_hash(daddr), | 91 | return jhash_3words(ipv6_addr_hash(saddr), ipv6_addr_hash(daddr), |
| 92 | (__force u32)id, ip6_frags.rnd); | 92 | (__force u32)id, ip6_frags.rnd); |
| 93 | |||
| 94 | return c & (INETFRAGS_HASHSZ - 1); | ||
| 95 | } | 93 | } |
| 96 | 94 | ||
| 97 | static unsigned int ip6_hashfn(struct inet_frag_queue *q) | 95 | static unsigned int ip6_hashfn(const struct inet_frag_queue *q) |
| 98 | { | 96 | { |
| 99 | struct frag_queue *fq; | 97 | const struct frag_queue *fq; |
| 100 | 98 | ||
| 101 | fq = container_of(q, struct frag_queue, q); | 99 | fq = container_of(q, struct frag_queue, q); |
| 102 | return inet6_hash_frag(fq->id, &fq->saddr, &fq->daddr); | 100 | return inet6_hash_frag(fq->id, &fq->saddr, &fq->daddr); |
| 103 | } | 101 | } |
| 104 | 102 | ||
| 105 | bool ip6_frag_match(struct inet_frag_queue *q, void *a) | 103 | bool ip6_frag_match(const struct inet_frag_queue *q, const void *a) |
| 106 | { | 104 | { |
| 107 | struct frag_queue *fq; | 105 | const struct frag_queue *fq; |
| 108 | struct ip6_create_arg *arg = a; | 106 | const struct ip6_create_arg *arg = a; |
| 109 | 107 | ||
| 110 | fq = container_of(q, struct frag_queue, q); | 108 | fq = container_of(q, struct frag_queue, q); |
| 111 | return fq->id == arg->id && | 109 | return fq->id == arg->id && |
| @@ -115,10 +113,10 @@ bool ip6_frag_match(struct inet_frag_queue *q, void *a) | |||
| 115 | } | 113 | } |
| 116 | EXPORT_SYMBOL(ip6_frag_match); | 114 | EXPORT_SYMBOL(ip6_frag_match); |
| 117 | 115 | ||
| 118 | void ip6_frag_init(struct inet_frag_queue *q, void *a) | 116 | void ip6_frag_init(struct inet_frag_queue *q, const void *a) |
| 119 | { | 117 | { |
| 120 | struct frag_queue *fq = container_of(q, struct frag_queue, q); | 118 | struct frag_queue *fq = container_of(q, struct frag_queue, q); |
| 121 | struct ip6_create_arg *arg = a; | 119 | const struct ip6_create_arg *arg = a; |
| 122 | 120 | ||
| 123 | fq->id = arg->id; | 121 | fq->id = arg->id; |
| 124 | fq->user = arg->user; | 122 | fq->user = arg->user; |
| @@ -135,7 +133,7 @@ void ip6_expire_frag_queue(struct net *net, struct frag_queue *fq, | |||
| 135 | 133 | ||
| 136 | spin_lock(&fq->q.lock); | 134 | spin_lock(&fq->q.lock); |
| 137 | 135 | ||
| 138 | if (fq->q.last_in & INET_FRAG_COMPLETE) | 136 | if (fq->q.flags & INET_FRAG_COMPLETE) |
| 139 | goto out; | 137 | goto out; |
| 140 | 138 | ||
| 141 | inet_frag_kill(&fq->q, frags); | 139 | inet_frag_kill(&fq->q, frags); |
| @@ -145,17 +143,20 @@ void ip6_expire_frag_queue(struct net *net, struct frag_queue *fq, | |||
| 145 | if (!dev) | 143 | if (!dev) |
| 146 | goto out_rcu_unlock; | 144 | goto out_rcu_unlock; |
| 147 | 145 | ||
| 148 | IP6_INC_STATS_BH(net, __in6_dev_get(dev), IPSTATS_MIB_REASMTIMEOUT); | ||
| 149 | IP6_INC_STATS_BH(net, __in6_dev_get(dev), IPSTATS_MIB_REASMFAILS); | 146 | IP6_INC_STATS_BH(net, __in6_dev_get(dev), IPSTATS_MIB_REASMFAILS); |
| 150 | 147 | ||
| 148 | if (fq->q.flags & INET_FRAG_EVICTED) | ||
| 149 | goto out_rcu_unlock; | ||
| 150 | |||
| 151 | IP6_INC_STATS_BH(net, __in6_dev_get(dev), IPSTATS_MIB_REASMTIMEOUT); | ||
| 152 | |||
| 151 | /* Don't send error if the first segment did not arrive. */ | 153 | /* Don't send error if the first segment did not arrive. */ |
| 152 | if (!(fq->q.last_in & INET_FRAG_FIRST_IN) || !fq->q.fragments) | 154 | if (!(fq->q.flags & INET_FRAG_FIRST_IN) || !fq->q.fragments) |
| 153 | goto out_rcu_unlock; | 155 | goto out_rcu_unlock; |
| 154 | 156 | ||
| 155 | /* | 157 | /* But use as source device on which LAST ARRIVED |
| 156 | But use as source device on which LAST ARRIVED | 158 | * segment was received. And do not use fq->dev |
| 157 | segment was received. And do not use fq->dev | 159 | * pointer directly, device might already disappeared. |
| 158 | pointer directly, device might already disappeared. | ||
| 159 | */ | 160 | */ |
| 160 | fq->q.fragments->dev = dev; | 161 | fq->q.fragments->dev = dev; |
| 161 | icmpv6_send(fq->q.fragments, ICMPV6_TIME_EXCEED, ICMPV6_EXC_FRAGTIME, 0); | 162 | icmpv6_send(fq->q.fragments, ICMPV6_TIME_EXCEED, ICMPV6_EXC_FRAGTIME, 0); |
| @@ -192,7 +193,6 @@ fq_find(struct net *net, __be32 id, const struct in6_addr *src, | |||
| 192 | arg.dst = dst; | 193 | arg.dst = dst; |
| 193 | arg.ecn = ecn; | 194 | arg.ecn = ecn; |
| 194 | 195 | ||
| 195 | read_lock(&ip6_frags.lock); | ||
| 196 | hash = inet6_hash_frag(id, src, dst); | 196 | hash = inet6_hash_frag(id, src, dst); |
| 197 | 197 | ||
| 198 | q = inet_frag_find(&net->ipv6.frags, &ip6_frags, &arg, hash); | 198 | q = inet_frag_find(&net->ipv6.frags, &ip6_frags, &arg, hash); |
| @@ -212,7 +212,7 @@ static int ip6_frag_queue(struct frag_queue *fq, struct sk_buff *skb, | |||
| 212 | struct net *net = dev_net(skb_dst(skb)->dev); | 212 | struct net *net = dev_net(skb_dst(skb)->dev); |
| 213 | u8 ecn; | 213 | u8 ecn; |
| 214 | 214 | ||
| 215 | if (fq->q.last_in & INET_FRAG_COMPLETE) | 215 | if (fq->q.flags & INET_FRAG_COMPLETE) |
| 216 | goto err; | 216 | goto err; |
| 217 | 217 | ||
| 218 | offset = ntohs(fhdr->frag_off) & ~0x7; | 218 | offset = ntohs(fhdr->frag_off) & ~0x7; |
| @@ -243,9 +243,9 @@ static int ip6_frag_queue(struct frag_queue *fq, struct sk_buff *skb, | |||
| 243 | * or have different end, the segment is corrupted. | 243 | * or have different end, the segment is corrupted. |
| 244 | */ | 244 | */ |
| 245 | if (end < fq->q.len || | 245 | if (end < fq->q.len || |
| 246 | ((fq->q.last_in & INET_FRAG_LAST_IN) && end != fq->q.len)) | 246 | ((fq->q.flags & INET_FRAG_LAST_IN) && end != fq->q.len)) |
| 247 | goto err; | 247 | goto err; |
| 248 | fq->q.last_in |= INET_FRAG_LAST_IN; | 248 | fq->q.flags |= INET_FRAG_LAST_IN; |
| 249 | fq->q.len = end; | 249 | fq->q.len = end; |
| 250 | } else { | 250 | } else { |
| 251 | /* Check if the fragment is rounded to 8 bytes. | 251 | /* Check if the fragment is rounded to 8 bytes. |
| @@ -263,7 +263,7 @@ static int ip6_frag_queue(struct frag_queue *fq, struct sk_buff *skb, | |||
| 263 | } | 263 | } |
| 264 | if (end > fq->q.len) { | 264 | if (end > fq->q.len) { |
| 265 | /* Some bits beyond end -> corruption. */ | 265 | /* Some bits beyond end -> corruption. */ |
| 266 | if (fq->q.last_in & INET_FRAG_LAST_IN) | 266 | if (fq->q.flags & INET_FRAG_LAST_IN) |
| 267 | goto err; | 267 | goto err; |
| 268 | fq->q.len = end; | 268 | fq->q.len = end; |
| 269 | } | 269 | } |
| @@ -338,10 +338,10 @@ found: | |||
| 338 | */ | 338 | */ |
| 339 | if (offset == 0) { | 339 | if (offset == 0) { |
| 340 | fq->nhoffset = nhoff; | 340 | fq->nhoffset = nhoff; |
| 341 | fq->q.last_in |= INET_FRAG_FIRST_IN; | 341 | fq->q.flags |= INET_FRAG_FIRST_IN; |
| 342 | } | 342 | } |
| 343 | 343 | ||
| 344 | if (fq->q.last_in == (INET_FRAG_FIRST_IN | INET_FRAG_LAST_IN) && | 344 | if (fq->q.flags == (INET_FRAG_FIRST_IN | INET_FRAG_LAST_IN) && |
| 345 | fq->q.meat == fq->q.len) { | 345 | fq->q.meat == fq->q.len) { |
| 346 | int res; | 346 | int res; |
| 347 | unsigned long orefdst = skb->_skb_refdst; | 347 | unsigned long orefdst = skb->_skb_refdst; |
| @@ -353,14 +353,13 @@ found: | |||
| 353 | } | 353 | } |
| 354 | 354 | ||
| 355 | skb_dst_drop(skb); | 355 | skb_dst_drop(skb); |
| 356 | inet_frag_lru_move(&fq->q); | ||
| 357 | return -1; | 356 | return -1; |
| 358 | 357 | ||
| 359 | discard_fq: | 358 | discard_fq: |
| 360 | inet_frag_kill(&fq->q, &ip6_frags); | 359 | inet_frag_kill(&fq->q, &ip6_frags); |
| 361 | err: | 360 | err: |
| 362 | IP6_INC_STATS(net, ip6_dst_idev(skb_dst(skb)), | 361 | IP6_INC_STATS_BH(net, ip6_dst_idev(skb_dst(skb)), |
| 363 | IPSTATS_MIB_REASMFAILS); | 362 | IPSTATS_MIB_REASMFAILS); |
| 364 | kfree_skb(skb); | 363 | kfree_skb(skb); |
| 365 | return -1; | 364 | return -1; |
| 366 | } | 365 | } |
| @@ -523,7 +522,6 @@ static int ipv6_frag_rcv(struct sk_buff *skb) | |||
| 523 | struct frag_queue *fq; | 522 | struct frag_queue *fq; |
| 524 | const struct ipv6hdr *hdr = ipv6_hdr(skb); | 523 | const struct ipv6hdr *hdr = ipv6_hdr(skb); |
| 525 | struct net *net = dev_net(skb_dst(skb)->dev); | 524 | struct net *net = dev_net(skb_dst(skb)->dev); |
| 526 | int evicted; | ||
| 527 | 525 | ||
| 528 | if (IP6CB(skb)->flags & IP6SKB_FRAGMENTED) | 526 | if (IP6CB(skb)->flags & IP6SKB_FRAGMENTED) |
| 529 | goto fail_hdr; | 527 | goto fail_hdr; |
| @@ -552,11 +550,6 @@ static int ipv6_frag_rcv(struct sk_buff *skb) | |||
| 552 | return 1; | 550 | return 1; |
| 553 | } | 551 | } |
| 554 | 552 | ||
| 555 | evicted = inet_frag_evictor(&net->ipv6.frags, &ip6_frags, false); | ||
| 556 | if (evicted) | ||
| 557 | IP6_ADD_STATS_BH(net, ip6_dst_idev(skb_dst(skb)), | ||
| 558 | IPSTATS_MIB_REASMFAILS, evicted); | ||
| 559 | |||
| 560 | fq = fq_find(net, fhdr->identification, &hdr->saddr, &hdr->daddr, | 553 | fq = fq_find(net, fhdr->identification, &hdr->saddr, &hdr->daddr, |
| 561 | ip6_frag_ecn(hdr)); | 554 | ip6_frag_ecn(hdr)); |
| 562 | if (fq != NULL) { | 555 | if (fq != NULL) { |
| @@ -576,7 +569,8 @@ static int ipv6_frag_rcv(struct sk_buff *skb) | |||
| 576 | return -1; | 569 | return -1; |
| 577 | 570 | ||
| 578 | fail_hdr: | 571 | fail_hdr: |
| 579 | IP6_INC_STATS(net, ip6_dst_idev(skb_dst(skb)), IPSTATS_MIB_INHDRERRORS); | 572 | IP6_INC_STATS_BH(net, ip6_dst_idev(skb_dst(skb)), |
| 573 | IPSTATS_MIB_INHDRERRORS); | ||
| 580 | icmpv6_param_prob(skb, ICMPV6_HDR_FIELD, skb_network_header_len(skb)); | 574 | icmpv6_param_prob(skb, ICMPV6_HDR_FIELD, skb_network_header_len(skb)); |
| 581 | return -1; | 575 | return -1; |
| 582 | } | 576 | } |
| @@ -588,20 +582,25 @@ static const struct inet6_protocol frag_protocol = | |||
| 588 | }; | 582 | }; |
| 589 | 583 | ||
| 590 | #ifdef CONFIG_SYSCTL | 584 | #ifdef CONFIG_SYSCTL |
| 585 | static int zero; | ||
| 586 | |||
| 591 | static struct ctl_table ip6_frags_ns_ctl_table[] = { | 587 | static struct ctl_table ip6_frags_ns_ctl_table[] = { |
| 592 | { | 588 | { |
| 593 | .procname = "ip6frag_high_thresh", | 589 | .procname = "ip6frag_high_thresh", |
| 594 | .data = &init_net.ipv6.frags.high_thresh, | 590 | .data = &init_net.ipv6.frags.high_thresh, |
| 595 | .maxlen = sizeof(int), | 591 | .maxlen = sizeof(int), |
| 596 | .mode = 0644, | 592 | .mode = 0644, |
| 597 | .proc_handler = proc_dointvec | 593 | .proc_handler = proc_dointvec_minmax, |
| 594 | .extra1 = &init_net.ipv6.frags.low_thresh | ||
| 598 | }, | 595 | }, |
| 599 | { | 596 | { |
| 600 | .procname = "ip6frag_low_thresh", | 597 | .procname = "ip6frag_low_thresh", |
| 601 | .data = &init_net.ipv6.frags.low_thresh, | 598 | .data = &init_net.ipv6.frags.low_thresh, |
| 602 | .maxlen = sizeof(int), | 599 | .maxlen = sizeof(int), |
| 603 | .mode = 0644, | 600 | .mode = 0644, |
| 604 | .proc_handler = proc_dointvec | 601 | .proc_handler = proc_dointvec_minmax, |
| 602 | .extra1 = &zero, | ||
| 603 | .extra2 = &init_net.ipv6.frags.high_thresh | ||
| 605 | }, | 604 | }, |
| 606 | { | 605 | { |
| 607 | .procname = "ip6frag_time", | 606 | .procname = "ip6frag_time", |
| @@ -613,10 +612,12 @@ static struct ctl_table ip6_frags_ns_ctl_table[] = { | |||
| 613 | { } | 612 | { } |
| 614 | }; | 613 | }; |
| 615 | 614 | ||
| 615 | /* secret interval has been deprecated */ | ||
| 616 | static int ip6_frags_secret_interval_unused; | ||
| 616 | static struct ctl_table ip6_frags_ctl_table[] = { | 617 | static struct ctl_table ip6_frags_ctl_table[] = { |
| 617 | { | 618 | { |
| 618 | .procname = "ip6frag_secret_interval", | 619 | .procname = "ip6frag_secret_interval", |
| 619 | .data = &ip6_frags.secret_interval, | 620 | .data = &ip6_frags_secret_interval_unused, |
| 620 | .maxlen = sizeof(int), | 621 | .maxlen = sizeof(int), |
| 621 | .mode = 0644, | 622 | .mode = 0644, |
| 622 | .proc_handler = proc_dointvec_jiffies, | 623 | .proc_handler = proc_dointvec_jiffies, |
| @@ -636,7 +637,10 @@ static int __net_init ip6_frags_ns_sysctl_register(struct net *net) | |||
| 636 | goto err_alloc; | 637 | goto err_alloc; |
| 637 | 638 | ||
| 638 | table[0].data = &net->ipv6.frags.high_thresh; | 639 | table[0].data = &net->ipv6.frags.high_thresh; |
| 640 | table[0].extra1 = &net->ipv6.frags.low_thresh; | ||
| 641 | table[0].extra2 = &init_net.ipv6.frags.high_thresh; | ||
| 639 | table[1].data = &net->ipv6.frags.low_thresh; | 642 | table[1].data = &net->ipv6.frags.low_thresh; |
| 643 | table[1].extra2 = &net->ipv6.frags.high_thresh; | ||
| 640 | table[2].data = &net->ipv6.frags.timeout; | 644 | table[2].data = &net->ipv6.frags.timeout; |
| 641 | 645 | ||
| 642 | /* Don't export sysctls to unprivileged users */ | 646 | /* Don't export sysctls to unprivileged users */ |
| @@ -746,8 +750,10 @@ int __init ipv6_frag_init(void) | |||
| 746 | ip6_frags.qsize = sizeof(struct frag_queue); | 750 | ip6_frags.qsize = sizeof(struct frag_queue); |
| 747 | ip6_frags.match = ip6_frag_match; | 751 | ip6_frags.match = ip6_frag_match; |
| 748 | ip6_frags.frag_expire = ip6_frag_expire; | 752 | ip6_frags.frag_expire = ip6_frag_expire; |
| 749 | ip6_frags.secret_interval = 10 * 60 * HZ; | 753 | ip6_frags.frags_cache_name = ip6_frag_cache_name; |
| 750 | inet_frags_init(&ip6_frags); | 754 | ret = inet_frags_init(&ip6_frags); |
| 755 | if (ret) | ||
| 756 | goto err_pernet; | ||
| 751 | out: | 757 | out: |
| 752 | return ret; | 758 | return ret; |
| 753 | 759 | ||
diff --git a/net/ipv6/sit.c b/net/ipv6/sit.c index 4f408176dc64..6163f851dc01 100644 --- a/net/ipv6/sit.c +++ b/net/ipv6/sit.c | |||
| @@ -101,19 +101,19 @@ static struct ip_tunnel *ipip6_tunnel_lookup(struct net *net, | |||
| 101 | for_each_ip_tunnel_rcu(t, sitn->tunnels_r_l[h0 ^ h1]) { | 101 | for_each_ip_tunnel_rcu(t, sitn->tunnels_r_l[h0 ^ h1]) { |
| 102 | if (local == t->parms.iph.saddr && | 102 | if (local == t->parms.iph.saddr && |
| 103 | remote == t->parms.iph.daddr && | 103 | remote == t->parms.iph.daddr && |
| 104 | (!dev || !t->parms.link || dev->iflink == t->parms.link) && | 104 | (!dev || !t->parms.link || dev->ifindex == t->parms.link) && |
| 105 | (t->dev->flags & IFF_UP)) | 105 | (t->dev->flags & IFF_UP)) |
| 106 | return t; | 106 | return t; |
| 107 | } | 107 | } |
| 108 | for_each_ip_tunnel_rcu(t, sitn->tunnels_r[h0]) { | 108 | for_each_ip_tunnel_rcu(t, sitn->tunnels_r[h0]) { |
| 109 | if (remote == t->parms.iph.daddr && | 109 | if (remote == t->parms.iph.daddr && |
| 110 | (!dev || !t->parms.link || dev->iflink == t->parms.link) && | 110 | (!dev || !t->parms.link || dev->ifindex == t->parms.link) && |
| 111 | (t->dev->flags & IFF_UP)) | 111 | (t->dev->flags & IFF_UP)) |
| 112 | return t; | 112 | return t; |
| 113 | } | 113 | } |
| 114 | for_each_ip_tunnel_rcu(t, sitn->tunnels_l[h1]) { | 114 | for_each_ip_tunnel_rcu(t, sitn->tunnels_l[h1]) { |
| 115 | if (local == t->parms.iph.saddr && | 115 | if (local == t->parms.iph.saddr && |
| 116 | (!dev || !t->parms.link || dev->iflink == t->parms.link) && | 116 | (!dev || !t->parms.link || dev->ifindex == t->parms.link) && |
| 117 | (t->dev->flags & IFF_UP)) | 117 | (t->dev->flags & IFF_UP)) |
| 118 | return t; | 118 | return t; |
| 119 | } | 119 | } |
| @@ -250,7 +250,8 @@ static struct ip_tunnel *ipip6_tunnel_locate(struct net *net, | |||
| 250 | else | 250 | else |
| 251 | strcpy(name, "sit%d"); | 251 | strcpy(name, "sit%d"); |
| 252 | 252 | ||
| 253 | dev = alloc_netdev(sizeof(*t), name, ipip6_tunnel_setup); | 253 | dev = alloc_netdev(sizeof(*t), name, NET_NAME_UNKNOWN, |
| 254 | ipip6_tunnel_setup); | ||
| 254 | if (dev == NULL) | 255 | if (dev == NULL) |
| 255 | return NULL; | 256 | return NULL; |
| 256 | 257 | ||
| @@ -1729,6 +1730,7 @@ static int __net_init sit_init_net(struct net *net) | |||
| 1729 | sitn->tunnels[3] = sitn->tunnels_r_l; | 1730 | sitn->tunnels[3] = sitn->tunnels_r_l; |
| 1730 | 1731 | ||
| 1731 | sitn->fb_tunnel_dev = alloc_netdev(sizeof(struct ip_tunnel), "sit0", | 1732 | sitn->fb_tunnel_dev = alloc_netdev(sizeof(struct ip_tunnel), "sit0", |
| 1733 | NET_NAME_UNKNOWN, | ||
| 1732 | ipip6_tunnel_setup); | 1734 | ipip6_tunnel_setup); |
| 1733 | if (!sitn->fb_tunnel_dev) { | 1735 | if (!sitn->fb_tunnel_dev) { |
| 1734 | err = -ENOMEM; | 1736 | err = -ENOMEM; |
diff --git a/net/ipv6/syncookies.c b/net/ipv6/syncookies.c index a822b880689b..83cea1d39466 100644 --- a/net/ipv6/syncookies.c +++ b/net/ipv6/syncookies.c | |||
| @@ -187,7 +187,7 @@ struct sock *cookie_v6_check(struct sock *sk, struct sk_buff *skb) | |||
| 187 | goto out; | 187 | goto out; |
| 188 | 188 | ||
| 189 | ret = NULL; | 189 | ret = NULL; |
| 190 | req = inet6_reqsk_alloc(&tcp6_request_sock_ops); | 190 | req = inet_reqsk_alloc(&tcp6_request_sock_ops); |
| 191 | if (!req) | 191 | if (!req) |
| 192 | goto out; | 192 | goto out; |
| 193 | 193 | ||
diff --git a/net/ipv6/sysctl_net_ipv6.c b/net/ipv6/sysctl_net_ipv6.c index 058f3eca2e53..0c56c93619e0 100644 --- a/net/ipv6/sysctl_net_ipv6.c +++ b/net/ipv6/sysctl_net_ipv6.c | |||
| @@ -39,6 +39,13 @@ static struct ctl_table ipv6_table_template[] = { | |||
| 39 | .proc_handler = proc_dointvec | 39 | .proc_handler = proc_dointvec |
| 40 | }, | 40 | }, |
| 41 | { | 41 | { |
| 42 | .procname = "auto_flowlabels", | ||
| 43 | .data = &init_net.ipv6.sysctl.auto_flowlabels, | ||
| 44 | .maxlen = sizeof(int), | ||
| 45 | .mode = 0644, | ||
| 46 | .proc_handler = proc_dointvec | ||
| 47 | }, | ||
| 48 | { | ||
| 42 | .procname = "fwmark_reflect", | 49 | .procname = "fwmark_reflect", |
| 43 | .data = &init_net.ipv6.sysctl.fwmark_reflect, | 50 | .data = &init_net.ipv6.sysctl.fwmark_reflect, |
| 44 | .maxlen = sizeof(int), | 51 | .maxlen = sizeof(int), |
| @@ -74,6 +81,8 @@ static int __net_init ipv6_sysctl_net_init(struct net *net) | |||
| 74 | ipv6_table[0].data = &net->ipv6.sysctl.bindv6only; | 81 | ipv6_table[0].data = &net->ipv6.sysctl.bindv6only; |
| 75 | ipv6_table[1].data = &net->ipv6.sysctl.anycast_src_echo_reply; | 82 | ipv6_table[1].data = &net->ipv6.sysctl.anycast_src_echo_reply; |
| 76 | ipv6_table[2].data = &net->ipv6.sysctl.flowlabel_consistency; | 83 | ipv6_table[2].data = &net->ipv6.sysctl.flowlabel_consistency; |
| 84 | ipv6_table[3].data = &net->ipv6.sysctl.auto_flowlabels; | ||
| 85 | ipv6_table[4].data = &net->ipv6.sysctl.fwmark_reflect; | ||
| 77 | 86 | ||
| 78 | ipv6_route_table = ipv6_route_sysctl_init(net); | 87 | ipv6_route_table = ipv6_route_sysctl_init(net); |
| 79 | if (!ipv6_route_table) | 88 | if (!ipv6_route_table) |
diff --git a/net/ipv6/tcp_ipv6.c b/net/ipv6/tcp_ipv6.c index 229239ad96b1..29964c3d363c 100644 --- a/net/ipv6/tcp_ipv6.c +++ b/net/ipv6/tcp_ipv6.c | |||
| @@ -198,6 +198,8 @@ static int tcp_v6_connect(struct sock *sk, struct sockaddr *uaddr, | |||
| 198 | sk->sk_v6_daddr = usin->sin6_addr; | 198 | sk->sk_v6_daddr = usin->sin6_addr; |
| 199 | np->flow_label = fl6.flowlabel; | 199 | np->flow_label = fl6.flowlabel; |
| 200 | 200 | ||
| 201 | ip6_set_txhash(sk); | ||
| 202 | |||
| 201 | /* | 203 | /* |
| 202 | * TCP over IPv4 | 204 | * TCP over IPv4 |
| 203 | */ | 205 | */ |
| @@ -470,13 +472,14 @@ out: | |||
| 470 | 472 | ||
| 471 | 473 | ||
| 472 | static int tcp_v6_send_synack(struct sock *sk, struct dst_entry *dst, | 474 | static int tcp_v6_send_synack(struct sock *sk, struct dst_entry *dst, |
| 473 | struct flowi6 *fl6, | 475 | struct flowi *fl, |
| 474 | struct request_sock *req, | 476 | struct request_sock *req, |
| 475 | u16 queue_mapping, | 477 | u16 queue_mapping, |
| 476 | struct tcp_fastopen_cookie *foc) | 478 | struct tcp_fastopen_cookie *foc) |
| 477 | { | 479 | { |
| 478 | struct inet_request_sock *ireq = inet_rsk(req); | 480 | struct inet_request_sock *ireq = inet_rsk(req); |
| 479 | struct ipv6_pinfo *np = inet6_sk(sk); | 481 | struct ipv6_pinfo *np = inet6_sk(sk); |
| 482 | struct flowi6 *fl6 = &fl->u.ip6; | ||
| 480 | struct sk_buff *skb; | 483 | struct sk_buff *skb; |
| 481 | int err = -ENOMEM; | 484 | int err = -ENOMEM; |
| 482 | 485 | ||
| @@ -503,18 +506,6 @@ done: | |||
| 503 | return err; | 506 | return err; |
| 504 | } | 507 | } |
| 505 | 508 | ||
| 506 | static int tcp_v6_rtx_synack(struct sock *sk, struct request_sock *req) | ||
| 507 | { | ||
| 508 | struct flowi6 fl6; | ||
| 509 | int res; | ||
| 510 | |||
| 511 | res = tcp_v6_send_synack(sk, NULL, &fl6, req, 0, NULL); | ||
| 512 | if (!res) { | ||
| 513 | TCP_INC_STATS_BH(sock_net(sk), TCP_MIB_RETRANSSEGS); | ||
| 514 | NET_INC_STATS_BH(sock_net(sk), LINUX_MIB_TCPSYNRETRANS); | ||
| 515 | } | ||
| 516 | return res; | ||
| 517 | } | ||
| 518 | 509 | ||
| 519 | static void tcp_v6_reqsk_destructor(struct request_sock *req) | 510 | static void tcp_v6_reqsk_destructor(struct request_sock *req) |
| 520 | { | 511 | { |
| @@ -676,7 +667,8 @@ clear_hash_noput: | |||
| 676 | return 1; | 667 | return 1; |
| 677 | } | 668 | } |
| 678 | 669 | ||
| 679 | static int tcp_v6_inbound_md5_hash(struct sock *sk, const struct sk_buff *skb) | 670 | static int __tcp_v6_inbound_md5_hash(struct sock *sk, |
| 671 | const struct sk_buff *skb) | ||
| 680 | { | 672 | { |
| 681 | const __u8 *hash_location = NULL; | 673 | const __u8 *hash_location = NULL; |
| 682 | struct tcp_md5sig_key *hash_expected; | 674 | struct tcp_md5sig_key *hash_expected; |
| @@ -716,24 +708,80 @@ static int tcp_v6_inbound_md5_hash(struct sock *sk, const struct sk_buff *skb) | |||
| 716 | } | 708 | } |
| 717 | return 0; | 709 | return 0; |
| 718 | } | 710 | } |
| 711 | |||
| 712 | static int tcp_v6_inbound_md5_hash(struct sock *sk, const struct sk_buff *skb) | ||
| 713 | { | ||
| 714 | int ret; | ||
| 715 | |||
| 716 | rcu_read_lock(); | ||
| 717 | ret = __tcp_v6_inbound_md5_hash(sk, skb); | ||
| 718 | rcu_read_unlock(); | ||
| 719 | |||
| 720 | return ret; | ||
| 721 | } | ||
| 722 | |||
| 719 | #endif | 723 | #endif |
| 720 | 724 | ||
| 725 | static void tcp_v6_init_req(struct request_sock *req, struct sock *sk, | ||
| 726 | struct sk_buff *skb) | ||
| 727 | { | ||
| 728 | struct inet_request_sock *ireq = inet_rsk(req); | ||
| 729 | struct ipv6_pinfo *np = inet6_sk(sk); | ||
| 730 | |||
| 731 | ireq->ir_v6_rmt_addr = ipv6_hdr(skb)->saddr; | ||
| 732 | ireq->ir_v6_loc_addr = ipv6_hdr(skb)->daddr; | ||
| 733 | |||
| 734 | ireq->ir_iif = sk->sk_bound_dev_if; | ||
| 735 | |||
| 736 | /* So that link locals have meaning */ | ||
| 737 | if (!sk->sk_bound_dev_if && | ||
| 738 | ipv6_addr_type(&ireq->ir_v6_rmt_addr) & IPV6_ADDR_LINKLOCAL) | ||
| 739 | ireq->ir_iif = inet6_iif(skb); | ||
| 740 | |||
| 741 | if (!TCP_SKB_CB(skb)->when && | ||
| 742 | (ipv6_opt_accepted(sk, skb) || np->rxopt.bits.rxinfo || | ||
| 743 | np->rxopt.bits.rxoinfo || np->rxopt.bits.rxhlim || | ||
| 744 | np->rxopt.bits.rxohlim || np->repflow)) { | ||
| 745 | atomic_inc(&skb->users); | ||
| 746 | ireq->pktopts = skb; | ||
| 747 | } | ||
| 748 | } | ||
| 749 | |||
| 750 | static struct dst_entry *tcp_v6_route_req(struct sock *sk, struct flowi *fl, | ||
| 751 | const struct request_sock *req, | ||
| 752 | bool *strict) | ||
| 753 | { | ||
| 754 | if (strict) | ||
| 755 | *strict = true; | ||
| 756 | return inet6_csk_route_req(sk, &fl->u.ip6, req); | ||
| 757 | } | ||
| 758 | |||
| 721 | struct request_sock_ops tcp6_request_sock_ops __read_mostly = { | 759 | struct request_sock_ops tcp6_request_sock_ops __read_mostly = { |
| 722 | .family = AF_INET6, | 760 | .family = AF_INET6, |
| 723 | .obj_size = sizeof(struct tcp6_request_sock), | 761 | .obj_size = sizeof(struct tcp6_request_sock), |
| 724 | .rtx_syn_ack = tcp_v6_rtx_synack, | 762 | .rtx_syn_ack = tcp_rtx_synack, |
| 725 | .send_ack = tcp_v6_reqsk_send_ack, | 763 | .send_ack = tcp_v6_reqsk_send_ack, |
| 726 | .destructor = tcp_v6_reqsk_destructor, | 764 | .destructor = tcp_v6_reqsk_destructor, |
| 727 | .send_reset = tcp_v6_send_reset, | 765 | .send_reset = tcp_v6_send_reset, |
| 728 | .syn_ack_timeout = tcp_syn_ack_timeout, | 766 | .syn_ack_timeout = tcp_syn_ack_timeout, |
| 729 | }; | 767 | }; |
| 730 | 768 | ||
| 731 | #ifdef CONFIG_TCP_MD5SIG | ||
| 732 | static const struct tcp_request_sock_ops tcp_request_sock_ipv6_ops = { | 769 | static const struct tcp_request_sock_ops tcp_request_sock_ipv6_ops = { |
| 770 | .mss_clamp = IPV6_MIN_MTU - sizeof(struct tcphdr) - | ||
| 771 | sizeof(struct ipv6hdr), | ||
| 772 | #ifdef CONFIG_TCP_MD5SIG | ||
| 733 | .md5_lookup = tcp_v6_reqsk_md5_lookup, | 773 | .md5_lookup = tcp_v6_reqsk_md5_lookup, |
| 734 | .calc_md5_hash = tcp_v6_md5_hash_skb, | 774 | .calc_md5_hash = tcp_v6_md5_hash_skb, |
| 735 | }; | ||
| 736 | #endif | 775 | #endif |
| 776 | .init_req = tcp_v6_init_req, | ||
| 777 | #ifdef CONFIG_SYN_COOKIES | ||
| 778 | .cookie_init_seq = cookie_v6_init_sequence, | ||
| 779 | #endif | ||
| 780 | .route_req = tcp_v6_route_req, | ||
| 781 | .init_seq = tcp_v6_init_sequence, | ||
| 782 | .send_synack = tcp_v6_send_synack, | ||
| 783 | .queue_hash_add = inet6_csk_reqsk_queue_hash_add, | ||
| 784 | }; | ||
| 737 | 785 | ||
| 738 | static void tcp_v6_send_response(struct sk_buff *skb, u32 seq, u32 ack, u32 win, | 786 | static void tcp_v6_send_response(struct sk_buff *skb, u32 seq, u32 ack, u32 win, |
| 739 | u32 tsval, u32 tsecr, int oif, | 787 | u32 tsval, u32 tsecr, int oif, |
| @@ -973,153 +1021,17 @@ static struct sock *tcp_v6_hnd_req(struct sock *sk, struct sk_buff *skb) | |||
| 973 | return sk; | 1021 | return sk; |
| 974 | } | 1022 | } |
| 975 | 1023 | ||
| 976 | /* FIXME: this is substantially similar to the ipv4 code. | ||
| 977 | * Can some kind of merge be done? -- erics | ||
| 978 | */ | ||
| 979 | static int tcp_v6_conn_request(struct sock *sk, struct sk_buff *skb) | 1024 | static int tcp_v6_conn_request(struct sock *sk, struct sk_buff *skb) |
| 980 | { | 1025 | { |
| 981 | struct tcp_options_received tmp_opt; | ||
| 982 | struct request_sock *req; | ||
| 983 | struct inet_request_sock *ireq; | ||
| 984 | struct ipv6_pinfo *np = inet6_sk(sk); | ||
| 985 | struct tcp_sock *tp = tcp_sk(sk); | ||
| 986 | __u32 isn = TCP_SKB_CB(skb)->when; | ||
| 987 | struct dst_entry *dst = NULL; | ||
| 988 | struct tcp_fastopen_cookie foc = { .len = -1 }; | ||
| 989 | bool want_cookie = false, fastopen; | ||
| 990 | struct flowi6 fl6; | ||
| 991 | int err; | ||
| 992 | |||
| 993 | if (skb->protocol == htons(ETH_P_IP)) | 1026 | if (skb->protocol == htons(ETH_P_IP)) |
| 994 | return tcp_v4_conn_request(sk, skb); | 1027 | return tcp_v4_conn_request(sk, skb); |
| 995 | 1028 | ||
| 996 | if (!ipv6_unicast_destination(skb)) | 1029 | if (!ipv6_unicast_destination(skb)) |
| 997 | goto drop; | 1030 | goto drop; |
| 998 | 1031 | ||
| 999 | if ((sysctl_tcp_syncookies == 2 || | 1032 | return tcp_conn_request(&tcp6_request_sock_ops, |
| 1000 | inet_csk_reqsk_queue_is_full(sk)) && !isn) { | 1033 | &tcp_request_sock_ipv6_ops, sk, skb); |
| 1001 | want_cookie = tcp_syn_flood_action(sk, skb, "TCPv6"); | ||
| 1002 | if (!want_cookie) | ||
| 1003 | goto drop; | ||
| 1004 | } | ||
| 1005 | |||
| 1006 | if (sk_acceptq_is_full(sk) && inet_csk_reqsk_queue_young(sk) > 1) { | ||
| 1007 | NET_INC_STATS_BH(sock_net(sk), LINUX_MIB_LISTENOVERFLOWS); | ||
| 1008 | goto drop; | ||
| 1009 | } | ||
| 1010 | |||
| 1011 | req = inet6_reqsk_alloc(&tcp6_request_sock_ops); | ||
| 1012 | if (req == NULL) | ||
| 1013 | goto drop; | ||
| 1014 | |||
| 1015 | #ifdef CONFIG_TCP_MD5SIG | ||
| 1016 | tcp_rsk(req)->af_specific = &tcp_request_sock_ipv6_ops; | ||
| 1017 | #endif | ||
| 1018 | |||
| 1019 | tcp_clear_options(&tmp_opt); | ||
| 1020 | tmp_opt.mss_clamp = IPV6_MIN_MTU - sizeof(struct tcphdr) - sizeof(struct ipv6hdr); | ||
| 1021 | tmp_opt.user_mss = tp->rx_opt.user_mss; | ||
| 1022 | tcp_parse_options(skb, &tmp_opt, 0, want_cookie ? NULL : &foc); | ||
| 1023 | |||
| 1024 | if (want_cookie && !tmp_opt.saw_tstamp) | ||
| 1025 | tcp_clear_options(&tmp_opt); | ||
| 1026 | |||
| 1027 | tmp_opt.tstamp_ok = tmp_opt.saw_tstamp; | ||
| 1028 | tcp_openreq_init(req, &tmp_opt, skb); | ||
| 1029 | |||
| 1030 | ireq = inet_rsk(req); | ||
| 1031 | ireq->ir_v6_rmt_addr = ipv6_hdr(skb)->saddr; | ||
| 1032 | ireq->ir_v6_loc_addr = ipv6_hdr(skb)->daddr; | ||
| 1033 | if (!want_cookie || tmp_opt.tstamp_ok) | ||
| 1034 | TCP_ECN_create_request(req, skb, sock_net(sk)); | ||
| 1035 | |||
| 1036 | ireq->ir_iif = sk->sk_bound_dev_if; | ||
| 1037 | ireq->ir_mark = inet_request_mark(sk, skb); | ||
| 1038 | |||
| 1039 | /* So that link locals have meaning */ | ||
| 1040 | if (!sk->sk_bound_dev_if && | ||
| 1041 | ipv6_addr_type(&ireq->ir_v6_rmt_addr) & IPV6_ADDR_LINKLOCAL) | ||
| 1042 | ireq->ir_iif = inet6_iif(skb); | ||
| 1043 | |||
| 1044 | if (!isn) { | ||
| 1045 | if (ipv6_opt_accepted(sk, skb) || | ||
| 1046 | np->rxopt.bits.rxinfo || np->rxopt.bits.rxoinfo || | ||
| 1047 | np->rxopt.bits.rxhlim || np->rxopt.bits.rxohlim || | ||
| 1048 | np->repflow) { | ||
| 1049 | atomic_inc(&skb->users); | ||
| 1050 | ireq->pktopts = skb; | ||
| 1051 | } | ||
| 1052 | 1034 | ||
| 1053 | if (want_cookie) { | ||
| 1054 | isn = cookie_v6_init_sequence(sk, skb, &req->mss); | ||
| 1055 | req->cookie_ts = tmp_opt.tstamp_ok; | ||
| 1056 | goto have_isn; | ||
| 1057 | } | ||
| 1058 | |||
| 1059 | /* VJ's idea. We save last timestamp seen | ||
| 1060 | * from the destination in peer table, when entering | ||
| 1061 | * state TIME-WAIT, and check against it before | ||
| 1062 | * accepting new connection request. | ||
| 1063 | * | ||
| 1064 | * If "isn" is not zero, this request hit alive | ||
| 1065 | * timewait bucket, so that all the necessary checks | ||
| 1066 | * are made in the function processing timewait state. | ||
| 1067 | */ | ||
| 1068 | if (tmp_opt.saw_tstamp && | ||
| 1069 | tcp_death_row.sysctl_tw_recycle && | ||
| 1070 | (dst = inet6_csk_route_req(sk, &fl6, req)) != NULL) { | ||
| 1071 | if (!tcp_peer_is_proven(req, dst, true)) { | ||
| 1072 | NET_INC_STATS_BH(sock_net(sk), LINUX_MIB_PAWSPASSIVEREJECTED); | ||
| 1073 | goto drop_and_release; | ||
| 1074 | } | ||
| 1075 | } | ||
| 1076 | /* Kill the following clause, if you dislike this way. */ | ||
| 1077 | else if (!sysctl_tcp_syncookies && | ||
| 1078 | (sysctl_max_syn_backlog - inet_csk_reqsk_queue_len(sk) < | ||
| 1079 | (sysctl_max_syn_backlog >> 2)) && | ||
| 1080 | !tcp_peer_is_proven(req, dst, false)) { | ||
| 1081 | /* Without syncookies last quarter of | ||
| 1082 | * backlog is filled with destinations, | ||
| 1083 | * proven to be alive. | ||
| 1084 | * It means that we continue to communicate | ||
| 1085 | * to destinations, already remembered | ||
| 1086 | * to the moment of synflood. | ||
| 1087 | */ | ||
| 1088 | LIMIT_NETDEBUG(KERN_DEBUG "TCP: drop open request from %pI6/%u\n", | ||
| 1089 | &ireq->ir_v6_rmt_addr, ntohs(tcp_hdr(skb)->source)); | ||
| 1090 | goto drop_and_release; | ||
| 1091 | } | ||
| 1092 | |||
| 1093 | isn = tcp_v6_init_sequence(skb); | ||
| 1094 | } | ||
| 1095 | have_isn: | ||
| 1096 | |||
| 1097 | if (security_inet_conn_request(sk, skb, req)) | ||
| 1098 | goto drop_and_release; | ||
| 1099 | |||
| 1100 | if (!dst && (dst = inet6_csk_route_req(sk, &fl6, req)) == NULL) | ||
| 1101 | goto drop_and_free; | ||
| 1102 | |||
| 1103 | tcp_rsk(req)->snt_isn = isn; | ||
| 1104 | tcp_rsk(req)->snt_synack = tcp_time_stamp; | ||
| 1105 | tcp_openreq_init_rwin(req, sk, dst); | ||
| 1106 | fastopen = !want_cookie && | ||
| 1107 | tcp_try_fastopen(sk, skb, req, &foc, dst); | ||
| 1108 | err = tcp_v6_send_synack(sk, dst, &fl6, req, | ||
| 1109 | skb_get_queue_mapping(skb), &foc); | ||
| 1110 | if (!fastopen) { | ||
| 1111 | if (err || want_cookie) | ||
| 1112 | goto drop_and_free; | ||
| 1113 | |||
| 1114 | tcp_rsk(req)->listener = NULL; | ||
| 1115 | inet6_csk_reqsk_queue_hash_add(sk, req, TCP_TIMEOUT_INIT); | ||
| 1116 | } | ||
| 1117 | return 0; | ||
| 1118 | |||
| 1119 | drop_and_release: | ||
| 1120 | dst_release(dst); | ||
| 1121 | drop_and_free: | ||
| 1122 | reqsk_free(req); | ||
| 1123 | drop: | 1035 | drop: |
| 1124 | NET_INC_STATS_BH(sock_net(sk), LINUX_MIB_LISTENDROPS); | 1036 | NET_INC_STATS_BH(sock_net(sk), LINUX_MIB_LISTENDROPS); |
| 1125 | return 0; /* don't send reset */ | 1037 | return 0; /* don't send reset */ |
| @@ -1235,6 +1147,8 @@ static struct sock *tcp_v6_syn_recv_sock(struct sock *sk, struct sk_buff *skb, | |||
| 1235 | newsk->sk_v6_rcv_saddr = ireq->ir_v6_loc_addr; | 1147 | newsk->sk_v6_rcv_saddr = ireq->ir_v6_loc_addr; |
| 1236 | newsk->sk_bound_dev_if = ireq->ir_iif; | 1148 | newsk->sk_bound_dev_if = ireq->ir_iif; |
| 1237 | 1149 | ||
| 1150 | ip6_set_txhash(newsk); | ||
| 1151 | |||
| 1238 | /* Now IPv6 options... | 1152 | /* Now IPv6 options... |
| 1239 | 1153 | ||
| 1240 | First: no IPv4 options. | 1154 | First: no IPv4 options. |
| @@ -1346,11 +1260,6 @@ static int tcp_v6_do_rcv(struct sock *sk, struct sk_buff *skb) | |||
| 1346 | if (skb->protocol == htons(ETH_P_IP)) | 1260 | if (skb->protocol == htons(ETH_P_IP)) |
| 1347 | return tcp_v4_do_rcv(sk, skb); | 1261 | return tcp_v4_do_rcv(sk, skb); |
| 1348 | 1262 | ||
| 1349 | #ifdef CONFIG_TCP_MD5SIG | ||
| 1350 | if (tcp_v6_inbound_md5_hash(sk, skb)) | ||
| 1351 | goto discard; | ||
| 1352 | #endif | ||
| 1353 | |||
| 1354 | if (sk_filter(sk, skb)) | 1263 | if (sk_filter(sk, skb)) |
| 1355 | goto discard; | 1264 | goto discard; |
| 1356 | 1265 | ||
| @@ -1523,6 +1432,11 @@ process: | |||
| 1523 | if (!xfrm6_policy_check(sk, XFRM_POLICY_IN, skb)) | 1432 | if (!xfrm6_policy_check(sk, XFRM_POLICY_IN, skb)) |
| 1524 | goto discard_and_relse; | 1433 | goto discard_and_relse; |
| 1525 | 1434 | ||
| 1435 | #ifdef CONFIG_TCP_MD5SIG | ||
| 1436 | if (tcp_v6_inbound_md5_hash(sk, skb)) | ||
| 1437 | goto discard_and_relse; | ||
| 1438 | #endif | ||
| 1439 | |||
| 1526 | if (sk_filter(sk, skb)) | 1440 | if (sk_filter(sk, skb)) |
| 1527 | goto discard_and_relse; | 1441 | goto discard_and_relse; |
| 1528 | 1442 | ||
| @@ -1681,6 +1595,7 @@ static const struct inet_connection_sock_af_ops ipv6_specific = { | |||
| 1681 | .compat_setsockopt = compat_ipv6_setsockopt, | 1595 | .compat_setsockopt = compat_ipv6_setsockopt, |
| 1682 | .compat_getsockopt = compat_ipv6_getsockopt, | 1596 | .compat_getsockopt = compat_ipv6_getsockopt, |
| 1683 | #endif | 1597 | #endif |
| 1598 | .mtu_reduced = tcp_v6_mtu_reduced, | ||
| 1684 | }; | 1599 | }; |
| 1685 | 1600 | ||
| 1686 | #ifdef CONFIG_TCP_MD5SIG | 1601 | #ifdef CONFIG_TCP_MD5SIG |
| @@ -1711,6 +1626,7 @@ static const struct inet_connection_sock_af_ops ipv6_mapped = { | |||
| 1711 | .compat_setsockopt = compat_ipv6_setsockopt, | 1626 | .compat_setsockopt = compat_ipv6_setsockopt, |
| 1712 | .compat_getsockopt = compat_ipv6_getsockopt, | 1627 | .compat_getsockopt = compat_ipv6_getsockopt, |
| 1713 | #endif | 1628 | #endif |
| 1629 | .mtu_reduced = tcp_v4_mtu_reduced, | ||
| 1714 | }; | 1630 | }; |
| 1715 | 1631 | ||
| 1716 | #ifdef CONFIG_TCP_MD5SIG | 1632 | #ifdef CONFIG_TCP_MD5SIG |
| @@ -1950,7 +1866,6 @@ struct proto tcpv6_prot = { | |||
| 1950 | .sendpage = tcp_sendpage, | 1866 | .sendpage = tcp_sendpage, |
| 1951 | .backlog_rcv = tcp_v6_do_rcv, | 1867 | .backlog_rcv = tcp_v6_do_rcv, |
| 1952 | .release_cb = tcp_release_cb, | 1868 | .release_cb = tcp_release_cb, |
| 1953 | .mtu_reduced = tcp_v6_mtu_reduced, | ||
| 1954 | .hash = tcp_v6_hash, | 1869 | .hash = tcp_v6_hash, |
| 1955 | .unhash = inet_unhash, | 1870 | .unhash = inet_unhash, |
| 1956 | .get_port = inet_csk_get_port, | 1871 | .get_port = inet_csk_get_port, |
diff --git a/net/ipv6/udp.c b/net/ipv6/udp.c index 7092ff78fd84..4836af8f582d 100644 --- a/net/ipv6/udp.c +++ b/net/ipv6/udp.c | |||
| @@ -79,7 +79,6 @@ static unsigned int udp6_ehashfn(struct net *net, | |||
| 79 | int ipv6_rcv_saddr_equal(const struct sock *sk, const struct sock *sk2) | 79 | int ipv6_rcv_saddr_equal(const struct sock *sk, const struct sock *sk2) |
| 80 | { | 80 | { |
| 81 | const struct in6_addr *sk2_rcv_saddr6 = inet6_rcv_saddr(sk2); | 81 | const struct in6_addr *sk2_rcv_saddr6 = inet6_rcv_saddr(sk2); |
| 82 | int sk_ipv6only = ipv6_only_sock(sk); | ||
| 83 | int sk2_ipv6only = inet_v6_ipv6only(sk2); | 82 | int sk2_ipv6only = inet_v6_ipv6only(sk2); |
| 84 | int addr_type = ipv6_addr_type(&sk->sk_v6_rcv_saddr); | 83 | int addr_type = ipv6_addr_type(&sk->sk_v6_rcv_saddr); |
| 85 | int addr_type2 = sk2_rcv_saddr6 ? ipv6_addr_type(sk2_rcv_saddr6) : IPV6_ADDR_MAPPED; | 84 | int addr_type2 = sk2_rcv_saddr6 ? ipv6_addr_type(sk2_rcv_saddr6) : IPV6_ADDR_MAPPED; |
| @@ -95,7 +94,7 @@ int ipv6_rcv_saddr_equal(const struct sock *sk, const struct sock *sk2) | |||
| 95 | return 1; | 94 | return 1; |
| 96 | 95 | ||
| 97 | if (addr_type == IPV6_ADDR_ANY && | 96 | if (addr_type == IPV6_ADDR_ANY && |
| 98 | !(sk_ipv6only && addr_type2 == IPV6_ADDR_MAPPED)) | 97 | !(ipv6_only_sock(sk) && addr_type2 == IPV6_ADDR_MAPPED)) |
| 99 | return 1; | 98 | return 1; |
| 100 | 99 | ||
| 101 | if (sk2_rcv_saddr6 && | 100 | if (sk2_rcv_saddr6 && |
| @@ -473,7 +472,7 @@ try_again: | |||
| 473 | sin6->sin6_addr = ipv6_hdr(skb)->saddr; | 472 | sin6->sin6_addr = ipv6_hdr(skb)->saddr; |
| 474 | sin6->sin6_scope_id = | 473 | sin6->sin6_scope_id = |
| 475 | ipv6_iface_scope_id(&sin6->sin6_addr, | 474 | ipv6_iface_scope_id(&sin6->sin6_addr, |
| 476 | IP6CB(skb)->iif); | 475 | inet6_iif(skb)); |
| 477 | } | 476 | } |
| 478 | *addr_len = sizeof(*sin6); | 477 | *addr_len = sizeof(*sin6); |
| 479 | } | 478 | } |
| @@ -534,11 +533,15 @@ void __udp6_lib_err(struct sk_buff *skb, struct inet6_skb_parm *opt, | |||
| 534 | struct udphdr *uh = (struct udphdr*)(skb->data+offset); | 533 | struct udphdr *uh = (struct udphdr*)(skb->data+offset); |
| 535 | struct sock *sk; | 534 | struct sock *sk; |
| 536 | int err; | 535 | int err; |
| 536 | struct net *net = dev_net(skb->dev); | ||
| 537 | 537 | ||
| 538 | sk = __udp6_lib_lookup(dev_net(skb->dev), daddr, uh->dest, | 538 | sk = __udp6_lib_lookup(net, daddr, uh->dest, |
| 539 | saddr, uh->source, inet6_iif(skb), udptable); | 539 | saddr, uh->source, inet6_iif(skb), udptable); |
| 540 | if (sk == NULL) | 540 | if (sk == NULL) { |
| 541 | ICMP6_INC_STATS_BH(net, __in6_dev_get(skb->dev), | ||
| 542 | ICMP6_MIB_INERRORS); | ||
| 541 | return; | 543 | return; |
| 544 | } | ||
| 542 | 545 | ||
| 543 | if (type == ICMPV6_PKT_TOOBIG) { | 546 | if (type == ICMPV6_PKT_TOOBIG) { |
| 544 | if (!ip6_sk_accept_pmtu(sk)) | 547 | if (!ip6_sk_accept_pmtu(sk)) |
| @@ -674,7 +677,7 @@ int udpv6_queue_rcv_skb(struct sock *sk, struct sk_buff *skb) | |||
| 674 | goto csum_error; | 677 | goto csum_error; |
| 675 | } | 678 | } |
| 676 | 679 | ||
| 677 | if (sk_rcvqueues_full(sk, skb, sk->sk_rcvbuf)) { | 680 | if (sk_rcvqueues_full(sk, sk->sk_rcvbuf)) { |
| 678 | UDP6_INC_STATS_BH(sock_net(sk), | 681 | UDP6_INC_STATS_BH(sock_net(sk), |
| 679 | UDP_MIB_RCVBUFERRORS, is_udplite); | 682 | UDP_MIB_RCVBUFERRORS, is_udplite); |
| 680 | goto drop; | 683 | goto drop; |
| @@ -703,43 +706,26 @@ drop: | |||
| 703 | return -1; | 706 | return -1; |
| 704 | } | 707 | } |
| 705 | 708 | ||
| 706 | static struct sock *udp_v6_mcast_next(struct net *net, struct sock *sk, | 709 | static bool __udp_v6_is_mcast_sock(struct net *net, struct sock *sk, |
| 707 | __be16 loc_port, const struct in6_addr *loc_addr, | 710 | __be16 loc_port, const struct in6_addr *loc_addr, |
| 708 | __be16 rmt_port, const struct in6_addr *rmt_addr, | 711 | __be16 rmt_port, const struct in6_addr *rmt_addr, |
| 709 | int dif) | 712 | int dif, unsigned short hnum) |
| 710 | { | 713 | { |
| 711 | struct hlist_nulls_node *node; | 714 | struct inet_sock *inet = inet_sk(sk); |
| 712 | unsigned short num = ntohs(loc_port); | ||
| 713 | |||
| 714 | sk_nulls_for_each_from(sk, node) { | ||
| 715 | struct inet_sock *inet = inet_sk(sk); | ||
| 716 | |||
| 717 | if (!net_eq(sock_net(sk), net)) | ||
| 718 | continue; | ||
| 719 | |||
| 720 | if (udp_sk(sk)->udp_port_hash == num && | ||
| 721 | sk->sk_family == PF_INET6) { | ||
| 722 | if (inet->inet_dport) { | ||
| 723 | if (inet->inet_dport != rmt_port) | ||
| 724 | continue; | ||
| 725 | } | ||
| 726 | if (!ipv6_addr_any(&sk->sk_v6_daddr) && | ||
| 727 | !ipv6_addr_equal(&sk->sk_v6_daddr, rmt_addr)) | ||
| 728 | continue; | ||
| 729 | |||
| 730 | if (sk->sk_bound_dev_if && sk->sk_bound_dev_if != dif) | ||
| 731 | continue; | ||
| 732 | 715 | ||
| 733 | if (!ipv6_addr_any(&sk->sk_v6_rcv_saddr)) { | 716 | if (!net_eq(sock_net(sk), net)) |
| 734 | if (!ipv6_addr_equal(&sk->sk_v6_rcv_saddr, loc_addr)) | 717 | return false; |
| 735 | continue; | 718 | |
| 736 | } | 719 | if (udp_sk(sk)->udp_port_hash != hnum || |
| 737 | if (!inet6_mc_check(sk, loc_addr, rmt_addr)) | 720 | sk->sk_family != PF_INET6 || |
| 738 | continue; | 721 | (inet->inet_dport && inet->inet_dport != rmt_port) || |
| 739 | return sk; | 722 | (!ipv6_addr_any(&sk->sk_v6_daddr) && |
| 740 | } | 723 | !ipv6_addr_equal(&sk->sk_v6_daddr, rmt_addr)) || |
| 741 | } | 724 | (sk->sk_bound_dev_if && sk->sk_bound_dev_if != dif)) |
| 742 | return NULL; | 725 | return false; |
| 726 | if (!inet6_mc_check(sk, loc_addr, rmt_addr)) | ||
| 727 | return false; | ||
| 728 | return true; | ||
| 743 | } | 729 | } |
| 744 | 730 | ||
| 745 | static void flush_stack(struct sock **stack, unsigned int count, | 731 | static void flush_stack(struct sock **stack, unsigned int count, |
| @@ -763,6 +749,7 @@ static void flush_stack(struct sock **stack, unsigned int count, | |||
| 763 | 749 | ||
| 764 | if (skb1 && udpv6_queue_rcv_skb(sk, skb1) <= 0) | 750 | if (skb1 && udpv6_queue_rcv_skb(sk, skb1) <= 0) |
| 765 | skb1 = NULL; | 751 | skb1 = NULL; |
| 752 | sock_put(sk); | ||
| 766 | } | 753 | } |
| 767 | if (unlikely(skb1)) | 754 | if (unlikely(skb1)) |
| 768 | kfree_skb(skb1); | 755 | kfree_skb(skb1); |
| @@ -788,43 +775,51 @@ static int __udp6_lib_mcast_deliver(struct net *net, struct sk_buff *skb, | |||
| 788 | { | 775 | { |
| 789 | struct sock *sk, *stack[256 / sizeof(struct sock *)]; | 776 | struct sock *sk, *stack[256 / sizeof(struct sock *)]; |
| 790 | const struct udphdr *uh = udp_hdr(skb); | 777 | const struct udphdr *uh = udp_hdr(skb); |
| 791 | struct udp_hslot *hslot = udp_hashslot(udptable, net, ntohs(uh->dest)); | 778 | struct hlist_nulls_node *node; |
| 792 | int dif; | 779 | unsigned short hnum = ntohs(uh->dest); |
| 793 | unsigned int i, count = 0; | 780 | struct udp_hslot *hslot = udp_hashslot(udptable, net, hnum); |
| 781 | int dif = inet6_iif(skb); | ||
| 782 | unsigned int count = 0, offset = offsetof(typeof(*sk), sk_nulls_node); | ||
| 783 | unsigned int hash2 = 0, hash2_any = 0, use_hash2 = (hslot->count > 10); | ||
| 784 | |||
| 785 | if (use_hash2) { | ||
| 786 | hash2_any = udp6_portaddr_hash(net, &in6addr_any, hnum) & | ||
| 787 | udp_table.mask; | ||
| 788 | hash2 = udp6_portaddr_hash(net, daddr, hnum) & udp_table.mask; | ||
| 789 | start_lookup: | ||
| 790 | hslot = &udp_table.hash2[hash2]; | ||
| 791 | offset = offsetof(typeof(*sk), __sk_common.skc_portaddr_node); | ||
| 792 | } | ||
| 794 | 793 | ||
| 795 | spin_lock(&hslot->lock); | 794 | spin_lock(&hslot->lock); |
| 796 | sk = sk_nulls_head(&hslot->head); | 795 | sk_nulls_for_each_entry_offset(sk, node, &hslot->head, offset) { |
| 797 | dif = inet6_iif(skb); | 796 | if (__udp_v6_is_mcast_sock(net, sk, |
| 798 | sk = udp_v6_mcast_next(net, sk, uh->dest, daddr, uh->source, saddr, dif); | 797 | uh->dest, daddr, |
| 799 | while (sk) { | 798 | uh->source, saddr, |
| 800 | /* If zero checksum and no_check is not on for | 799 | dif, hnum) && |
| 801 | * the socket then skip it. | 800 | /* If zero checksum and no_check is not on for |
| 802 | */ | 801 | * the socket then skip it. |
| 803 | if (uh->check || udp_sk(sk)->no_check6_rx) | 802 | */ |
| 803 | (uh->check || udp_sk(sk)->no_check6_rx)) { | ||
| 804 | if (unlikely(count == ARRAY_SIZE(stack))) { | ||
| 805 | flush_stack(stack, count, skb, ~0); | ||
| 806 | count = 0; | ||
| 807 | } | ||
| 804 | stack[count++] = sk; | 808 | stack[count++] = sk; |
| 805 | 809 | sock_hold(sk); | |
| 806 | sk = udp_v6_mcast_next(net, sk_nulls_next(sk), uh->dest, daddr, | ||
| 807 | uh->source, saddr, dif); | ||
| 808 | if (unlikely(count == ARRAY_SIZE(stack))) { | ||
| 809 | if (!sk) | ||
| 810 | break; | ||
| 811 | flush_stack(stack, count, skb, ~0); | ||
| 812 | count = 0; | ||
| 813 | } | 810 | } |
| 814 | } | 811 | } |
| 815 | /* | ||
| 816 | * before releasing the lock, we must take reference on sockets | ||
| 817 | */ | ||
| 818 | for (i = 0; i < count; i++) | ||
| 819 | sock_hold(stack[i]); | ||
| 820 | 812 | ||
| 821 | spin_unlock(&hslot->lock); | 813 | spin_unlock(&hslot->lock); |
| 822 | 814 | ||
| 815 | /* Also lookup *:port if we are using hash2 and haven't done so yet. */ | ||
| 816 | if (use_hash2 && hash2 != hash2_any) { | ||
| 817 | hash2 = hash2_any; | ||
| 818 | goto start_lookup; | ||
| 819 | } | ||
| 820 | |||
| 823 | if (count) { | 821 | if (count) { |
| 824 | flush_stack(stack, count, skb, count - 1); | 822 | flush_stack(stack, count, skb, count - 1); |
| 825 | |||
| 826 | for (i = 0; i < count; i++) | ||
| 827 | sock_put(stack[i]); | ||
| 828 | } else { | 823 | } else { |
| 829 | kfree_skb(skb); | 824 | kfree_skb(skb); |
| 830 | } | 825 | } |
diff --git a/net/irda/af_irda.c b/net/irda/af_irda.c index 54747c25c86c..92fafd485deb 100644 --- a/net/irda/af_irda.c +++ b/net/irda/af_irda.c | |||
| @@ -674,7 +674,6 @@ static int irda_discover_daddr_and_lsap_sel(struct irda_sock *self, char *name) | |||
| 674 | self->daddr = DEV_ADDR_ANY; | 674 | self->daddr = DEV_ADDR_ANY; |
| 675 | kfree(discoveries); | 675 | kfree(discoveries); |
| 676 | return -EHOSTUNREACH; | 676 | return -EHOSTUNREACH; |
| 677 | break; | ||
| 678 | } | 677 | } |
| 679 | } | 678 | } |
| 680 | /* Cleanup our copy of the discovery log */ | 679 | /* Cleanup our copy of the discovery log */ |
diff --git a/net/irda/ircomm/ircomm_tty.c b/net/irda/ircomm/ircomm_tty.c index 2ba8b9705bb7..61ceb4cdb4a2 100644 --- a/net/irda/ircomm/ircomm_tty.c +++ b/net/irda/ircomm/ircomm_tty.c | |||
| @@ -320,8 +320,7 @@ static int ircomm_tty_block_til_ready(struct ircomm_tty_cb *self, | |||
| 320 | __FILE__, __LINE__, tty->driver->name, port->count); | 320 | __FILE__, __LINE__, tty->driver->name, port->count); |
| 321 | 321 | ||
| 322 | spin_lock_irqsave(&port->lock, flags); | 322 | spin_lock_irqsave(&port->lock, flags); |
| 323 | if (!tty_hung_up_p(filp)) | 323 | port->count--; |
| 324 | port->count--; | ||
| 325 | port->blocked_open++; | 324 | port->blocked_open++; |
| 326 | spin_unlock_irqrestore(&port->lock, flags); | 325 | spin_unlock_irqrestore(&port->lock, flags); |
| 327 | 326 | ||
| @@ -458,8 +457,7 @@ static int ircomm_tty_open(struct tty_struct *tty, struct file *filp) | |||
| 458 | /* | 457 | /* |
| 459 | * If the port is the middle of closing, bail out now | 458 | * If the port is the middle of closing, bail out now |
| 460 | */ | 459 | */ |
| 461 | if (tty_hung_up_p(filp) || | 460 | if (test_bit(ASYNCB_CLOSING, &self->port.flags)) { |
| 462 | test_bit(ASYNCB_CLOSING, &self->port.flags)) { | ||
| 463 | 461 | ||
| 464 | /* Hm, why are we blocking on ASYNC_CLOSING if we | 462 | /* Hm, why are we blocking on ASYNC_CLOSING if we |
| 465 | * do return -EAGAIN/-ERESTARTSYS below anyway? | 463 | * do return -EAGAIN/-ERESTARTSYS below anyway? |
diff --git a/net/irda/irda_device.c b/net/irda/irda_device.c index 365b895da84b..9e0d909390fd 100644 --- a/net/irda/irda_device.c +++ b/net/irda/irda_device.c | |||
| @@ -293,7 +293,8 @@ static void irda_device_setup(struct net_device *dev) | |||
| 293 | */ | 293 | */ |
| 294 | struct net_device *alloc_irdadev(int sizeof_priv) | 294 | struct net_device *alloc_irdadev(int sizeof_priv) |
| 295 | { | 295 | { |
| 296 | return alloc_netdev(sizeof_priv, "irda%d", irda_device_setup); | 296 | return alloc_netdev(sizeof_priv, "irda%d", NET_NAME_UNKNOWN, |
| 297 | irda_device_setup); | ||
| 297 | } | 298 | } |
| 298 | EXPORT_SYMBOL(alloc_irdadev); | 299 | EXPORT_SYMBOL(alloc_irdadev); |
| 299 | 300 | ||
diff --git a/net/irda/irlan/irlan_common.c b/net/irda/irlan/irlan_common.c index 7ac4d1becbfc..1bc49edf2296 100644 --- a/net/irda/irlan/irlan_common.c +++ b/net/irda/irlan/irlan_common.c | |||
| @@ -1024,7 +1024,6 @@ static int __irlan_insert_param(struct sk_buff *skb, char *param, int type, | |||
| 1024 | default: | 1024 | default: |
| 1025 | IRDA_DEBUG(2, "%s(), Unknown parameter type!\n", __func__ ); | 1025 | IRDA_DEBUG(2, "%s(), Unknown parameter type!\n", __func__ ); |
| 1026 | return 0; | 1026 | return 0; |
| 1027 | break; | ||
| 1028 | } | 1027 | } |
| 1029 | 1028 | ||
| 1030 | /* Insert at end of sk-buffer */ | 1029 | /* Insert at end of sk-buffer */ |
diff --git a/net/irda/irlan/irlan_eth.c b/net/irda/irlan/irlan_eth.c index ffcec225b5d9..dc13f1a45f2f 100644 --- a/net/irda/irlan/irlan_eth.c +++ b/net/irda/irlan/irlan_eth.c | |||
| @@ -96,7 +96,7 @@ static void irlan_eth_setup(struct net_device *dev) | |||
| 96 | */ | 96 | */ |
| 97 | struct net_device *alloc_irlandev(const char *name) | 97 | struct net_device *alloc_irlandev(const char *name) |
| 98 | { | 98 | { |
| 99 | return alloc_netdev(sizeof(struct irlan_cb), name, | 99 | return alloc_netdev(sizeof(struct irlan_cb), name, NET_NAME_UNKNOWN, |
| 100 | irlan_eth_setup); | 100 | irlan_eth_setup); |
| 101 | } | 101 | } |
| 102 | 102 | ||
diff --git a/net/irda/irlap_frame.c b/net/irda/irlap_frame.c index 9ea0c933b9ff..a37998c6273d 100644 --- a/net/irda/irlap_frame.c +++ b/net/irda/irlap_frame.c | |||
| @@ -622,7 +622,7 @@ void irlap_send_rd_frame(struct irlap_cb *self) | |||
| 622 | frame = (struct rd_frame *)skb_put(tx_skb, 2); | 622 | frame = (struct rd_frame *)skb_put(tx_skb, 2); |
| 623 | 623 | ||
| 624 | frame->caddr = self->caddr; | 624 | frame->caddr = self->caddr; |
| 625 | frame->caddr = RD_RSP | PF_BIT; | 625 | frame->control = RD_RSP | PF_BIT; |
| 626 | 626 | ||
| 627 | irlap_queue_xmit(self, tx_skb); | 627 | irlap_queue_xmit(self, tx_skb); |
| 628 | } | 628 | } |
diff --git a/net/irda/irlmp.c b/net/irda/irlmp.c index 98ad6ec4bd3c..a5f28d421ea8 100644 --- a/net/irda/irlmp.c +++ b/net/irda/irlmp.c | |||
| @@ -1426,7 +1426,8 @@ __u8 *irlmp_hint_to_service(__u8 *hint) | |||
| 1426 | if (hint[1] & HINT_TELEPHONY) { | 1426 | if (hint[1] & HINT_TELEPHONY) { |
| 1427 | IRDA_DEBUG(1, "Telephony "); | 1427 | IRDA_DEBUG(1, "Telephony "); |
| 1428 | service[i++] = S_TELEPHONY; | 1428 | service[i++] = S_TELEPHONY; |
| 1429 | } if (hint[1] & HINT_FILE_SERVER) | 1429 | } |
| 1430 | if (hint[1] & HINT_FILE_SERVER) | ||
| 1430 | IRDA_DEBUG(1, "File Server "); | 1431 | IRDA_DEBUG(1, "File Server "); |
| 1431 | 1432 | ||
| 1432 | if (hint[1] & HINT_COMM) { | 1433 | if (hint[1] & HINT_COMM) { |
diff --git a/net/iucv/af_iucv.c b/net/iucv/af_iucv.c index 7a95fa4a3de1..a089b6b91650 100644 --- a/net/iucv/af_iucv.c +++ b/net/iucv/af_iucv.c | |||
| @@ -1103,7 +1103,6 @@ static int iucv_sock_sendmsg(struct kiocb *iocb, struct socket *sock, | |||
| 1103 | default: | 1103 | default: |
| 1104 | err = -EINVAL; | 1104 | err = -EINVAL; |
| 1105 | goto out; | 1105 | goto out; |
| 1106 | break; | ||
| 1107 | } | 1106 | } |
| 1108 | } | 1107 | } |
| 1109 | 1108 | ||
| @@ -1543,7 +1542,8 @@ static int iucv_sock_shutdown(struct socket *sock, int how) | |||
| 1543 | 1542 | ||
| 1544 | sk->sk_shutdown |= how; | 1543 | sk->sk_shutdown |= how; |
| 1545 | if (how == RCV_SHUTDOWN || how == SHUTDOWN_MASK) { | 1544 | if (how == RCV_SHUTDOWN || how == SHUTDOWN_MASK) { |
| 1546 | if (iucv->transport == AF_IUCV_TRANS_IUCV) { | 1545 | if ((iucv->transport == AF_IUCV_TRANS_IUCV) && |
| 1546 | iucv->path) { | ||
| 1547 | err = pr_iucv->path_quiesce(iucv->path, NULL); | 1547 | err = pr_iucv->path_quiesce(iucv->path, NULL); |
| 1548 | if (err) | 1548 | if (err) |
| 1549 | err = -ENOTCONN; | 1549 | err = -ENOTCONN; |
diff --git a/net/key/af_key.c b/net/key/af_key.c index ba2a2f95911c..1847ec4e3930 100644 --- a/net/key/af_key.c +++ b/net/key/af_key.c | |||
| @@ -405,7 +405,6 @@ static int verify_address_len(const void *p) | |||
| 405 | * XXX When it can, remove this -EINVAL. -DaveM | 405 | * XXX When it can, remove this -EINVAL. -DaveM |
| 406 | */ | 406 | */ |
| 407 | return -EINVAL; | 407 | return -EINVAL; |
| 408 | break; | ||
| 409 | } | 408 | } |
| 410 | 409 | ||
| 411 | return 0; | 410 | return 0; |
| @@ -536,7 +535,6 @@ pfkey_satype2proto(uint8_t satype) | |||
| 536 | return IPPROTO_ESP; | 535 | return IPPROTO_ESP; |
| 537 | case SADB_X_SATYPE_IPCOMP: | 536 | case SADB_X_SATYPE_IPCOMP: |
| 538 | return IPPROTO_COMP; | 537 | return IPPROTO_COMP; |
| 539 | break; | ||
| 540 | default: | 538 | default: |
| 541 | return 0; | 539 | return 0; |
| 542 | } | 540 | } |
| @@ -553,7 +551,6 @@ pfkey_proto2satype(uint16_t proto) | |||
| 553 | return SADB_SATYPE_ESP; | 551 | return SADB_SATYPE_ESP; |
| 554 | case IPPROTO_COMP: | 552 | case IPPROTO_COMP: |
| 555 | return SADB_X_SATYPE_IPCOMP; | 553 | return SADB_X_SATYPE_IPCOMP; |
| 556 | break; | ||
| 557 | default: | 554 | default: |
| 558 | return 0; | 555 | return 0; |
| 559 | } | 556 | } |
diff --git a/net/l2tp/Kconfig b/net/l2tp/Kconfig index adb9843dd7cf..378c73b26093 100644 --- a/net/l2tp/Kconfig +++ b/net/l2tp/Kconfig | |||
| @@ -6,6 +6,7 @@ menuconfig L2TP | |||
| 6 | tristate "Layer Two Tunneling Protocol (L2TP)" | 6 | tristate "Layer Two Tunneling Protocol (L2TP)" |
| 7 | depends on (IPV6 || IPV6=n) | 7 | depends on (IPV6 || IPV6=n) |
| 8 | depends on INET | 8 | depends on INET |
| 9 | select NET_UDP_TUNNEL | ||
| 9 | ---help--- | 10 | ---help--- |
| 10 | Layer Two Tunneling Protocol | 11 | Layer Two Tunneling Protocol |
| 11 | 12 | ||
diff --git a/net/l2tp/l2tp_core.c b/net/l2tp/l2tp_core.c index bea259043205..1109d3bb8dac 100644 --- a/net/l2tp/l2tp_core.c +++ b/net/l2tp/l2tp_core.c | |||
| @@ -52,6 +52,7 @@ | |||
| 52 | #include <net/dst.h> | 52 | #include <net/dst.h> |
| 53 | #include <net/ip.h> | 53 | #include <net/ip.h> |
| 54 | #include <net/udp.h> | 54 | #include <net/udp.h> |
| 55 | #include <net/udp_tunnel.h> | ||
| 55 | #include <net/inet_common.h> | 56 | #include <net/inet_common.h> |
| 56 | #include <net/xfrm.h> | 57 | #include <net/xfrm.h> |
| 57 | #include <net/protocol.h> | 58 | #include <net/protocol.h> |
| @@ -1358,81 +1359,46 @@ static int l2tp_tunnel_sock_create(struct net *net, | |||
| 1358 | { | 1359 | { |
| 1359 | int err = -EINVAL; | 1360 | int err = -EINVAL; |
| 1360 | struct socket *sock = NULL; | 1361 | struct socket *sock = NULL; |
| 1361 | struct sockaddr_in udp_addr = {0}; | 1362 | struct udp_port_cfg udp_conf; |
| 1362 | struct sockaddr_l2tpip ip_addr = {0}; | ||
| 1363 | #if IS_ENABLED(CONFIG_IPV6) | ||
| 1364 | struct sockaddr_in6 udp6_addr = {0}; | ||
| 1365 | struct sockaddr_l2tpip6 ip6_addr = {0}; | ||
| 1366 | #endif | ||
| 1367 | 1363 | ||
| 1368 | switch (cfg->encap) { | 1364 | switch (cfg->encap) { |
| 1369 | case L2TP_ENCAPTYPE_UDP: | 1365 | case L2TP_ENCAPTYPE_UDP: |
| 1366 | memset(&udp_conf, 0, sizeof(udp_conf)); | ||
| 1367 | |||
| 1370 | #if IS_ENABLED(CONFIG_IPV6) | 1368 | #if IS_ENABLED(CONFIG_IPV6) |
| 1371 | if (cfg->local_ip6 && cfg->peer_ip6) { | 1369 | if (cfg->local_ip6 && cfg->peer_ip6) { |
| 1372 | err = sock_create_kern(AF_INET6, SOCK_DGRAM, 0, &sock); | 1370 | udp_conf.family = AF_INET6; |
| 1373 | if (err < 0) | 1371 | memcpy(&udp_conf.local_ip6, cfg->local_ip6, |
| 1374 | goto out; | 1372 | sizeof(udp_conf.local_ip6)); |
| 1375 | 1373 | memcpy(&udp_conf.peer_ip6, cfg->peer_ip6, | |
| 1376 | sk_change_net(sock->sk, net); | 1374 | sizeof(udp_conf.peer_ip6)); |
| 1377 | 1375 | udp_conf.use_udp6_tx_checksums = | |
| 1378 | udp6_addr.sin6_family = AF_INET6; | 1376 | cfg->udp6_zero_tx_checksums; |
| 1379 | memcpy(&udp6_addr.sin6_addr, cfg->local_ip6, | 1377 | udp_conf.use_udp6_rx_checksums = |
| 1380 | sizeof(udp6_addr.sin6_addr)); | 1378 | cfg->udp6_zero_rx_checksums; |
| 1381 | udp6_addr.sin6_port = htons(cfg->local_udp_port); | ||
| 1382 | err = kernel_bind(sock, (struct sockaddr *) &udp6_addr, | ||
| 1383 | sizeof(udp6_addr)); | ||
| 1384 | if (err < 0) | ||
| 1385 | goto out; | ||
| 1386 | |||
| 1387 | udp6_addr.sin6_family = AF_INET6; | ||
| 1388 | memcpy(&udp6_addr.sin6_addr, cfg->peer_ip6, | ||
| 1389 | sizeof(udp6_addr.sin6_addr)); | ||
| 1390 | udp6_addr.sin6_port = htons(cfg->peer_udp_port); | ||
| 1391 | err = kernel_connect(sock, | ||
| 1392 | (struct sockaddr *) &udp6_addr, | ||
| 1393 | sizeof(udp6_addr), 0); | ||
| 1394 | if (err < 0) | ||
| 1395 | goto out; | ||
| 1396 | |||
| 1397 | if (cfg->udp6_zero_tx_checksums) | ||
| 1398 | udp_set_no_check6_tx(sock->sk, true); | ||
| 1399 | if (cfg->udp6_zero_rx_checksums) | ||
| 1400 | udp_set_no_check6_rx(sock->sk, true); | ||
| 1401 | } else | 1379 | } else |
| 1402 | #endif | 1380 | #endif |
| 1403 | { | 1381 | { |
| 1404 | err = sock_create_kern(AF_INET, SOCK_DGRAM, 0, &sock); | 1382 | udp_conf.family = AF_INET; |
| 1405 | if (err < 0) | 1383 | udp_conf.local_ip = cfg->local_ip; |
| 1406 | goto out; | 1384 | udp_conf.peer_ip = cfg->peer_ip; |
| 1407 | 1385 | udp_conf.use_udp_checksums = cfg->use_udp_checksums; | |
| 1408 | sk_change_net(sock->sk, net); | ||
| 1409 | |||
| 1410 | udp_addr.sin_family = AF_INET; | ||
| 1411 | udp_addr.sin_addr = cfg->local_ip; | ||
| 1412 | udp_addr.sin_port = htons(cfg->local_udp_port); | ||
| 1413 | err = kernel_bind(sock, (struct sockaddr *) &udp_addr, | ||
| 1414 | sizeof(udp_addr)); | ||
| 1415 | if (err < 0) | ||
| 1416 | goto out; | ||
| 1417 | |||
| 1418 | udp_addr.sin_family = AF_INET; | ||
| 1419 | udp_addr.sin_addr = cfg->peer_ip; | ||
| 1420 | udp_addr.sin_port = htons(cfg->peer_udp_port); | ||
| 1421 | err = kernel_connect(sock, | ||
| 1422 | (struct sockaddr *) &udp_addr, | ||
| 1423 | sizeof(udp_addr), 0); | ||
| 1424 | if (err < 0) | ||
| 1425 | goto out; | ||
| 1426 | } | 1386 | } |
| 1427 | 1387 | ||
| 1428 | if (!cfg->use_udp_checksums) | 1388 | udp_conf.local_udp_port = htons(cfg->local_udp_port); |
| 1429 | sock->sk->sk_no_check_tx = 1; | 1389 | udp_conf.peer_udp_port = htons(cfg->peer_udp_port); |
| 1390 | |||
| 1391 | err = udp_sock_create(net, &udp_conf, &sock); | ||
| 1392 | if (err < 0) | ||
| 1393 | goto out; | ||
| 1430 | 1394 | ||
| 1431 | break; | 1395 | break; |
| 1432 | 1396 | ||
| 1433 | case L2TP_ENCAPTYPE_IP: | 1397 | case L2TP_ENCAPTYPE_IP: |
| 1434 | #if IS_ENABLED(CONFIG_IPV6) | 1398 | #if IS_ENABLED(CONFIG_IPV6) |
| 1435 | if (cfg->local_ip6 && cfg->peer_ip6) { | 1399 | if (cfg->local_ip6 && cfg->peer_ip6) { |
| 1400 | struct sockaddr_l2tpip6 ip6_addr = {0}; | ||
| 1401 | |||
| 1436 | err = sock_create_kern(AF_INET6, SOCK_DGRAM, | 1402 | err = sock_create_kern(AF_INET6, SOCK_DGRAM, |
| 1437 | IPPROTO_L2TP, &sock); | 1403 | IPPROTO_L2TP, &sock); |
| 1438 | if (err < 0) | 1404 | if (err < 0) |
| @@ -1461,6 +1427,8 @@ static int l2tp_tunnel_sock_create(struct net *net, | |||
| 1461 | } else | 1427 | } else |
| 1462 | #endif | 1428 | #endif |
| 1463 | { | 1429 | { |
| 1430 | struct sockaddr_l2tpip ip_addr = {0}; | ||
| 1431 | |||
| 1464 | err = sock_create_kern(AF_INET, SOCK_DGRAM, | 1432 | err = sock_create_kern(AF_INET, SOCK_DGRAM, |
| 1465 | IPPROTO_L2TP, &sock); | 1433 | IPPROTO_L2TP, &sock); |
| 1466 | if (err < 0) | 1434 | if (err < 0) |
diff --git a/net/l2tp/l2tp_eth.c b/net/l2tp/l2tp_eth.c index 76125c57ee6d..edb78e69efe4 100644 --- a/net/l2tp/l2tp_eth.c +++ b/net/l2tp/l2tp_eth.c | |||
| @@ -246,7 +246,8 @@ static int l2tp_eth_create(struct net *net, u32 tunnel_id, u32 session_id, u32 p | |||
| 246 | goto out; | 246 | goto out; |
| 247 | } | 247 | } |
| 248 | 248 | ||
| 249 | dev = alloc_netdev(sizeof(*priv), name, l2tp_eth_dev_setup); | 249 | dev = alloc_netdev(sizeof(*priv), name, NET_NAME_UNKNOWN, |
| 250 | l2tp_eth_dev_setup); | ||
| 250 | if (!dev) { | 251 | if (!dev) { |
| 251 | rc = -ENOMEM; | 252 | rc = -ENOMEM; |
| 252 | goto out_del_session; | 253 | goto out_del_session; |
diff --git a/net/l2tp/l2tp_ip6.c b/net/l2tp/l2tp_ip6.c index f3f98a156cee..0edb263cc002 100644 --- a/net/l2tp/l2tp_ip6.c +++ b/net/l2tp/l2tp_ip6.c | |||
| @@ -687,7 +687,7 @@ static int l2tp_ip6_recvmsg(struct kiocb *iocb, struct sock *sk, | |||
| 687 | lsa->l2tp_scope_id = 0; | 687 | lsa->l2tp_scope_id = 0; |
| 688 | lsa->l2tp_conn_id = 0; | 688 | lsa->l2tp_conn_id = 0; |
| 689 | if (ipv6_addr_type(&lsa->l2tp_addr) & IPV6_ADDR_LINKLOCAL) | 689 | if (ipv6_addr_type(&lsa->l2tp_addr) & IPV6_ADDR_LINKLOCAL) |
| 690 | lsa->l2tp_scope_id = IP6CB(skb)->iif; | 690 | lsa->l2tp_scope_id = inet6_iif(skb); |
| 691 | } | 691 | } |
| 692 | 692 | ||
| 693 | if (np->rxopt.all) | 693 | if (np->rxopt.all) |
diff --git a/net/mac80211/Kconfig b/net/mac80211/Kconfig index 97b5dcad5025..aeb6a483b3bc 100644 --- a/net/mac80211/Kconfig +++ b/net/mac80211/Kconfig | |||
| @@ -19,14 +19,6 @@ if MAC80211 != n | |||
| 19 | config MAC80211_HAS_RC | 19 | config MAC80211_HAS_RC |
| 20 | bool | 20 | bool |
| 21 | 21 | ||
| 22 | config MAC80211_RC_PID | ||
| 23 | bool "PID controller based rate control algorithm" if EXPERT | ||
| 24 | select MAC80211_HAS_RC | ||
| 25 | ---help--- | ||
| 26 | This option enables a TX rate control algorithm for | ||
| 27 | mac80211 that uses a PID controller to select the TX | ||
| 28 | rate. | ||
| 29 | |||
| 30 | config MAC80211_RC_MINSTREL | 22 | config MAC80211_RC_MINSTREL |
| 31 | bool "Minstrel" if EXPERT | 23 | bool "Minstrel" if EXPERT |
| 32 | select MAC80211_HAS_RC | 24 | select MAC80211_HAS_RC |
| @@ -51,14 +43,6 @@ choice | |||
| 51 | overridden through the ieee80211_default_rc_algo module | 43 | overridden through the ieee80211_default_rc_algo module |
| 52 | parameter if different algorithms are available. | 44 | parameter if different algorithms are available. |
| 53 | 45 | ||
| 54 | config MAC80211_RC_DEFAULT_PID | ||
| 55 | bool "PID controller based rate control algorithm" | ||
| 56 | depends on MAC80211_RC_PID | ||
| 57 | ---help--- | ||
| 58 | Select the PID controller based rate control as the | ||
| 59 | default rate control algorithm. You should choose | ||
| 60 | this unless you know what you are doing. | ||
| 61 | |||
| 62 | config MAC80211_RC_DEFAULT_MINSTREL | 46 | config MAC80211_RC_DEFAULT_MINSTREL |
| 63 | bool "Minstrel" | 47 | bool "Minstrel" |
| 64 | depends on MAC80211_RC_MINSTREL | 48 | depends on MAC80211_RC_MINSTREL |
| @@ -72,7 +56,6 @@ config MAC80211_RC_DEFAULT | |||
| 72 | string | 56 | string |
| 73 | default "minstrel_ht" if MAC80211_RC_DEFAULT_MINSTREL && MAC80211_RC_MINSTREL_HT | 57 | default "minstrel_ht" if MAC80211_RC_DEFAULT_MINSTREL && MAC80211_RC_MINSTREL_HT |
| 74 | default "minstrel" if MAC80211_RC_DEFAULT_MINSTREL | 58 | default "minstrel" if MAC80211_RC_DEFAULT_MINSTREL |
| 75 | default "pid" if MAC80211_RC_DEFAULT_PID | ||
| 76 | default "" | 59 | default "" |
| 77 | 60 | ||
| 78 | endif | 61 | endif |
diff --git a/net/mac80211/Makefile b/net/mac80211/Makefile index 1e46ffa69167..7273d2796dd1 100644 --- a/net/mac80211/Makefile +++ b/net/mac80211/Makefile | |||
| @@ -17,6 +17,7 @@ mac80211-y := \ | |||
| 17 | aes_ccm.o \ | 17 | aes_ccm.o \ |
| 18 | aes_cmac.o \ | 18 | aes_cmac.o \ |
| 19 | cfg.o \ | 19 | cfg.o \ |
| 20 | ethtool.o \ | ||
| 20 | rx.o \ | 21 | rx.o \ |
| 21 | spectmgmt.o \ | 22 | spectmgmt.o \ |
| 22 | tx.o \ | 23 | tx.o \ |
| @@ -47,17 +48,12 @@ mac80211-$(CONFIG_PM) += pm.o | |||
| 47 | 48 | ||
| 48 | CFLAGS_trace.o := -I$(src) | 49 | CFLAGS_trace.o := -I$(src) |
| 49 | 50 | ||
| 50 | # objects for PID algorithm | ||
| 51 | rc80211_pid-y := rc80211_pid_algo.o | ||
| 52 | rc80211_pid-$(CONFIG_MAC80211_DEBUGFS) += rc80211_pid_debugfs.o | ||
| 53 | |||
| 54 | rc80211_minstrel-y := rc80211_minstrel.o | 51 | rc80211_minstrel-y := rc80211_minstrel.o |
| 55 | rc80211_minstrel-$(CONFIG_MAC80211_DEBUGFS) += rc80211_minstrel_debugfs.o | 52 | rc80211_minstrel-$(CONFIG_MAC80211_DEBUGFS) += rc80211_minstrel_debugfs.o |
| 56 | 53 | ||
| 57 | rc80211_minstrel_ht-y := rc80211_minstrel_ht.o | 54 | rc80211_minstrel_ht-y := rc80211_minstrel_ht.o |
| 58 | rc80211_minstrel_ht-$(CONFIG_MAC80211_DEBUGFS) += rc80211_minstrel_ht_debugfs.o | 55 | rc80211_minstrel_ht-$(CONFIG_MAC80211_DEBUGFS) += rc80211_minstrel_ht_debugfs.o |
| 59 | 56 | ||
| 60 | mac80211-$(CONFIG_MAC80211_RC_PID) += $(rc80211_pid-y) | ||
| 61 | mac80211-$(CONFIG_MAC80211_RC_MINSTREL) += $(rc80211_minstrel-y) | 57 | mac80211-$(CONFIG_MAC80211_RC_MINSTREL) += $(rc80211_minstrel-y) |
| 62 | mac80211-$(CONFIG_MAC80211_RC_MINSTREL_HT) += $(rc80211_minstrel_ht-y) | 58 | mac80211-$(CONFIG_MAC80211_RC_MINSTREL_HT) += $(rc80211_minstrel_ht-y) |
| 63 | 59 | ||
diff --git a/net/mac80211/agg-rx.c b/net/mac80211/agg-rx.c index 31bf2586fb84..f0e84bc48038 100644 --- a/net/mac80211/agg-rx.c +++ b/net/mac80211/agg-rx.c | |||
| @@ -52,7 +52,7 @@ static void ieee80211_free_tid_rx(struct rcu_head *h) | |||
| 52 | del_timer_sync(&tid_rx->reorder_timer); | 52 | del_timer_sync(&tid_rx->reorder_timer); |
| 53 | 53 | ||
| 54 | for (i = 0; i < tid_rx->buf_size; i++) | 54 | for (i = 0; i < tid_rx->buf_size; i++) |
| 55 | dev_kfree_skb(tid_rx->reorder_buf[i]); | 55 | __skb_queue_purge(&tid_rx->reorder_buf[i]); |
| 56 | kfree(tid_rx->reorder_buf); | 56 | kfree(tid_rx->reorder_buf); |
| 57 | kfree(tid_rx->reorder_time); | 57 | kfree(tid_rx->reorder_time); |
| 58 | kfree(tid_rx); | 58 | kfree(tid_rx); |
| @@ -224,28 +224,15 @@ static void ieee80211_send_addba_resp(struct ieee80211_sub_if_data *sdata, u8 *d | |||
| 224 | ieee80211_tx_skb(sdata, skb); | 224 | ieee80211_tx_skb(sdata, skb); |
| 225 | } | 225 | } |
| 226 | 226 | ||
| 227 | void ieee80211_process_addba_request(struct ieee80211_local *local, | 227 | void __ieee80211_start_rx_ba_session(struct sta_info *sta, |
| 228 | struct sta_info *sta, | 228 | u8 dialog_token, u16 timeout, |
| 229 | struct ieee80211_mgmt *mgmt, | 229 | u16 start_seq_num, u16 ba_policy, u16 tid, |
| 230 | size_t len) | 230 | u16 buf_size, bool tx) |
| 231 | { | 231 | { |
| 232 | struct ieee80211_local *local = sta->sdata->local; | ||
| 232 | struct tid_ampdu_rx *tid_agg_rx; | 233 | struct tid_ampdu_rx *tid_agg_rx; |
| 233 | u16 capab, tid, timeout, ba_policy, buf_size, start_seq_num, status; | 234 | int i, ret = -EOPNOTSUPP; |
| 234 | u8 dialog_token; | 235 | u16 status = WLAN_STATUS_REQUEST_DECLINED; |
| 235 | int ret = -EOPNOTSUPP; | ||
| 236 | |||
| 237 | /* extract session parameters from addba request frame */ | ||
| 238 | dialog_token = mgmt->u.action.u.addba_req.dialog_token; | ||
| 239 | timeout = le16_to_cpu(mgmt->u.action.u.addba_req.timeout); | ||
| 240 | start_seq_num = | ||
| 241 | le16_to_cpu(mgmt->u.action.u.addba_req.start_seq_num) >> 4; | ||
| 242 | |||
| 243 | capab = le16_to_cpu(mgmt->u.action.u.addba_req.capab); | ||
| 244 | ba_policy = (capab & IEEE80211_ADDBA_PARAM_POLICY_MASK) >> 1; | ||
| 245 | tid = (capab & IEEE80211_ADDBA_PARAM_TID_MASK) >> 2; | ||
| 246 | buf_size = (capab & IEEE80211_ADDBA_PARAM_BUF_SIZE_MASK) >> 6; | ||
| 247 | |||
| 248 | status = WLAN_STATUS_REQUEST_DECLINED; | ||
| 249 | 236 | ||
| 250 | if (test_sta_flag(sta, WLAN_STA_BLOCK_BA)) { | 237 | if (test_sta_flag(sta, WLAN_STA_BLOCK_BA)) { |
| 251 | ht_dbg(sta->sdata, | 238 | ht_dbg(sta->sdata, |
| @@ -264,7 +251,7 @@ void ieee80211_process_addba_request(struct ieee80211_local *local, | |||
| 264 | status = WLAN_STATUS_INVALID_QOS_PARAM; | 251 | status = WLAN_STATUS_INVALID_QOS_PARAM; |
| 265 | ht_dbg_ratelimited(sta->sdata, | 252 | ht_dbg_ratelimited(sta->sdata, |
| 266 | "AddBA Req with bad params from %pM on tid %u. policy %d, buffer size %d\n", | 253 | "AddBA Req with bad params from %pM on tid %u. policy %d, buffer size %d\n", |
| 267 | mgmt->sa, tid, ba_policy, buf_size); | 254 | sta->sta.addr, tid, ba_policy, buf_size); |
| 268 | goto end_no_lock; | 255 | goto end_no_lock; |
| 269 | } | 256 | } |
| 270 | /* determine default buffer size */ | 257 | /* determine default buffer size */ |
| @@ -281,7 +268,7 @@ void ieee80211_process_addba_request(struct ieee80211_local *local, | |||
| 281 | if (sta->ampdu_mlme.tid_rx[tid]) { | 268 | if (sta->ampdu_mlme.tid_rx[tid]) { |
| 282 | ht_dbg_ratelimited(sta->sdata, | 269 | ht_dbg_ratelimited(sta->sdata, |
| 283 | "unexpected AddBA Req from %pM on tid %u\n", | 270 | "unexpected AddBA Req from %pM on tid %u\n", |
| 284 | mgmt->sa, tid); | 271 | sta->sta.addr, tid); |
| 285 | 272 | ||
| 286 | /* delete existing Rx BA session on the same tid */ | 273 | /* delete existing Rx BA session on the same tid */ |
| 287 | ___ieee80211_stop_rx_ba_session(sta, tid, WLAN_BACK_RECIPIENT, | 274 | ___ieee80211_stop_rx_ba_session(sta, tid, WLAN_BACK_RECIPIENT, |
| @@ -308,7 +295,7 @@ void ieee80211_process_addba_request(struct ieee80211_local *local, | |||
| 308 | 295 | ||
| 309 | /* prepare reordering buffer */ | 296 | /* prepare reordering buffer */ |
| 310 | tid_agg_rx->reorder_buf = | 297 | tid_agg_rx->reorder_buf = |
| 311 | kcalloc(buf_size, sizeof(struct sk_buff *), GFP_KERNEL); | 298 | kcalloc(buf_size, sizeof(struct sk_buff_head), GFP_KERNEL); |
| 312 | tid_agg_rx->reorder_time = | 299 | tid_agg_rx->reorder_time = |
| 313 | kcalloc(buf_size, sizeof(unsigned long), GFP_KERNEL); | 300 | kcalloc(buf_size, sizeof(unsigned long), GFP_KERNEL); |
| 314 | if (!tid_agg_rx->reorder_buf || !tid_agg_rx->reorder_time) { | 301 | if (!tid_agg_rx->reorder_buf || !tid_agg_rx->reorder_time) { |
| @@ -318,6 +305,9 @@ void ieee80211_process_addba_request(struct ieee80211_local *local, | |||
| 318 | goto end; | 305 | goto end; |
| 319 | } | 306 | } |
| 320 | 307 | ||
| 308 | for (i = 0; i < buf_size; i++) | ||
| 309 | __skb_queue_head_init(&tid_agg_rx->reorder_buf[i]); | ||
| 310 | |||
| 321 | ret = drv_ampdu_action(local, sta->sdata, IEEE80211_AMPDU_RX_START, | 311 | ret = drv_ampdu_action(local, sta->sdata, IEEE80211_AMPDU_RX_START, |
| 322 | &sta->sta, tid, &start_seq_num, 0); | 312 | &sta->sta, tid, &start_seq_num, 0); |
| 323 | ht_dbg(sta->sdata, "Rx A-MPDU request on %pM tid %d result %d\n", | 313 | ht_dbg(sta->sdata, "Rx A-MPDU request on %pM tid %d result %d\n", |
| @@ -350,6 +340,74 @@ end: | |||
| 350 | mutex_unlock(&sta->ampdu_mlme.mtx); | 340 | mutex_unlock(&sta->ampdu_mlme.mtx); |
| 351 | 341 | ||
| 352 | end_no_lock: | 342 | end_no_lock: |
| 353 | ieee80211_send_addba_resp(sta->sdata, sta->sta.addr, tid, | 343 | if (tx) |
| 354 | dialog_token, status, 1, buf_size, timeout); | 344 | ieee80211_send_addba_resp(sta->sdata, sta->sta.addr, tid, |
| 345 | dialog_token, status, 1, buf_size, | ||
| 346 | timeout); | ||
| 347 | } | ||
| 348 | |||
| 349 | void ieee80211_process_addba_request(struct ieee80211_local *local, | ||
| 350 | struct sta_info *sta, | ||
| 351 | struct ieee80211_mgmt *mgmt, | ||
| 352 | size_t len) | ||
| 353 | { | ||
| 354 | u16 capab, tid, timeout, ba_policy, buf_size, start_seq_num; | ||
| 355 | u8 dialog_token; | ||
| 356 | |||
| 357 | /* extract session parameters from addba request frame */ | ||
| 358 | dialog_token = mgmt->u.action.u.addba_req.dialog_token; | ||
| 359 | timeout = le16_to_cpu(mgmt->u.action.u.addba_req.timeout); | ||
| 360 | start_seq_num = | ||
| 361 | le16_to_cpu(mgmt->u.action.u.addba_req.start_seq_num) >> 4; | ||
| 362 | |||
| 363 | capab = le16_to_cpu(mgmt->u.action.u.addba_req.capab); | ||
| 364 | ba_policy = (capab & IEEE80211_ADDBA_PARAM_POLICY_MASK) >> 1; | ||
| 365 | tid = (capab & IEEE80211_ADDBA_PARAM_TID_MASK) >> 2; | ||
| 366 | buf_size = (capab & IEEE80211_ADDBA_PARAM_BUF_SIZE_MASK) >> 6; | ||
| 367 | |||
| 368 | __ieee80211_start_rx_ba_session(sta, dialog_token, timeout, | ||
| 369 | start_seq_num, ba_policy, tid, | ||
| 370 | buf_size, true); | ||
| 371 | } | ||
| 372 | |||
| 373 | void ieee80211_start_rx_ba_session_offl(struct ieee80211_vif *vif, | ||
| 374 | const u8 *addr, u16 tid) | ||
| 375 | { | ||
| 376 | struct ieee80211_sub_if_data *sdata = vif_to_sdata(vif); | ||
| 377 | struct ieee80211_local *local = sdata->local; | ||
| 378 | struct ieee80211_rx_agg *rx_agg; | ||
| 379 | struct sk_buff *skb = dev_alloc_skb(0); | ||
| 380 | |||
| 381 | if (unlikely(!skb)) | ||
| 382 | return; | ||
| 383 | |||
| 384 | rx_agg = (struct ieee80211_rx_agg *) &skb->cb; | ||
| 385 | memcpy(&rx_agg->addr, addr, ETH_ALEN); | ||
| 386 | rx_agg->tid = tid; | ||
| 387 | |||
| 388 | skb->pkt_type = IEEE80211_SDATA_QUEUE_RX_AGG_START; | ||
| 389 | skb_queue_tail(&sdata->skb_queue, skb); | ||
| 390 | ieee80211_queue_work(&local->hw, &sdata->work); | ||
| 391 | } | ||
| 392 | EXPORT_SYMBOL(ieee80211_start_rx_ba_session_offl); | ||
| 393 | |||
| 394 | void ieee80211_stop_rx_ba_session_offl(struct ieee80211_vif *vif, | ||
| 395 | const u8 *addr, u16 tid) | ||
| 396 | { | ||
| 397 | struct ieee80211_sub_if_data *sdata = vif_to_sdata(vif); | ||
| 398 | struct ieee80211_local *local = sdata->local; | ||
| 399 | struct ieee80211_rx_agg *rx_agg; | ||
| 400 | struct sk_buff *skb = dev_alloc_skb(0); | ||
| 401 | |||
| 402 | if (unlikely(!skb)) | ||
| 403 | return; | ||
| 404 | |||
| 405 | rx_agg = (struct ieee80211_rx_agg *) &skb->cb; | ||
| 406 | memcpy(&rx_agg->addr, addr, ETH_ALEN); | ||
| 407 | rx_agg->tid = tid; | ||
| 408 | |||
| 409 | skb->pkt_type = IEEE80211_SDATA_QUEUE_RX_AGG_STOP; | ||
| 410 | skb_queue_tail(&sdata->skb_queue, skb); | ||
| 411 | ieee80211_queue_work(&local->hw, &sdata->work); | ||
| 355 | } | 412 | } |
| 413 | EXPORT_SYMBOL(ieee80211_stop_rx_ba_session_offl); | ||
diff --git a/net/mac80211/agg-tx.c b/net/mac80211/agg-tx.c index ce9633a3cfb0..d6986f3aa5c4 100644 --- a/net/mac80211/agg-tx.c +++ b/net/mac80211/agg-tx.c | |||
| @@ -170,10 +170,13 @@ ieee80211_stop_queue_agg(struct ieee80211_sub_if_data *sdata, int tid) | |||
| 170 | { | 170 | { |
| 171 | int queue = sdata->vif.hw_queue[ieee80211_ac_from_tid(tid)]; | 171 | int queue = sdata->vif.hw_queue[ieee80211_ac_from_tid(tid)]; |
| 172 | 172 | ||
| 173 | /* we do refcounting here, so don't use the queue reason refcounting */ | ||
| 174 | |||
| 173 | if (atomic_inc_return(&sdata->local->agg_queue_stop[queue]) == 1) | 175 | if (atomic_inc_return(&sdata->local->agg_queue_stop[queue]) == 1) |
| 174 | ieee80211_stop_queue_by_reason( | 176 | ieee80211_stop_queue_by_reason( |
| 175 | &sdata->local->hw, queue, | 177 | &sdata->local->hw, queue, |
| 176 | IEEE80211_QUEUE_STOP_REASON_AGGREGATION); | 178 | IEEE80211_QUEUE_STOP_REASON_AGGREGATION, |
| 179 | false); | ||
| 177 | __acquire(agg_queue); | 180 | __acquire(agg_queue); |
| 178 | } | 181 | } |
| 179 | 182 | ||
| @@ -185,7 +188,8 @@ ieee80211_wake_queue_agg(struct ieee80211_sub_if_data *sdata, int tid) | |||
| 185 | if (atomic_dec_return(&sdata->local->agg_queue_stop[queue]) == 0) | 188 | if (atomic_dec_return(&sdata->local->agg_queue_stop[queue]) == 0) |
| 186 | ieee80211_wake_queue_by_reason( | 189 | ieee80211_wake_queue_by_reason( |
| 187 | &sdata->local->hw, queue, | 190 | &sdata->local->hw, queue, |
| 188 | IEEE80211_QUEUE_STOP_REASON_AGGREGATION); | 191 | IEEE80211_QUEUE_STOP_REASON_AGGREGATION, |
| 192 | false); | ||
| 189 | __release(agg_queue); | 193 | __release(agg_queue); |
| 190 | } | 194 | } |
| 191 | 195 | ||
diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c index 592f4b152ba8..927b4ea0128b 100644 --- a/net/mac80211/cfg.c +++ b/net/mac80211/cfg.c | |||
| @@ -468,330 +468,6 @@ void sta_set_rate_info_rx(struct sta_info *sta, struct rate_info *rinfo) | |||
| 468 | rinfo->flags |= RATE_INFO_FLAGS_160_MHZ_WIDTH; | 468 | rinfo->flags |= RATE_INFO_FLAGS_160_MHZ_WIDTH; |
| 469 | } | 469 | } |
| 470 | 470 | ||
| 471 | static void sta_set_sinfo(struct sta_info *sta, struct station_info *sinfo) | ||
| 472 | { | ||
| 473 | struct ieee80211_sub_if_data *sdata = sta->sdata; | ||
| 474 | struct ieee80211_local *local = sdata->local; | ||
| 475 | struct rate_control_ref *ref = NULL; | ||
| 476 | struct timespec uptime; | ||
| 477 | u64 packets = 0; | ||
| 478 | u32 thr = 0; | ||
| 479 | int i, ac; | ||
| 480 | |||
| 481 | if (test_sta_flag(sta, WLAN_STA_RATE_CONTROL)) | ||
| 482 | ref = local->rate_ctrl; | ||
| 483 | |||
| 484 | sinfo->generation = sdata->local->sta_generation; | ||
| 485 | |||
| 486 | sinfo->filled = STATION_INFO_INACTIVE_TIME | | ||
| 487 | STATION_INFO_RX_BYTES64 | | ||
| 488 | STATION_INFO_TX_BYTES64 | | ||
| 489 | STATION_INFO_RX_PACKETS | | ||
| 490 | STATION_INFO_TX_PACKETS | | ||
| 491 | STATION_INFO_TX_RETRIES | | ||
| 492 | STATION_INFO_TX_FAILED | | ||
| 493 | STATION_INFO_TX_BITRATE | | ||
| 494 | STATION_INFO_RX_BITRATE | | ||
| 495 | STATION_INFO_RX_DROP_MISC | | ||
| 496 | STATION_INFO_BSS_PARAM | | ||
| 497 | STATION_INFO_CONNECTED_TIME | | ||
| 498 | STATION_INFO_STA_FLAGS | | ||
| 499 | STATION_INFO_BEACON_LOSS_COUNT; | ||
| 500 | |||
| 501 | do_posix_clock_monotonic_gettime(&uptime); | ||
| 502 | sinfo->connected_time = uptime.tv_sec - sta->last_connected; | ||
| 503 | |||
| 504 | sinfo->inactive_time = jiffies_to_msecs(jiffies - sta->last_rx); | ||
| 505 | sinfo->tx_bytes = 0; | ||
| 506 | for (ac = 0; ac < IEEE80211_NUM_ACS; ac++) { | ||
| 507 | sinfo->tx_bytes += sta->tx_bytes[ac]; | ||
| 508 | packets += sta->tx_packets[ac]; | ||
| 509 | } | ||
| 510 | sinfo->tx_packets = packets; | ||
| 511 | sinfo->rx_bytes = sta->rx_bytes; | ||
| 512 | sinfo->rx_packets = sta->rx_packets; | ||
| 513 | sinfo->tx_retries = sta->tx_retry_count; | ||
| 514 | sinfo->tx_failed = sta->tx_retry_failed; | ||
| 515 | sinfo->rx_dropped_misc = sta->rx_dropped; | ||
| 516 | sinfo->beacon_loss_count = sta->beacon_loss_count; | ||
| 517 | |||
| 518 | if ((sta->local->hw.flags & IEEE80211_HW_SIGNAL_DBM) || | ||
| 519 | (sta->local->hw.flags & IEEE80211_HW_SIGNAL_UNSPEC)) { | ||
| 520 | sinfo->filled |= STATION_INFO_SIGNAL | STATION_INFO_SIGNAL_AVG; | ||
| 521 | if (!local->ops->get_rssi || | ||
| 522 | drv_get_rssi(local, sdata, &sta->sta, &sinfo->signal)) | ||
| 523 | sinfo->signal = (s8)sta->last_signal; | ||
| 524 | sinfo->signal_avg = (s8) -ewma_read(&sta->avg_signal); | ||
| 525 | } | ||
| 526 | if (sta->chains) { | ||
| 527 | sinfo->filled |= STATION_INFO_CHAIN_SIGNAL | | ||
| 528 | STATION_INFO_CHAIN_SIGNAL_AVG; | ||
| 529 | |||
| 530 | sinfo->chains = sta->chains; | ||
| 531 | for (i = 0; i < ARRAY_SIZE(sinfo->chain_signal); i++) { | ||
| 532 | sinfo->chain_signal[i] = sta->chain_signal_last[i]; | ||
| 533 | sinfo->chain_signal_avg[i] = | ||
| 534 | (s8) -ewma_read(&sta->chain_signal_avg[i]); | ||
| 535 | } | ||
| 536 | } | ||
| 537 | |||
| 538 | sta_set_rate_info_tx(sta, &sta->last_tx_rate, &sinfo->txrate); | ||
| 539 | sta_set_rate_info_rx(sta, &sinfo->rxrate); | ||
| 540 | |||
| 541 | if (ieee80211_vif_is_mesh(&sdata->vif)) { | ||
| 542 | #ifdef CONFIG_MAC80211_MESH | ||
| 543 | sinfo->filled |= STATION_INFO_LLID | | ||
| 544 | STATION_INFO_PLID | | ||
| 545 | STATION_INFO_PLINK_STATE | | ||
| 546 | STATION_INFO_LOCAL_PM | | ||
| 547 | STATION_INFO_PEER_PM | | ||
| 548 | STATION_INFO_NONPEER_PM; | ||
| 549 | |||
| 550 | sinfo->llid = sta->llid; | ||
| 551 | sinfo->plid = sta->plid; | ||
| 552 | sinfo->plink_state = sta->plink_state; | ||
| 553 | if (test_sta_flag(sta, WLAN_STA_TOFFSET_KNOWN)) { | ||
| 554 | sinfo->filled |= STATION_INFO_T_OFFSET; | ||
| 555 | sinfo->t_offset = sta->t_offset; | ||
| 556 | } | ||
| 557 | sinfo->local_pm = sta->local_pm; | ||
| 558 | sinfo->peer_pm = sta->peer_pm; | ||
| 559 | sinfo->nonpeer_pm = sta->nonpeer_pm; | ||
| 560 | #endif | ||
| 561 | } | ||
| 562 | |||
| 563 | sinfo->bss_param.flags = 0; | ||
| 564 | if (sdata->vif.bss_conf.use_cts_prot) | ||
| 565 | sinfo->bss_param.flags |= BSS_PARAM_FLAGS_CTS_PROT; | ||
| 566 | if (sdata->vif.bss_conf.use_short_preamble) | ||
| 567 | sinfo->bss_param.flags |= BSS_PARAM_FLAGS_SHORT_PREAMBLE; | ||
| 568 | if (sdata->vif.bss_conf.use_short_slot) | ||
| 569 | sinfo->bss_param.flags |= BSS_PARAM_FLAGS_SHORT_SLOT_TIME; | ||
| 570 | sinfo->bss_param.dtim_period = sdata->local->hw.conf.ps_dtim_period; | ||
| 571 | sinfo->bss_param.beacon_interval = sdata->vif.bss_conf.beacon_int; | ||
| 572 | |||
| 573 | sinfo->sta_flags.set = 0; | ||
| 574 | sinfo->sta_flags.mask = BIT(NL80211_STA_FLAG_AUTHORIZED) | | ||
| 575 | BIT(NL80211_STA_FLAG_SHORT_PREAMBLE) | | ||
| 576 | BIT(NL80211_STA_FLAG_WME) | | ||
| 577 | BIT(NL80211_STA_FLAG_MFP) | | ||
| 578 | BIT(NL80211_STA_FLAG_AUTHENTICATED) | | ||
| 579 | BIT(NL80211_STA_FLAG_ASSOCIATED) | | ||
| 580 | BIT(NL80211_STA_FLAG_TDLS_PEER); | ||
| 581 | if (test_sta_flag(sta, WLAN_STA_AUTHORIZED)) | ||
| 582 | sinfo->sta_flags.set |= BIT(NL80211_STA_FLAG_AUTHORIZED); | ||
| 583 | if (test_sta_flag(sta, WLAN_STA_SHORT_PREAMBLE)) | ||
| 584 | sinfo->sta_flags.set |= BIT(NL80211_STA_FLAG_SHORT_PREAMBLE); | ||
| 585 | if (test_sta_flag(sta, WLAN_STA_WME)) | ||
| 586 | sinfo->sta_flags.set |= BIT(NL80211_STA_FLAG_WME); | ||
| 587 | if (test_sta_flag(sta, WLAN_STA_MFP)) | ||
| 588 | sinfo->sta_flags.set |= BIT(NL80211_STA_FLAG_MFP); | ||
| 589 | if (test_sta_flag(sta, WLAN_STA_AUTH)) | ||
| 590 | sinfo->sta_flags.set |= BIT(NL80211_STA_FLAG_AUTHENTICATED); | ||
| 591 | if (test_sta_flag(sta, WLAN_STA_ASSOC)) | ||
| 592 | sinfo->sta_flags.set |= BIT(NL80211_STA_FLAG_ASSOCIATED); | ||
| 593 | if (test_sta_flag(sta, WLAN_STA_TDLS_PEER)) | ||
| 594 | sinfo->sta_flags.set |= BIT(NL80211_STA_FLAG_TDLS_PEER); | ||
| 595 | |||
| 596 | /* check if the driver has a SW RC implementation */ | ||
| 597 | if (ref && ref->ops->get_expected_throughput) | ||
| 598 | thr = ref->ops->get_expected_throughput(sta->rate_ctrl_priv); | ||
| 599 | else | ||
| 600 | thr = drv_get_expected_throughput(local, &sta->sta); | ||
| 601 | |||
| 602 | if (thr != 0) { | ||
| 603 | sinfo->filled |= STATION_INFO_EXPECTED_THROUGHPUT; | ||
| 604 | sinfo->expected_throughput = thr; | ||
| 605 | } | ||
| 606 | } | ||
| 607 | |||
| 608 | static const char ieee80211_gstrings_sta_stats[][ETH_GSTRING_LEN] = { | ||
| 609 | "rx_packets", "rx_bytes", "wep_weak_iv_count", | ||
| 610 | "rx_duplicates", "rx_fragments", "rx_dropped", | ||
| 611 | "tx_packets", "tx_bytes", "tx_fragments", | ||
| 612 | "tx_filtered", "tx_retry_failed", "tx_retries", | ||
| 613 | "beacon_loss", "sta_state", "txrate", "rxrate", "signal", | ||
| 614 | "channel", "noise", "ch_time", "ch_time_busy", | ||
| 615 | "ch_time_ext_busy", "ch_time_rx", "ch_time_tx" | ||
| 616 | }; | ||
| 617 | #define STA_STATS_LEN ARRAY_SIZE(ieee80211_gstrings_sta_stats) | ||
| 618 | |||
| 619 | static int ieee80211_get_et_sset_count(struct wiphy *wiphy, | ||
| 620 | struct net_device *dev, | ||
| 621 | int sset) | ||
| 622 | { | ||
| 623 | struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); | ||
| 624 | int rv = 0; | ||
| 625 | |||
| 626 | if (sset == ETH_SS_STATS) | ||
| 627 | rv += STA_STATS_LEN; | ||
| 628 | |||
| 629 | rv += drv_get_et_sset_count(sdata, sset); | ||
| 630 | |||
| 631 | if (rv == 0) | ||
| 632 | return -EOPNOTSUPP; | ||
| 633 | return rv; | ||
| 634 | } | ||
| 635 | |||
| 636 | static void ieee80211_get_et_stats(struct wiphy *wiphy, | ||
| 637 | struct net_device *dev, | ||
| 638 | struct ethtool_stats *stats, | ||
| 639 | u64 *data) | ||
| 640 | { | ||
| 641 | struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); | ||
| 642 | struct ieee80211_chanctx_conf *chanctx_conf; | ||
| 643 | struct ieee80211_channel *channel; | ||
| 644 | struct sta_info *sta; | ||
| 645 | struct ieee80211_local *local = sdata->local; | ||
| 646 | struct station_info sinfo; | ||
| 647 | struct survey_info survey; | ||
| 648 | int i, q; | ||
| 649 | #define STA_STATS_SURVEY_LEN 7 | ||
| 650 | |||
| 651 | memset(data, 0, sizeof(u64) * STA_STATS_LEN); | ||
| 652 | |||
| 653 | #define ADD_STA_STATS(sta) \ | ||
| 654 | do { \ | ||
| 655 | data[i++] += sta->rx_packets; \ | ||
| 656 | data[i++] += sta->rx_bytes; \ | ||
| 657 | data[i++] += sta->wep_weak_iv_count; \ | ||
| 658 | data[i++] += sta->num_duplicates; \ | ||
| 659 | data[i++] += sta->rx_fragments; \ | ||
| 660 | data[i++] += sta->rx_dropped; \ | ||
| 661 | \ | ||
| 662 | data[i++] += sinfo.tx_packets; \ | ||
| 663 | data[i++] += sinfo.tx_bytes; \ | ||
| 664 | data[i++] += sta->tx_fragments; \ | ||
| 665 | data[i++] += sta->tx_filtered_count; \ | ||
| 666 | data[i++] += sta->tx_retry_failed; \ | ||
| 667 | data[i++] += sta->tx_retry_count; \ | ||
| 668 | data[i++] += sta->beacon_loss_count; \ | ||
| 669 | } while (0) | ||
| 670 | |||
| 671 | /* For Managed stations, find the single station based on BSSID | ||
| 672 | * and use that. For interface types, iterate through all available | ||
| 673 | * stations and add stats for any station that is assigned to this | ||
| 674 | * network device. | ||
| 675 | */ | ||
| 676 | |||
| 677 | mutex_lock(&local->sta_mtx); | ||
| 678 | |||
| 679 | if (sdata->vif.type == NL80211_IFTYPE_STATION) { | ||
| 680 | sta = sta_info_get_bss(sdata, sdata->u.mgd.bssid); | ||
| 681 | |||
| 682 | if (!(sta && !WARN_ON(sta->sdata->dev != dev))) | ||
| 683 | goto do_survey; | ||
| 684 | |||
| 685 | sinfo.filled = 0; | ||
| 686 | sta_set_sinfo(sta, &sinfo); | ||
| 687 | |||
| 688 | i = 0; | ||
| 689 | ADD_STA_STATS(sta); | ||
| 690 | |||
| 691 | data[i++] = sta->sta_state; | ||
| 692 | |||
| 693 | |||
| 694 | if (sinfo.filled & STATION_INFO_TX_BITRATE) | ||
| 695 | data[i] = 100000 * | ||
| 696 | cfg80211_calculate_bitrate(&sinfo.txrate); | ||
| 697 | i++; | ||
| 698 | if (sinfo.filled & STATION_INFO_RX_BITRATE) | ||
| 699 | data[i] = 100000 * | ||
| 700 | cfg80211_calculate_bitrate(&sinfo.rxrate); | ||
| 701 | i++; | ||
| 702 | |||
| 703 | if (sinfo.filled & STATION_INFO_SIGNAL_AVG) | ||
| 704 | data[i] = (u8)sinfo.signal_avg; | ||
| 705 | i++; | ||
| 706 | } else { | ||
| 707 | list_for_each_entry(sta, &local->sta_list, list) { | ||
| 708 | /* Make sure this station belongs to the proper dev */ | ||
| 709 | if (sta->sdata->dev != dev) | ||
| 710 | continue; | ||
| 711 | |||
| 712 | sinfo.filled = 0; | ||
| 713 | sta_set_sinfo(sta, &sinfo); | ||
| 714 | i = 0; | ||
| 715 | ADD_STA_STATS(sta); | ||
| 716 | } | ||
| 717 | } | ||
| 718 | |||
| 719 | do_survey: | ||
| 720 | i = STA_STATS_LEN - STA_STATS_SURVEY_LEN; | ||
| 721 | /* Get survey stats for current channel */ | ||
| 722 | survey.filled = 0; | ||
| 723 | |||
| 724 | rcu_read_lock(); | ||
| 725 | chanctx_conf = rcu_dereference(sdata->vif.chanctx_conf); | ||
| 726 | if (chanctx_conf) | ||
| 727 | channel = chanctx_conf->def.chan; | ||
| 728 | else | ||
| 729 | channel = NULL; | ||
| 730 | rcu_read_unlock(); | ||
| 731 | |||
| 732 | if (channel) { | ||
| 733 | q = 0; | ||
| 734 | do { | ||
| 735 | survey.filled = 0; | ||
| 736 | if (drv_get_survey(local, q, &survey) != 0) { | ||
| 737 | survey.filled = 0; | ||
| 738 | break; | ||
| 739 | } | ||
| 740 | q++; | ||
| 741 | } while (channel != survey.channel); | ||
| 742 | } | ||
| 743 | |||
| 744 | if (survey.filled) | ||
| 745 | data[i++] = survey.channel->center_freq; | ||
| 746 | else | ||
| 747 | data[i++] = 0; | ||
| 748 | if (survey.filled & SURVEY_INFO_NOISE_DBM) | ||
| 749 | data[i++] = (u8)survey.noise; | ||
| 750 | else | ||
| 751 | data[i++] = -1LL; | ||
| 752 | if (survey.filled & SURVEY_INFO_CHANNEL_TIME) | ||
| 753 | data[i++] = survey.channel_time; | ||
| 754 | else | ||
| 755 | data[i++] = -1LL; | ||
| 756 | if (survey.filled & SURVEY_INFO_CHANNEL_TIME_BUSY) | ||
| 757 | data[i++] = survey.channel_time_busy; | ||
| 758 | else | ||
| 759 | data[i++] = -1LL; | ||
| 760 | if (survey.filled & SURVEY_INFO_CHANNEL_TIME_EXT_BUSY) | ||
| 761 | data[i++] = survey.channel_time_ext_busy; | ||
| 762 | else | ||
| 763 | data[i++] = -1LL; | ||
| 764 | if (survey.filled & SURVEY_INFO_CHANNEL_TIME_RX) | ||
| 765 | data[i++] = survey.channel_time_rx; | ||
| 766 | else | ||
| 767 | data[i++] = -1LL; | ||
| 768 | if (survey.filled & SURVEY_INFO_CHANNEL_TIME_TX) | ||
| 769 | data[i++] = survey.channel_time_tx; | ||
| 770 | else | ||
| 771 | data[i++] = -1LL; | ||
| 772 | |||
| 773 | mutex_unlock(&local->sta_mtx); | ||
| 774 | |||
| 775 | if (WARN_ON(i != STA_STATS_LEN)) | ||
| 776 | return; | ||
| 777 | |||
| 778 | drv_get_et_stats(sdata, stats, &(data[STA_STATS_LEN])); | ||
| 779 | } | ||
| 780 | |||
| 781 | static void ieee80211_get_et_strings(struct wiphy *wiphy, | ||
| 782 | struct net_device *dev, | ||
| 783 | u32 sset, u8 *data) | ||
| 784 | { | ||
| 785 | struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); | ||
| 786 | int sz_sta_stats = 0; | ||
| 787 | |||
| 788 | if (sset == ETH_SS_STATS) { | ||
| 789 | sz_sta_stats = sizeof(ieee80211_gstrings_sta_stats); | ||
| 790 | memcpy(data, ieee80211_gstrings_sta_stats, sz_sta_stats); | ||
| 791 | } | ||
| 792 | drv_get_et_strings(sdata, sset, &(data[sz_sta_stats])); | ||
| 793 | } | ||
| 794 | |||
| 795 | static int ieee80211_dump_station(struct wiphy *wiphy, struct net_device *dev, | 471 | static int ieee80211_dump_station(struct wiphy *wiphy, struct net_device *dev, |
| 796 | int idx, u8 *mac, struct station_info *sinfo) | 472 | int idx, u8 *mac, struct station_info *sinfo) |
| 797 | { | 473 | { |
| @@ -878,7 +554,8 @@ static int ieee80211_set_monitor_channel(struct wiphy *wiphy, | |||
| 878 | } | 554 | } |
| 879 | 555 | ||
| 880 | static int ieee80211_set_probe_resp(struct ieee80211_sub_if_data *sdata, | 556 | static int ieee80211_set_probe_resp(struct ieee80211_sub_if_data *sdata, |
| 881 | const u8 *resp, size_t resp_len) | 557 | const u8 *resp, size_t resp_len, |
| 558 | const struct ieee80211_csa_settings *csa) | ||
| 882 | { | 559 | { |
| 883 | struct probe_resp *new, *old; | 560 | struct probe_resp *new, *old; |
| 884 | 561 | ||
| @@ -894,6 +571,11 @@ static int ieee80211_set_probe_resp(struct ieee80211_sub_if_data *sdata, | |||
| 894 | new->len = resp_len; | 571 | new->len = resp_len; |
| 895 | memcpy(new->data, resp, resp_len); | 572 | memcpy(new->data, resp, resp_len); |
| 896 | 573 | ||
| 574 | if (csa) | ||
| 575 | memcpy(new->csa_counter_offsets, csa->counter_offsets_presp, | ||
| 576 | csa->n_counter_offsets_presp * | ||
| 577 | sizeof(new->csa_counter_offsets[0])); | ||
| 578 | |||
| 897 | rcu_assign_pointer(sdata->u.ap.probe_resp, new); | 579 | rcu_assign_pointer(sdata->u.ap.probe_resp, new); |
| 898 | if (old) | 580 | if (old) |
| 899 | kfree_rcu(old, rcu_head); | 581 | kfree_rcu(old, rcu_head); |
| @@ -902,7 +584,8 @@ static int ieee80211_set_probe_resp(struct ieee80211_sub_if_data *sdata, | |||
| 902 | } | 584 | } |
| 903 | 585 | ||
| 904 | static int ieee80211_assign_beacon(struct ieee80211_sub_if_data *sdata, | 586 | static int ieee80211_assign_beacon(struct ieee80211_sub_if_data *sdata, |
| 905 | struct cfg80211_beacon_data *params) | 587 | struct cfg80211_beacon_data *params, |
| 588 | const struct ieee80211_csa_settings *csa) | ||
| 906 | { | 589 | { |
| 907 | struct beacon_data *new, *old; | 590 | struct beacon_data *new, *old; |
| 908 | int new_head_len, new_tail_len; | 591 | int new_head_len, new_tail_len; |
| @@ -946,6 +629,13 @@ static int ieee80211_assign_beacon(struct ieee80211_sub_if_data *sdata, | |||
| 946 | new->head_len = new_head_len; | 629 | new->head_len = new_head_len; |
| 947 | new->tail_len = new_tail_len; | 630 | new->tail_len = new_tail_len; |
| 948 | 631 | ||
| 632 | if (csa) { | ||
| 633 | new->csa_current_counter = csa->count; | ||
| 634 | memcpy(new->csa_counter_offsets, csa->counter_offsets_beacon, | ||
| 635 | csa->n_counter_offsets_beacon * | ||
| 636 | sizeof(new->csa_counter_offsets[0])); | ||
| 637 | } | ||
| 638 | |||
| 949 | /* copy in head */ | 639 | /* copy in head */ |
| 950 | if (params->head) | 640 | if (params->head) |
| 951 | memcpy(new->head, params->head, new_head_len); | 641 | memcpy(new->head, params->head, new_head_len); |
| @@ -960,7 +650,7 @@ static int ieee80211_assign_beacon(struct ieee80211_sub_if_data *sdata, | |||
| 960 | memcpy(new->tail, old->tail, new_tail_len); | 650 | memcpy(new->tail, old->tail, new_tail_len); |
| 961 | 651 | ||
| 962 | err = ieee80211_set_probe_resp(sdata, params->probe_resp, | 652 | err = ieee80211_set_probe_resp(sdata, params->probe_resp, |
| 963 | params->probe_resp_len); | 653 | params->probe_resp_len, csa); |
| 964 | if (err < 0) | 654 | if (err < 0) |
| 965 | return err; | 655 | return err; |
| 966 | if (err == 0) | 656 | if (err == 0) |
| @@ -1045,7 +735,7 @@ static int ieee80211_start_ap(struct wiphy *wiphy, struct net_device *dev, | |||
| 1045 | sdata->vif.bss_conf.p2p_noa_attr.oppps_ctwindow |= | 735 | sdata->vif.bss_conf.p2p_noa_attr.oppps_ctwindow |= |
| 1046 | IEEE80211_P2P_OPPPS_ENABLE_BIT; | 736 | IEEE80211_P2P_OPPPS_ENABLE_BIT; |
| 1047 | 737 | ||
| 1048 | err = ieee80211_assign_beacon(sdata, ¶ms->beacon); | 738 | err = ieee80211_assign_beacon(sdata, ¶ms->beacon, NULL); |
| 1049 | if (err < 0) { | 739 | if (err < 0) { |
| 1050 | ieee80211_vif_release_channel(sdata); | 740 | ieee80211_vif_release_channel(sdata); |
| 1051 | return err; | 741 | return err; |
| @@ -1093,38 +783,13 @@ static int ieee80211_change_beacon(struct wiphy *wiphy, struct net_device *dev, | |||
| 1093 | if (!old) | 783 | if (!old) |
| 1094 | return -ENOENT; | 784 | return -ENOENT; |
| 1095 | 785 | ||
| 1096 | err = ieee80211_assign_beacon(sdata, params); | 786 | err = ieee80211_assign_beacon(sdata, params, NULL); |
| 1097 | if (err < 0) | 787 | if (err < 0) |
| 1098 | return err; | 788 | return err; |
| 1099 | ieee80211_bss_info_change_notify(sdata, err); | 789 | ieee80211_bss_info_change_notify(sdata, err); |
| 1100 | return 0; | 790 | return 0; |
| 1101 | } | 791 | } |
| 1102 | 792 | ||
| 1103 | bool ieee80211_csa_needs_block_tx(struct ieee80211_local *local) | ||
| 1104 | { | ||
| 1105 | struct ieee80211_sub_if_data *sdata; | ||
| 1106 | |||
| 1107 | lockdep_assert_held(&local->mtx); | ||
| 1108 | |||
| 1109 | rcu_read_lock(); | ||
| 1110 | list_for_each_entry_rcu(sdata, &local->interfaces, list) { | ||
| 1111 | if (!ieee80211_sdata_running(sdata)) | ||
| 1112 | continue; | ||
| 1113 | |||
| 1114 | if (!sdata->vif.csa_active) | ||
| 1115 | continue; | ||
| 1116 | |||
| 1117 | if (!sdata->csa_block_tx) | ||
| 1118 | continue; | ||
| 1119 | |||
| 1120 | rcu_read_unlock(); | ||
| 1121 | return true; | ||
| 1122 | } | ||
| 1123 | rcu_read_unlock(); | ||
| 1124 | |||
| 1125 | return false; | ||
| 1126 | } | ||
| 1127 | |||
| 1128 | static int ieee80211_stop_ap(struct wiphy *wiphy, struct net_device *dev) | 793 | static int ieee80211_stop_ap(struct wiphy *wiphy, struct net_device *dev) |
| 1129 | { | 794 | { |
| 1130 | struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); | 795 | struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); |
| @@ -1144,10 +809,12 @@ static int ieee80211_stop_ap(struct wiphy *wiphy, struct net_device *dev) | |||
| 1144 | /* abort any running channel switch */ | 809 | /* abort any running channel switch */ |
| 1145 | mutex_lock(&local->mtx); | 810 | mutex_lock(&local->mtx); |
| 1146 | sdata->vif.csa_active = false; | 811 | sdata->vif.csa_active = false; |
| 1147 | if (!ieee80211_csa_needs_block_tx(local)) | 812 | if (sdata->csa_block_tx) { |
| 1148 | ieee80211_wake_queues_by_reason(&local->hw, | 813 | ieee80211_wake_vif_queues(local, sdata, |
| 1149 | IEEE80211_MAX_QUEUE_MAP, | 814 | IEEE80211_QUEUE_STOP_REASON_CSA); |
| 1150 | IEEE80211_QUEUE_STOP_REASON_CSA); | 815 | sdata->csa_block_tx = false; |
| 816 | } | ||
| 817 | |||
| 1151 | mutex_unlock(&local->mtx); | 818 | mutex_unlock(&local->mtx); |
| 1152 | 819 | ||
| 1153 | kfree(sdata->u.ap.next_beacon); | 820 | kfree(sdata->u.ap.next_beacon); |
| @@ -1330,9 +997,12 @@ static int sta_apply_parameters(struct ieee80211_local *local, | |||
| 1330 | } | 997 | } |
| 1331 | } | 998 | } |
| 1332 | 999 | ||
| 1333 | ret = sta_apply_auth_flags(local, sta, mask, set); | 1000 | /* auth flags will be set later for TDLS stations */ |
| 1334 | if (ret) | 1001 | if (!test_sta_flag(sta, WLAN_STA_TDLS_PEER)) { |
| 1335 | return ret; | 1002 | ret = sta_apply_auth_flags(local, sta, mask, set); |
| 1003 | if (ret) | ||
| 1004 | return ret; | ||
| 1005 | } | ||
| 1336 | 1006 | ||
| 1337 | if (mask & BIT(NL80211_STA_FLAG_SHORT_PREAMBLE)) { | 1007 | if (mask & BIT(NL80211_STA_FLAG_SHORT_PREAMBLE)) { |
| 1338 | if (set & BIT(NL80211_STA_FLAG_SHORT_PREAMBLE)) | 1008 | if (set & BIT(NL80211_STA_FLAG_SHORT_PREAMBLE)) |
| @@ -1469,6 +1139,13 @@ static int sta_apply_parameters(struct ieee80211_local *local, | |||
| 1469 | #endif | 1139 | #endif |
| 1470 | } | 1140 | } |
| 1471 | 1141 | ||
| 1142 | /* set the STA state after all sta info from usermode has been set */ | ||
| 1143 | if (test_sta_flag(sta, WLAN_STA_TDLS_PEER)) { | ||
| 1144 | ret = sta_apply_auth_flags(local, sta, mask, set); | ||
| 1145 | if (ret) | ||
| 1146 | return ret; | ||
| 1147 | } | ||
| 1148 | |||
| 1472 | return 0; | 1149 | return 0; |
| 1473 | } | 1150 | } |
| 1474 | 1151 | ||
| @@ -3076,7 +2753,8 @@ static int ieee80211_set_after_csa_beacon(struct ieee80211_sub_if_data *sdata, | |||
| 3076 | 2753 | ||
| 3077 | switch (sdata->vif.type) { | 2754 | switch (sdata->vif.type) { |
| 3078 | case NL80211_IFTYPE_AP: | 2755 | case NL80211_IFTYPE_AP: |
| 3079 | err = ieee80211_assign_beacon(sdata, sdata->u.ap.next_beacon); | 2756 | err = ieee80211_assign_beacon(sdata, sdata->u.ap.next_beacon, |
| 2757 | NULL); | ||
| 3080 | kfree(sdata->u.ap.next_beacon); | 2758 | kfree(sdata->u.ap.next_beacon); |
| 3081 | sdata->u.ap.next_beacon = NULL; | 2759 | sdata->u.ap.next_beacon = NULL; |
| 3082 | 2760 | ||
| @@ -3114,17 +2792,35 @@ static int __ieee80211_csa_finalize(struct ieee80211_sub_if_data *sdata) | |||
| 3114 | 2792 | ||
| 3115 | sdata_assert_lock(sdata); | 2793 | sdata_assert_lock(sdata); |
| 3116 | lockdep_assert_held(&local->mtx); | 2794 | lockdep_assert_held(&local->mtx); |
| 2795 | lockdep_assert_held(&local->chanctx_mtx); | ||
| 3117 | 2796 | ||
| 3118 | sdata->radar_required = sdata->csa_radar_required; | 2797 | /* |
| 3119 | err = ieee80211_vif_change_channel(sdata, &changed); | 2798 | * using reservation isn't immediate as it may be deferred until later |
| 3120 | if (err < 0) | 2799 | * with multi-vif. once reservation is complete it will re-schedule the |
| 3121 | return err; | 2800 | * work with no reserved_chanctx so verify chandef to check if it |
| 2801 | * completed successfully | ||
| 2802 | */ | ||
| 3122 | 2803 | ||
| 3123 | if (!local->use_chanctx) { | 2804 | if (sdata->reserved_chanctx) { |
| 3124 | local->_oper_chandef = sdata->csa_chandef; | 2805 | /* |
| 3125 | ieee80211_hw_config(local, 0); | 2806 | * with multi-vif csa driver may call ieee80211_csa_finish() |
| 2807 | * many times while waiting for other interfaces to use their | ||
| 2808 | * reservations | ||
| 2809 | */ | ||
| 2810 | if (sdata->reserved_ready) | ||
| 2811 | return 0; | ||
| 2812 | |||
| 2813 | err = ieee80211_vif_use_reserved_context(sdata); | ||
| 2814 | if (err) | ||
| 2815 | return err; | ||
| 2816 | |||
| 2817 | return 0; | ||
| 3126 | } | 2818 | } |
| 3127 | 2819 | ||
| 2820 | if (!cfg80211_chandef_identical(&sdata->vif.bss_conf.chandef, | ||
| 2821 | &sdata->csa_chandef)) | ||
| 2822 | return -EINVAL; | ||
| 2823 | |||
| 3128 | sdata->vif.csa_active = false; | 2824 | sdata->vif.csa_active = false; |
| 3129 | 2825 | ||
| 3130 | err = ieee80211_set_after_csa_beacon(sdata, &changed); | 2826 | err = ieee80211_set_after_csa_beacon(sdata, &changed); |
| @@ -3134,10 +2830,11 @@ static int __ieee80211_csa_finalize(struct ieee80211_sub_if_data *sdata) | |||
| 3134 | ieee80211_bss_info_change_notify(sdata, changed); | 2830 | ieee80211_bss_info_change_notify(sdata, changed); |
| 3135 | cfg80211_ch_switch_notify(sdata->dev, &sdata->csa_chandef); | 2831 | cfg80211_ch_switch_notify(sdata->dev, &sdata->csa_chandef); |
| 3136 | 2832 | ||
| 3137 | if (!ieee80211_csa_needs_block_tx(local)) | 2833 | if (sdata->csa_block_tx) { |
| 3138 | ieee80211_wake_queues_by_reason(&local->hw, | 2834 | ieee80211_wake_vif_queues(local, sdata, |
| 3139 | IEEE80211_MAX_QUEUE_MAP, | 2835 | IEEE80211_QUEUE_STOP_REASON_CSA); |
| 3140 | IEEE80211_QUEUE_STOP_REASON_CSA); | 2836 | sdata->csa_block_tx = false; |
| 2837 | } | ||
| 3141 | 2838 | ||
| 3142 | return 0; | 2839 | return 0; |
| 3143 | } | 2840 | } |
| @@ -3160,6 +2857,7 @@ void ieee80211_csa_finalize_work(struct work_struct *work) | |||
| 3160 | 2857 | ||
| 3161 | sdata_lock(sdata); | 2858 | sdata_lock(sdata); |
| 3162 | mutex_lock(&local->mtx); | 2859 | mutex_lock(&local->mtx); |
| 2860 | mutex_lock(&local->chanctx_mtx); | ||
| 3163 | 2861 | ||
| 3164 | /* AP might have been stopped while waiting for the lock. */ | 2862 | /* AP might have been stopped while waiting for the lock. */ |
| 3165 | if (!sdata->vif.csa_active) | 2863 | if (!sdata->vif.csa_active) |
| @@ -3171,6 +2869,7 @@ void ieee80211_csa_finalize_work(struct work_struct *work) | |||
| 3171 | ieee80211_csa_finalize(sdata); | 2869 | ieee80211_csa_finalize(sdata); |
| 3172 | 2870 | ||
| 3173 | unlock: | 2871 | unlock: |
| 2872 | mutex_unlock(&local->chanctx_mtx); | ||
| 3174 | mutex_unlock(&local->mtx); | 2873 | mutex_unlock(&local->mtx); |
| 3175 | sdata_unlock(sdata); | 2874 | sdata_unlock(sdata); |
| 3176 | } | 2875 | } |
| @@ -3179,6 +2878,7 @@ static int ieee80211_set_csa_beacon(struct ieee80211_sub_if_data *sdata, | |||
| 3179 | struct cfg80211_csa_settings *params, | 2878 | struct cfg80211_csa_settings *params, |
| 3180 | u32 *changed) | 2879 | u32 *changed) |
| 3181 | { | 2880 | { |
| 2881 | struct ieee80211_csa_settings csa = {}; | ||
| 3182 | int err; | 2882 | int err; |
| 3183 | 2883 | ||
| 3184 | switch (sdata->vif.type) { | 2884 | switch (sdata->vif.type) { |
| @@ -3213,20 +2913,13 @@ static int ieee80211_set_csa_beacon(struct ieee80211_sub_if_data *sdata, | |||
| 3213 | IEEE80211_MAX_CSA_COUNTERS_NUM)) | 2913 | IEEE80211_MAX_CSA_COUNTERS_NUM)) |
| 3214 | return -EINVAL; | 2914 | return -EINVAL; |
| 3215 | 2915 | ||
| 3216 | /* make sure we don't have garbage in other counters */ | 2916 | csa.counter_offsets_beacon = params->counter_offsets_beacon; |
| 3217 | memset(sdata->csa_counter_offset_beacon, 0, | 2917 | csa.counter_offsets_presp = params->counter_offsets_presp; |
| 3218 | sizeof(sdata->csa_counter_offset_beacon)); | 2918 | csa.n_counter_offsets_beacon = params->n_counter_offsets_beacon; |
| 3219 | memset(sdata->csa_counter_offset_presp, 0, | 2919 | csa.n_counter_offsets_presp = params->n_counter_offsets_presp; |
| 3220 | sizeof(sdata->csa_counter_offset_presp)); | 2920 | csa.count = params->count; |
| 3221 | |||
| 3222 | memcpy(sdata->csa_counter_offset_beacon, | ||
| 3223 | params->counter_offsets_beacon, | ||
| 3224 | params->n_counter_offsets_beacon * sizeof(u16)); | ||
| 3225 | memcpy(sdata->csa_counter_offset_presp, | ||
| 3226 | params->counter_offsets_presp, | ||
| 3227 | params->n_counter_offsets_presp * sizeof(u16)); | ||
| 3228 | 2921 | ||
| 3229 | err = ieee80211_assign_beacon(sdata, ¶ms->beacon_csa); | 2922 | err = ieee80211_assign_beacon(sdata, ¶ms->beacon_csa, &csa); |
| 3230 | if (err < 0) { | 2923 | if (err < 0) { |
| 3231 | kfree(sdata->u.ap.next_beacon); | 2924 | kfree(sdata->u.ap.next_beacon); |
| 3232 | return err; | 2925 | return err; |
| @@ -3322,7 +3015,7 @@ __ieee80211_channel_switch(struct wiphy *wiphy, struct net_device *dev, | |||
| 3322 | struct ieee80211_local *local = sdata->local; | 3015 | struct ieee80211_local *local = sdata->local; |
| 3323 | struct ieee80211_chanctx_conf *conf; | 3016 | struct ieee80211_chanctx_conf *conf; |
| 3324 | struct ieee80211_chanctx *chanctx; | 3017 | struct ieee80211_chanctx *chanctx; |
| 3325 | int err, num_chanctx, changed = 0; | 3018 | int err, changed = 0; |
| 3326 | 3019 | ||
| 3327 | sdata_assert_lock(sdata); | 3020 | sdata_assert_lock(sdata); |
| 3328 | lockdep_assert_held(&local->mtx); | 3021 | lockdep_assert_held(&local->mtx); |
| @@ -3337,46 +3030,50 @@ __ieee80211_channel_switch(struct wiphy *wiphy, struct net_device *dev, | |||
| 3337 | &sdata->vif.bss_conf.chandef)) | 3030 | &sdata->vif.bss_conf.chandef)) |
| 3338 | return -EINVAL; | 3031 | return -EINVAL; |
| 3339 | 3032 | ||
| 3033 | /* don't allow another channel switch if one is already active. */ | ||
| 3034 | if (sdata->vif.csa_active) | ||
| 3035 | return -EBUSY; | ||
| 3036 | |||
| 3340 | mutex_lock(&local->chanctx_mtx); | 3037 | mutex_lock(&local->chanctx_mtx); |
| 3341 | conf = rcu_dereference_protected(sdata->vif.chanctx_conf, | 3038 | conf = rcu_dereference_protected(sdata->vif.chanctx_conf, |
| 3342 | lockdep_is_held(&local->chanctx_mtx)); | 3039 | lockdep_is_held(&local->chanctx_mtx)); |
| 3343 | if (!conf) { | 3040 | if (!conf) { |
| 3344 | mutex_unlock(&local->chanctx_mtx); | 3041 | err = -EBUSY; |
| 3345 | return -EBUSY; | 3042 | goto out; |
| 3346 | } | 3043 | } |
| 3347 | 3044 | ||
| 3348 | /* don't handle for multi-VIF cases */ | ||
| 3349 | chanctx = container_of(conf, struct ieee80211_chanctx, conf); | 3045 | chanctx = container_of(conf, struct ieee80211_chanctx, conf); |
| 3350 | if (ieee80211_chanctx_refcount(local, chanctx) > 1) { | 3046 | if (!chanctx) { |
| 3351 | mutex_unlock(&local->chanctx_mtx); | 3047 | err = -EBUSY; |
| 3352 | return -EBUSY; | 3048 | goto out; |
| 3353 | } | 3049 | } |
| 3354 | num_chanctx = 0; | ||
| 3355 | list_for_each_entry_rcu(chanctx, &local->chanctx_list, list) | ||
| 3356 | num_chanctx++; | ||
| 3357 | mutex_unlock(&local->chanctx_mtx); | ||
| 3358 | 3050 | ||
| 3359 | if (num_chanctx > 1) | 3051 | err = ieee80211_vif_reserve_chanctx(sdata, ¶ms->chandef, |
| 3360 | return -EBUSY; | 3052 | chanctx->mode, |
| 3053 | params->radar_required); | ||
| 3054 | if (err) | ||
| 3055 | goto out; | ||
| 3361 | 3056 | ||
| 3362 | /* don't allow another channel switch if one is already active. */ | 3057 | /* if reservation is invalid then this will fail */ |
| 3363 | if (sdata->vif.csa_active) | 3058 | err = ieee80211_check_combinations(sdata, NULL, chanctx->mode, 0); |
| 3364 | return -EBUSY; | 3059 | if (err) { |
| 3060 | ieee80211_vif_unreserve_chanctx(sdata); | ||
| 3061 | goto out; | ||
| 3062 | } | ||
| 3365 | 3063 | ||
| 3366 | err = ieee80211_set_csa_beacon(sdata, params, &changed); | 3064 | err = ieee80211_set_csa_beacon(sdata, params, &changed); |
| 3367 | if (err) | 3065 | if (err) { |
| 3368 | return err; | 3066 | ieee80211_vif_unreserve_chanctx(sdata); |
| 3067 | goto out; | ||
| 3068 | } | ||
| 3369 | 3069 | ||
| 3370 | sdata->csa_radar_required = params->radar_required; | ||
| 3371 | sdata->csa_chandef = params->chandef; | 3070 | sdata->csa_chandef = params->chandef; |
| 3372 | sdata->csa_block_tx = params->block_tx; | 3071 | sdata->csa_block_tx = params->block_tx; |
| 3373 | sdata->csa_current_counter = params->count; | ||
| 3374 | sdata->vif.csa_active = true; | 3072 | sdata->vif.csa_active = true; |
| 3375 | 3073 | ||
| 3376 | if (sdata->csa_block_tx) | 3074 | if (sdata->csa_block_tx) |
| 3377 | ieee80211_stop_queues_by_reason(&local->hw, | 3075 | ieee80211_stop_vif_queues(local, sdata, |
| 3378 | IEEE80211_MAX_QUEUE_MAP, | 3076 | IEEE80211_QUEUE_STOP_REASON_CSA); |
| 3379 | IEEE80211_QUEUE_STOP_REASON_CSA); | ||
| 3380 | 3077 | ||
| 3381 | if (changed) { | 3078 | if (changed) { |
| 3382 | ieee80211_bss_info_change_notify(sdata, changed); | 3079 | ieee80211_bss_info_change_notify(sdata, changed); |
| @@ -3386,7 +3083,9 @@ __ieee80211_channel_switch(struct wiphy *wiphy, struct net_device *dev, | |||
| 3386 | ieee80211_csa_finalize(sdata); | 3083 | ieee80211_csa_finalize(sdata); |
| 3387 | } | 3084 | } |
| 3388 | 3085 | ||
| 3389 | return 0; | 3086 | out: |
| 3087 | mutex_unlock(&local->chanctx_mtx); | ||
| 3088 | return err; | ||
| 3390 | } | 3089 | } |
| 3391 | 3090 | ||
| 3392 | int ieee80211_channel_switch(struct wiphy *wiphy, struct net_device *dev, | 3091 | int ieee80211_channel_switch(struct wiphy *wiphy, struct net_device *dev, |
| @@ -3518,10 +3217,23 @@ static int ieee80211_mgmt_tx(struct wiphy *wiphy, struct wireless_dev *wdev, | |||
| 3518 | sdata->vif.type == NL80211_IFTYPE_ADHOC) && | 3217 | sdata->vif.type == NL80211_IFTYPE_ADHOC) && |
| 3519 | params->n_csa_offsets) { | 3218 | params->n_csa_offsets) { |
| 3520 | int i; | 3219 | int i; |
| 3521 | u8 c = sdata->csa_current_counter; | 3220 | struct beacon_data *beacon = NULL; |
| 3522 | 3221 | ||
| 3523 | for (i = 0; i < params->n_csa_offsets; i++) | 3222 | rcu_read_lock(); |
| 3524 | data[params->csa_offsets[i]] = c; | 3223 | |
| 3224 | if (sdata->vif.type == NL80211_IFTYPE_AP) | ||
| 3225 | beacon = rcu_dereference(sdata->u.ap.beacon); | ||
| 3226 | else if (sdata->vif.type == NL80211_IFTYPE_ADHOC) | ||
| 3227 | beacon = rcu_dereference(sdata->u.ibss.presp); | ||
| 3228 | else if (ieee80211_vif_is_mesh(&sdata->vif)) | ||
| 3229 | beacon = rcu_dereference(sdata->u.mesh.beacon); | ||
| 3230 | |||
| 3231 | if (beacon) | ||
| 3232 | for (i = 0; i < params->n_csa_offsets; i++) | ||
| 3233 | data[params->csa_offsets[i]] = | ||
| 3234 | beacon->csa_current_counter; | ||
| 3235 | |||
| 3236 | rcu_read_unlock(); | ||
| 3525 | } | 3237 | } |
| 3526 | 3238 | ||
| 3527 | IEEE80211_SKB_CB(skb)->flags = flags; | 3239 | IEEE80211_SKB_CB(skb)->flags = flags; |
| @@ -3601,21 +3313,6 @@ static int ieee80211_get_antenna(struct wiphy *wiphy, u32 *tx_ant, u32 *rx_ant) | |||
| 3601 | return drv_get_antenna(local, tx_ant, rx_ant); | 3313 | return drv_get_antenna(local, tx_ant, rx_ant); |
| 3602 | } | 3314 | } |
| 3603 | 3315 | ||
| 3604 | static int ieee80211_set_ringparam(struct wiphy *wiphy, u32 tx, u32 rx) | ||
| 3605 | { | ||
| 3606 | struct ieee80211_local *local = wiphy_priv(wiphy); | ||
| 3607 | |||
| 3608 | return drv_set_ringparam(local, tx, rx); | ||
| 3609 | } | ||
| 3610 | |||
| 3611 | static void ieee80211_get_ringparam(struct wiphy *wiphy, | ||
| 3612 | u32 *tx, u32 *tx_max, u32 *rx, u32 *rx_max) | ||
| 3613 | { | ||
| 3614 | struct ieee80211_local *local = wiphy_priv(wiphy); | ||
| 3615 | |||
| 3616 | drv_get_ringparam(local, tx, tx_max, rx, rx_max); | ||
| 3617 | } | ||
| 3618 | |||
| 3619 | static int ieee80211_set_rekey_data(struct wiphy *wiphy, | 3316 | static int ieee80211_set_rekey_data(struct wiphy *wiphy, |
| 3620 | struct net_device *dev, | 3317 | struct net_device *dev, |
| 3621 | struct cfg80211_gtk_rekey_data *data) | 3318 | struct cfg80211_gtk_rekey_data *data) |
| @@ -3847,8 +3544,6 @@ const struct cfg80211_ops mac80211_config_ops = { | |||
| 3847 | .mgmt_frame_register = ieee80211_mgmt_frame_register, | 3544 | .mgmt_frame_register = ieee80211_mgmt_frame_register, |
| 3848 | .set_antenna = ieee80211_set_antenna, | 3545 | .set_antenna = ieee80211_set_antenna, |
| 3849 | .get_antenna = ieee80211_get_antenna, | 3546 | .get_antenna = ieee80211_get_antenna, |
| 3850 | .set_ringparam = ieee80211_set_ringparam, | ||
| 3851 | .get_ringparam = ieee80211_get_ringparam, | ||
| 3852 | .set_rekey_data = ieee80211_set_rekey_data, | 3547 | .set_rekey_data = ieee80211_set_rekey_data, |
| 3853 | .tdls_oper = ieee80211_tdls_oper, | 3548 | .tdls_oper = ieee80211_tdls_oper, |
| 3854 | .tdls_mgmt = ieee80211_tdls_mgmt, | 3549 | .tdls_mgmt = ieee80211_tdls_mgmt, |
| @@ -3857,9 +3552,6 @@ const struct cfg80211_ops mac80211_config_ops = { | |||
| 3857 | #ifdef CONFIG_PM | 3552 | #ifdef CONFIG_PM |
| 3858 | .set_wakeup = ieee80211_set_wakeup, | 3553 | .set_wakeup = ieee80211_set_wakeup, |
| 3859 | #endif | 3554 | #endif |
| 3860 | .get_et_sset_count = ieee80211_get_et_sset_count, | ||
| 3861 | .get_et_stats = ieee80211_get_et_stats, | ||
| 3862 | .get_et_strings = ieee80211_get_et_strings, | ||
| 3863 | .get_channel = ieee80211_cfg_get_channel, | 3555 | .get_channel = ieee80211_cfg_get_channel, |
| 3864 | .start_radar_detection = ieee80211_start_radar_detection, | 3556 | .start_radar_detection = ieee80211_start_radar_detection, |
| 3865 | .channel_switch = ieee80211_channel_switch, | 3557 | .channel_switch = ieee80211_channel_switch, |
diff --git a/net/mac80211/chan.c b/net/mac80211/chan.c index a310e33972de..6d537f03c0ba 100644 --- a/net/mac80211/chan.c +++ b/net/mac80211/chan.c | |||
| @@ -63,6 +63,20 @@ static bool ieee80211_can_create_new_chanctx(struct ieee80211_local *local) | |||
| 63 | return ieee80211_num_chanctx(local) < ieee80211_max_num_channels(local); | 63 | return ieee80211_num_chanctx(local) < ieee80211_max_num_channels(local); |
| 64 | } | 64 | } |
| 65 | 65 | ||
| 66 | static struct ieee80211_chanctx * | ||
| 67 | ieee80211_vif_get_chanctx(struct ieee80211_sub_if_data *sdata) | ||
| 68 | { | ||
| 69 | struct ieee80211_local *local __maybe_unused = sdata->local; | ||
| 70 | struct ieee80211_chanctx_conf *conf; | ||
| 71 | |||
| 72 | conf = rcu_dereference_protected(sdata->vif.chanctx_conf, | ||
| 73 | lockdep_is_held(&local->chanctx_mtx)); | ||
| 74 | if (!conf) | ||
| 75 | return NULL; | ||
| 76 | |||
| 77 | return container_of(conf, struct ieee80211_chanctx, conf); | ||
| 78 | } | ||
| 79 | |||
| 66 | static const struct cfg80211_chan_def * | 80 | static const struct cfg80211_chan_def * |
| 67 | ieee80211_chanctx_reserved_chandef(struct ieee80211_local *local, | 81 | ieee80211_chanctx_reserved_chandef(struct ieee80211_local *local, |
| 68 | struct ieee80211_chanctx *ctx, | 82 | struct ieee80211_chanctx *ctx, |
| @@ -160,6 +174,9 @@ ieee80211_find_reservation_chanctx(struct ieee80211_local *local, | |||
| 160 | return NULL; | 174 | return NULL; |
| 161 | 175 | ||
| 162 | list_for_each_entry(ctx, &local->chanctx_list, list) { | 176 | list_for_each_entry(ctx, &local->chanctx_list, list) { |
| 177 | if (ctx->replace_state == IEEE80211_CHANCTX_WILL_BE_REPLACED) | ||
| 178 | continue; | ||
| 179 | |||
| 163 | if (ctx->mode == IEEE80211_CHANCTX_EXCLUSIVE) | 180 | if (ctx->mode == IEEE80211_CHANCTX_EXCLUSIVE) |
| 164 | continue; | 181 | continue; |
| 165 | 182 | ||
| @@ -347,6 +364,9 @@ ieee80211_find_chanctx(struct ieee80211_local *local, | |||
| 347 | list_for_each_entry(ctx, &local->chanctx_list, list) { | 364 | list_for_each_entry(ctx, &local->chanctx_list, list) { |
| 348 | const struct cfg80211_chan_def *compat; | 365 | const struct cfg80211_chan_def *compat; |
| 349 | 366 | ||
| 367 | if (ctx->replace_state != IEEE80211_CHANCTX_REPLACE_NONE) | ||
| 368 | continue; | ||
| 369 | |||
| 350 | if (ctx->mode == IEEE80211_CHANCTX_EXCLUSIVE) | 370 | if (ctx->mode == IEEE80211_CHANCTX_EXCLUSIVE) |
| 351 | continue; | 371 | continue; |
| 352 | 372 | ||
| @@ -622,6 +642,7 @@ static void __ieee80211_vif_release_channel(struct ieee80211_sub_if_data *sdata) | |||
| 622 | struct ieee80211_local *local = sdata->local; | 642 | struct ieee80211_local *local = sdata->local; |
| 623 | struct ieee80211_chanctx_conf *conf; | 643 | struct ieee80211_chanctx_conf *conf; |
| 624 | struct ieee80211_chanctx *ctx; | 644 | struct ieee80211_chanctx *ctx; |
| 645 | bool use_reserved_switch = false; | ||
| 625 | 646 | ||
| 626 | lockdep_assert_held(&local->chanctx_mtx); | 647 | lockdep_assert_held(&local->chanctx_mtx); |
| 627 | 648 | ||
| @@ -632,12 +653,23 @@ static void __ieee80211_vif_release_channel(struct ieee80211_sub_if_data *sdata) | |||
| 632 | 653 | ||
| 633 | ctx = container_of(conf, struct ieee80211_chanctx, conf); | 654 | ctx = container_of(conf, struct ieee80211_chanctx, conf); |
| 634 | 655 | ||
| 635 | if (sdata->reserved_chanctx) | 656 | if (sdata->reserved_chanctx) { |
| 657 | if (sdata->reserved_chanctx->replace_state == | ||
| 658 | IEEE80211_CHANCTX_REPLACES_OTHER && | ||
| 659 | ieee80211_chanctx_num_reserved(local, | ||
| 660 | sdata->reserved_chanctx) > 1) | ||
| 661 | use_reserved_switch = true; | ||
| 662 | |||
| 636 | ieee80211_vif_unreserve_chanctx(sdata); | 663 | ieee80211_vif_unreserve_chanctx(sdata); |
| 664 | } | ||
| 637 | 665 | ||
| 638 | ieee80211_assign_vif_chanctx(sdata, NULL); | 666 | ieee80211_assign_vif_chanctx(sdata, NULL); |
| 639 | if (ieee80211_chanctx_refcount(local, ctx) == 0) | 667 | if (ieee80211_chanctx_refcount(local, ctx) == 0) |
| 640 | ieee80211_free_chanctx(local, ctx); | 668 | ieee80211_free_chanctx(local, ctx); |
| 669 | |||
| 670 | /* Unreserving may ready an in-place reservation. */ | ||
| 671 | if (use_reserved_switch) | ||
| 672 | ieee80211_vif_use_reserved_switch(local); | ||
| 641 | } | 673 | } |
| 642 | 674 | ||
| 643 | void ieee80211_recalc_smps_chanctx(struct ieee80211_local *local, | 675 | void ieee80211_recalc_smps_chanctx(struct ieee80211_local *local, |
| @@ -787,70 +819,6 @@ int ieee80211_vif_use_channel(struct ieee80211_sub_if_data *sdata, | |||
| 787 | return ret; | 819 | return ret; |
| 788 | } | 820 | } |
| 789 | 821 | ||
| 790 | static int __ieee80211_vif_change_channel(struct ieee80211_sub_if_data *sdata, | ||
| 791 | struct ieee80211_chanctx *ctx, | ||
| 792 | u32 *changed) | ||
| 793 | { | ||
| 794 | struct ieee80211_local *local = sdata->local; | ||
| 795 | const struct cfg80211_chan_def *chandef = &sdata->csa_chandef; | ||
| 796 | u32 chanctx_changed = 0; | ||
| 797 | |||
| 798 | if (!cfg80211_chandef_usable(sdata->local->hw.wiphy, chandef, | ||
| 799 | IEEE80211_CHAN_DISABLED)) | ||
| 800 | return -EINVAL; | ||
| 801 | |||
| 802 | if (ieee80211_chanctx_refcount(local, ctx) != 1) | ||
| 803 | return -EINVAL; | ||
| 804 | |||
| 805 | if (sdata->vif.bss_conf.chandef.width != chandef->width) { | ||
| 806 | chanctx_changed = IEEE80211_CHANCTX_CHANGE_WIDTH; | ||
| 807 | *changed |= BSS_CHANGED_BANDWIDTH; | ||
| 808 | } | ||
| 809 | |||
| 810 | sdata->vif.bss_conf.chandef = *chandef; | ||
| 811 | ctx->conf.def = *chandef; | ||
| 812 | |||
| 813 | chanctx_changed |= IEEE80211_CHANCTX_CHANGE_CHANNEL; | ||
| 814 | drv_change_chanctx(local, ctx, chanctx_changed); | ||
| 815 | |||
| 816 | ieee80211_recalc_chanctx_chantype(local, ctx); | ||
| 817 | ieee80211_recalc_smps_chanctx(local, ctx); | ||
| 818 | ieee80211_recalc_radar_chanctx(local, ctx); | ||
| 819 | ieee80211_recalc_chanctx_min_def(local, ctx); | ||
| 820 | |||
| 821 | return 0; | ||
| 822 | } | ||
| 823 | |||
| 824 | int ieee80211_vif_change_channel(struct ieee80211_sub_if_data *sdata, | ||
| 825 | u32 *changed) | ||
| 826 | { | ||
| 827 | struct ieee80211_local *local = sdata->local; | ||
| 828 | struct ieee80211_chanctx_conf *conf; | ||
| 829 | struct ieee80211_chanctx *ctx; | ||
| 830 | int ret; | ||
| 831 | |||
| 832 | lockdep_assert_held(&local->mtx); | ||
| 833 | |||
| 834 | /* should never be called if not performing a channel switch. */ | ||
| 835 | if (WARN_ON(!sdata->vif.csa_active)) | ||
| 836 | return -EINVAL; | ||
| 837 | |||
| 838 | mutex_lock(&local->chanctx_mtx); | ||
| 839 | conf = rcu_dereference_protected(sdata->vif.chanctx_conf, | ||
| 840 | lockdep_is_held(&local->chanctx_mtx)); | ||
| 841 | if (!conf) { | ||
| 842 | ret = -EINVAL; | ||
| 843 | goto out; | ||
| 844 | } | ||
| 845 | |||
| 846 | ctx = container_of(conf, struct ieee80211_chanctx, conf); | ||
| 847 | |||
| 848 | ret = __ieee80211_vif_change_channel(sdata, ctx, changed); | ||
| 849 | out: | ||
| 850 | mutex_unlock(&local->chanctx_mtx); | ||
| 851 | return ret; | ||
| 852 | } | ||
| 853 | |||
| 854 | static void | 822 | static void |
| 855 | __ieee80211_vif_copy_chanctx_to_vlans(struct ieee80211_sub_if_data *sdata, | 823 | __ieee80211_vif_copy_chanctx_to_vlans(struct ieee80211_sub_if_data *sdata, |
| 856 | bool clear) | 824 | bool clear) |
| @@ -905,8 +873,25 @@ int ieee80211_vif_unreserve_chanctx(struct ieee80211_sub_if_data *sdata) | |||
| 905 | list_del(&sdata->reserved_chanctx_list); | 873 | list_del(&sdata->reserved_chanctx_list); |
| 906 | sdata->reserved_chanctx = NULL; | 874 | sdata->reserved_chanctx = NULL; |
| 907 | 875 | ||
| 908 | if (ieee80211_chanctx_refcount(sdata->local, ctx) == 0) | 876 | if (ieee80211_chanctx_refcount(sdata->local, ctx) == 0) { |
| 909 | ieee80211_free_chanctx(sdata->local, ctx); | 877 | if (ctx->replace_state == IEEE80211_CHANCTX_REPLACES_OTHER) { |
| 878 | if (WARN_ON(!ctx->replace_ctx)) | ||
| 879 | return -EINVAL; | ||
| 880 | |||
| 881 | WARN_ON(ctx->replace_ctx->replace_state != | ||
| 882 | IEEE80211_CHANCTX_WILL_BE_REPLACED); | ||
| 883 | WARN_ON(ctx->replace_ctx->replace_ctx != ctx); | ||
| 884 | |||
| 885 | ctx->replace_ctx->replace_ctx = NULL; | ||
| 886 | ctx->replace_ctx->replace_state = | ||
| 887 | IEEE80211_CHANCTX_REPLACE_NONE; | ||
| 888 | |||
| 889 | list_del_rcu(&ctx->list); | ||
| 890 | kfree_rcu(ctx, rcu_head); | ||
| 891 | } else { | ||
| 892 | ieee80211_free_chanctx(sdata->local, ctx); | ||
| 893 | } | ||
| 894 | } | ||
| 910 | 895 | ||
| 911 | return 0; | 896 | return 0; |
| 912 | } | 897 | } |
| @@ -917,40 +902,84 @@ int ieee80211_vif_reserve_chanctx(struct ieee80211_sub_if_data *sdata, | |||
| 917 | bool radar_required) | 902 | bool radar_required) |
| 918 | { | 903 | { |
| 919 | struct ieee80211_local *local = sdata->local; | 904 | struct ieee80211_local *local = sdata->local; |
| 920 | struct ieee80211_chanctx_conf *conf; | 905 | struct ieee80211_chanctx *new_ctx, *curr_ctx, *ctx; |
| 921 | struct ieee80211_chanctx *new_ctx, *curr_ctx; | ||
| 922 | int ret = 0; | ||
| 923 | 906 | ||
| 924 | mutex_lock(&local->chanctx_mtx); | 907 | lockdep_assert_held(&local->chanctx_mtx); |
| 925 | |||
| 926 | conf = rcu_dereference_protected(sdata->vif.chanctx_conf, | ||
| 927 | lockdep_is_held(&local->chanctx_mtx)); | ||
| 928 | if (!conf) { | ||
| 929 | ret = -EINVAL; | ||
| 930 | goto out; | ||
| 931 | } | ||
| 932 | 908 | ||
| 933 | curr_ctx = container_of(conf, struct ieee80211_chanctx, conf); | 909 | curr_ctx = ieee80211_vif_get_chanctx(sdata); |
| 910 | if (curr_ctx && local->use_chanctx && !local->ops->switch_vif_chanctx) | ||
| 911 | return -ENOTSUPP; | ||
| 934 | 912 | ||
| 935 | new_ctx = ieee80211_find_reservation_chanctx(local, chandef, mode); | 913 | new_ctx = ieee80211_find_reservation_chanctx(local, chandef, mode); |
| 936 | if (!new_ctx) { | 914 | if (!new_ctx) { |
| 937 | if (ieee80211_chanctx_refcount(local, curr_ctx) == 1 && | 915 | if (ieee80211_can_create_new_chanctx(local)) { |
| 938 | (local->hw.flags & IEEE80211_HW_CHANGE_RUNNING_CHANCTX)) { | ||
| 939 | /* if we're the only users of the chanctx and | ||
| 940 | * the driver supports changing a running | ||
| 941 | * context, reserve our current context | ||
| 942 | */ | ||
| 943 | new_ctx = curr_ctx; | ||
| 944 | } else if (ieee80211_can_create_new_chanctx(local)) { | ||
| 945 | /* create a new context and reserve it */ | ||
| 946 | new_ctx = ieee80211_new_chanctx(local, chandef, mode); | 916 | new_ctx = ieee80211_new_chanctx(local, chandef, mode); |
| 947 | if (IS_ERR(new_ctx)) { | 917 | if (IS_ERR(new_ctx)) |
| 948 | ret = PTR_ERR(new_ctx); | 918 | return PTR_ERR(new_ctx); |
| 949 | goto out; | ||
| 950 | } | ||
| 951 | } else { | 919 | } else { |
| 952 | ret = -EBUSY; | 920 | if (!curr_ctx || |
| 953 | goto out; | 921 | (curr_ctx->replace_state == |
| 922 | IEEE80211_CHANCTX_WILL_BE_REPLACED) || | ||
| 923 | !list_empty(&curr_ctx->reserved_vifs)) { | ||
| 924 | /* | ||
| 925 | * Another vif already requested this context | ||
| 926 | * for a reservation. Find another one hoping | ||
| 927 | * all vifs assigned to it will also switch | ||
| 928 | * soon enough. | ||
| 929 | * | ||
| 930 | * TODO: This needs a little more work as some | ||
| 931 | * cases (more than 2 chanctx capable devices) | ||
| 932 | * may fail which could otherwise succeed | ||
| 933 | * provided some channel context juggling was | ||
| 934 | * performed. | ||
| 935 | * | ||
| 936 | * Consider ctx1..3, vif1..6, each ctx has 2 | ||
| 937 | * vifs. vif1 and vif2 from ctx1 request new | ||
| 938 | * different chandefs starting 2 in-place | ||
| 939 | * reserations with ctx4 and ctx5 replacing | ||
| 940 | * ctx1 and ctx2 respectively. Next vif5 and | ||
| 941 | * vif6 from ctx3 reserve ctx4. If vif3 and | ||
| 942 | * vif4 remain on ctx2 as they are then this | ||
| 943 | * fails unless `replace_ctx` from ctx5 is | ||
| 944 | * replaced with ctx3. | ||
| 945 | */ | ||
| 946 | list_for_each_entry(ctx, &local->chanctx_list, | ||
| 947 | list) { | ||
| 948 | if (ctx->replace_state != | ||
| 949 | IEEE80211_CHANCTX_REPLACE_NONE) | ||
| 950 | continue; | ||
| 951 | |||
| 952 | if (!list_empty(&ctx->reserved_vifs)) | ||
| 953 | continue; | ||
| 954 | |||
| 955 | curr_ctx = ctx; | ||
| 956 | break; | ||
| 957 | } | ||
| 958 | } | ||
| 959 | |||
| 960 | /* | ||
| 961 | * If that's true then all available contexts already | ||
| 962 | * have reservations and cannot be used. | ||
| 963 | */ | ||
| 964 | if (!curr_ctx || | ||
| 965 | (curr_ctx->replace_state == | ||
| 966 | IEEE80211_CHANCTX_WILL_BE_REPLACED) || | ||
| 967 | !list_empty(&curr_ctx->reserved_vifs)) | ||
| 968 | return -EBUSY; | ||
| 969 | |||
| 970 | new_ctx = ieee80211_alloc_chanctx(local, chandef, mode); | ||
| 971 | if (!new_ctx) | ||
| 972 | return -ENOMEM; | ||
| 973 | |||
| 974 | new_ctx->replace_ctx = curr_ctx; | ||
| 975 | new_ctx->replace_state = | ||
| 976 | IEEE80211_CHANCTX_REPLACES_OTHER; | ||
| 977 | |||
| 978 | curr_ctx->replace_ctx = new_ctx; | ||
| 979 | curr_ctx->replace_state = | ||
| 980 | IEEE80211_CHANCTX_WILL_BE_REPLACED; | ||
| 981 | |||
| 982 | list_add_rcu(&new_ctx->list, &local->chanctx_list); | ||
| 954 | } | 983 | } |
| 955 | } | 984 | } |
| 956 | 985 | ||
| @@ -958,82 +987,601 @@ int ieee80211_vif_reserve_chanctx(struct ieee80211_sub_if_data *sdata, | |||
| 958 | sdata->reserved_chanctx = new_ctx; | 987 | sdata->reserved_chanctx = new_ctx; |
| 959 | sdata->reserved_chandef = *chandef; | 988 | sdata->reserved_chandef = *chandef; |
| 960 | sdata->reserved_radar_required = radar_required; | 989 | sdata->reserved_radar_required = radar_required; |
| 961 | out: | 990 | sdata->reserved_ready = false; |
| 962 | mutex_unlock(&local->chanctx_mtx); | 991 | |
| 963 | return ret; | 992 | return 0; |
| 964 | } | 993 | } |
| 965 | 994 | ||
| 966 | int ieee80211_vif_use_reserved_context(struct ieee80211_sub_if_data *sdata, | 995 | static void |
| 967 | u32 *changed) | 996 | ieee80211_vif_chanctx_reservation_complete(struct ieee80211_sub_if_data *sdata) |
| 968 | { | 997 | { |
| 969 | struct ieee80211_local *local = sdata->local; | 998 | switch (sdata->vif.type) { |
| 970 | struct ieee80211_chanctx *ctx; | 999 | case NL80211_IFTYPE_ADHOC: |
| 971 | struct ieee80211_chanctx *old_ctx; | 1000 | case NL80211_IFTYPE_AP: |
| 972 | struct ieee80211_chanctx_conf *conf; | 1001 | case NL80211_IFTYPE_MESH_POINT: |
| 973 | int ret; | 1002 | ieee80211_queue_work(&sdata->local->hw, |
| 974 | u32 tmp_changed = *changed; | 1003 | &sdata->csa_finalize_work); |
| 1004 | break; | ||
| 1005 | case NL80211_IFTYPE_STATION: | ||
| 1006 | ieee80211_queue_work(&sdata->local->hw, | ||
| 1007 | &sdata->u.mgd.chswitch_work); | ||
| 1008 | break; | ||
| 1009 | case NL80211_IFTYPE_UNSPECIFIED: | ||
| 1010 | case NL80211_IFTYPE_AP_VLAN: | ||
| 1011 | case NL80211_IFTYPE_WDS: | ||
| 1012 | case NL80211_IFTYPE_MONITOR: | ||
| 1013 | case NL80211_IFTYPE_P2P_CLIENT: | ||
| 1014 | case NL80211_IFTYPE_P2P_GO: | ||
| 1015 | case NL80211_IFTYPE_P2P_DEVICE: | ||
| 1016 | case NUM_NL80211_IFTYPES: | ||
| 1017 | WARN_ON(1); | ||
| 1018 | break; | ||
| 1019 | } | ||
| 1020 | } | ||
| 975 | 1021 | ||
| 976 | /* TODO: need to recheck if the chandef is usable etc.? */ | 1022 | static int |
| 1023 | ieee80211_vif_use_reserved_reassign(struct ieee80211_sub_if_data *sdata) | ||
| 1024 | { | ||
| 1025 | struct ieee80211_local *local = sdata->local; | ||
| 1026 | struct ieee80211_vif_chanctx_switch vif_chsw[1] = {}; | ||
| 1027 | struct ieee80211_chanctx *old_ctx, *new_ctx; | ||
| 1028 | const struct cfg80211_chan_def *chandef; | ||
| 1029 | u32 changed = 0; | ||
| 1030 | int err; | ||
| 977 | 1031 | ||
| 978 | lockdep_assert_held(&local->mtx); | 1032 | lockdep_assert_held(&local->mtx); |
| 1033 | lockdep_assert_held(&local->chanctx_mtx); | ||
| 979 | 1034 | ||
| 980 | mutex_lock(&local->chanctx_mtx); | 1035 | new_ctx = sdata->reserved_chanctx; |
| 1036 | old_ctx = ieee80211_vif_get_chanctx(sdata); | ||
| 981 | 1037 | ||
| 982 | ctx = sdata->reserved_chanctx; | 1038 | if (WARN_ON(!sdata->reserved_ready)) |
| 983 | if (WARN_ON(!ctx)) { | 1039 | return -EBUSY; |
| 984 | ret = -EINVAL; | 1040 | |
| 985 | goto out; | 1041 | if (WARN_ON(!new_ctx)) |
| 986 | } | 1042 | return -EINVAL; |
| 1043 | |||
| 1044 | if (WARN_ON(!old_ctx)) | ||
| 1045 | return -EINVAL; | ||
| 1046 | |||
| 1047 | if (WARN_ON(new_ctx->replace_state == | ||
| 1048 | IEEE80211_CHANCTX_REPLACES_OTHER)) | ||
| 1049 | return -EINVAL; | ||
| 1050 | |||
| 1051 | chandef = ieee80211_chanctx_non_reserved_chandef(local, new_ctx, | ||
| 1052 | &sdata->reserved_chandef); | ||
| 1053 | if (WARN_ON(!chandef)) | ||
| 1054 | return -EINVAL; | ||
| 1055 | |||
| 1056 | vif_chsw[0].vif = &sdata->vif; | ||
| 1057 | vif_chsw[0].old_ctx = &old_ctx->conf; | ||
| 1058 | vif_chsw[0].new_ctx = &new_ctx->conf; | ||
| 1059 | |||
| 1060 | list_del(&sdata->reserved_chanctx_list); | ||
| 1061 | sdata->reserved_chanctx = NULL; | ||
| 1062 | |||
| 1063 | err = drv_switch_vif_chanctx(local, vif_chsw, 1, | ||
| 1064 | CHANCTX_SWMODE_REASSIGN_VIF); | ||
| 1065 | if (err) { | ||
| 1066 | if (ieee80211_chanctx_refcount(local, new_ctx) == 0) | ||
| 1067 | ieee80211_free_chanctx(local, new_ctx); | ||
| 987 | 1068 | ||
| 988 | conf = rcu_dereference_protected(sdata->vif.chanctx_conf, | ||
| 989 | lockdep_is_held(&local->chanctx_mtx)); | ||
| 990 | if (!conf) { | ||
| 991 | ret = -EINVAL; | ||
| 992 | goto out; | 1069 | goto out; |
| 993 | } | 1070 | } |
| 994 | 1071 | ||
| 995 | old_ctx = container_of(conf, struct ieee80211_chanctx, conf); | 1072 | list_move(&sdata->assigned_chanctx_list, &new_ctx->assigned_vifs); |
| 1073 | rcu_assign_pointer(sdata->vif.chanctx_conf, &new_ctx->conf); | ||
| 1074 | |||
| 1075 | if (sdata->vif.type == NL80211_IFTYPE_AP) | ||
| 1076 | __ieee80211_vif_copy_chanctx_to_vlans(sdata, false); | ||
| 1077 | |||
| 1078 | if (ieee80211_chanctx_refcount(local, old_ctx) == 0) | ||
| 1079 | ieee80211_free_chanctx(local, old_ctx); | ||
| 996 | 1080 | ||
| 997 | if (sdata->vif.bss_conf.chandef.width != sdata->reserved_chandef.width) | 1081 | if (sdata->vif.bss_conf.chandef.width != sdata->reserved_chandef.width) |
| 998 | tmp_changed |= BSS_CHANGED_BANDWIDTH; | 1082 | changed = BSS_CHANGED_BANDWIDTH; |
| 999 | 1083 | ||
| 1000 | sdata->vif.bss_conf.chandef = sdata->reserved_chandef; | 1084 | sdata->vif.bss_conf.chandef = sdata->reserved_chandef; |
| 1001 | 1085 | ||
| 1002 | /* unref our reservation */ | 1086 | if (changed) |
| 1003 | sdata->reserved_chanctx = NULL; | 1087 | ieee80211_bss_info_change_notify(sdata, changed); |
| 1004 | sdata->radar_required = sdata->reserved_radar_required; | 1088 | |
| 1089 | out: | ||
| 1090 | ieee80211_vif_chanctx_reservation_complete(sdata); | ||
| 1091 | return err; | ||
| 1092 | } | ||
| 1093 | |||
| 1094 | static int | ||
| 1095 | ieee80211_vif_use_reserved_assign(struct ieee80211_sub_if_data *sdata) | ||
| 1096 | { | ||
| 1097 | struct ieee80211_local *local = sdata->local; | ||
| 1098 | struct ieee80211_chanctx *old_ctx, *new_ctx; | ||
| 1099 | const struct cfg80211_chan_def *chandef; | ||
| 1100 | int err; | ||
| 1101 | |||
| 1102 | old_ctx = ieee80211_vif_get_chanctx(sdata); | ||
| 1103 | new_ctx = sdata->reserved_chanctx; | ||
| 1104 | |||
| 1105 | if (WARN_ON(!sdata->reserved_ready)) | ||
| 1106 | return -EINVAL; | ||
| 1107 | |||
| 1108 | if (WARN_ON(old_ctx)) | ||
| 1109 | return -EINVAL; | ||
| 1110 | |||
| 1111 | if (WARN_ON(!new_ctx)) | ||
| 1112 | return -EINVAL; | ||
| 1113 | |||
| 1114 | if (WARN_ON(new_ctx->replace_state == | ||
| 1115 | IEEE80211_CHANCTX_REPLACES_OTHER)) | ||
| 1116 | return -EINVAL; | ||
| 1117 | |||
| 1118 | chandef = ieee80211_chanctx_non_reserved_chandef(local, new_ctx, | ||
| 1119 | &sdata->reserved_chandef); | ||
| 1120 | if (WARN_ON(!chandef)) | ||
| 1121 | return -EINVAL; | ||
| 1122 | |||
| 1005 | list_del(&sdata->reserved_chanctx_list); | 1123 | list_del(&sdata->reserved_chanctx_list); |
| 1124 | sdata->reserved_chanctx = NULL; | ||
| 1006 | 1125 | ||
| 1007 | if (old_ctx == ctx) { | 1126 | err = ieee80211_assign_vif_chanctx(sdata, new_ctx); |
| 1008 | /* This is our own context, just change it */ | 1127 | if (err) { |
| 1009 | ret = __ieee80211_vif_change_channel(sdata, old_ctx, | 1128 | if (ieee80211_chanctx_refcount(local, new_ctx) == 0) |
| 1010 | &tmp_changed); | 1129 | ieee80211_free_chanctx(local, new_ctx); |
| 1011 | if (ret) | 1130 | |
| 1012 | goto out; | 1131 | goto out; |
| 1013 | } else { | 1132 | } |
| 1014 | ret = ieee80211_assign_vif_chanctx(sdata, ctx); | 1133 | |
| 1015 | if (ieee80211_chanctx_refcount(local, old_ctx) == 0) | 1134 | out: |
| 1016 | ieee80211_free_chanctx(local, old_ctx); | 1135 | ieee80211_vif_chanctx_reservation_complete(sdata); |
| 1017 | if (ret) { | 1136 | return err; |
| 1018 | /* if assign fails refcount stays the same */ | 1137 | } |
| 1019 | if (ieee80211_chanctx_refcount(local, ctx) == 0) | 1138 | |
| 1020 | ieee80211_free_chanctx(local, ctx); | 1139 | static bool |
| 1140 | ieee80211_vif_has_in_place_reservation(struct ieee80211_sub_if_data *sdata) | ||
| 1141 | { | ||
| 1142 | struct ieee80211_chanctx *old_ctx, *new_ctx; | ||
| 1143 | |||
| 1144 | lockdep_assert_held(&sdata->local->chanctx_mtx); | ||
| 1145 | |||
| 1146 | new_ctx = sdata->reserved_chanctx; | ||
| 1147 | old_ctx = ieee80211_vif_get_chanctx(sdata); | ||
| 1148 | |||
| 1149 | if (!old_ctx) | ||
| 1150 | return false; | ||
| 1151 | |||
| 1152 | if (WARN_ON(!new_ctx)) | ||
| 1153 | return false; | ||
| 1154 | |||
| 1155 | if (old_ctx->replace_state != IEEE80211_CHANCTX_WILL_BE_REPLACED) | ||
| 1156 | return false; | ||
| 1157 | |||
| 1158 | if (new_ctx->replace_state != IEEE80211_CHANCTX_REPLACES_OTHER) | ||
| 1159 | return false; | ||
| 1160 | |||
| 1161 | return true; | ||
| 1162 | } | ||
| 1163 | |||
| 1164 | static int ieee80211_chsw_switch_hwconf(struct ieee80211_local *local, | ||
| 1165 | struct ieee80211_chanctx *new_ctx) | ||
| 1166 | { | ||
| 1167 | const struct cfg80211_chan_def *chandef; | ||
| 1168 | |||
| 1169 | lockdep_assert_held(&local->mtx); | ||
| 1170 | lockdep_assert_held(&local->chanctx_mtx); | ||
| 1171 | |||
| 1172 | chandef = ieee80211_chanctx_reserved_chandef(local, new_ctx, NULL); | ||
| 1173 | if (WARN_ON(!chandef)) | ||
| 1174 | return -EINVAL; | ||
| 1175 | |||
| 1176 | local->hw.conf.radar_enabled = new_ctx->conf.radar_enabled; | ||
| 1177 | local->_oper_chandef = *chandef; | ||
| 1178 | ieee80211_hw_config(local, 0); | ||
| 1179 | |||
| 1180 | return 0; | ||
| 1181 | } | ||
| 1182 | |||
| 1183 | static int ieee80211_chsw_switch_vifs(struct ieee80211_local *local, | ||
| 1184 | int n_vifs) | ||
| 1185 | { | ||
| 1186 | struct ieee80211_vif_chanctx_switch *vif_chsw; | ||
| 1187 | struct ieee80211_sub_if_data *sdata; | ||
| 1188 | struct ieee80211_chanctx *ctx, *old_ctx; | ||
| 1189 | int i, err; | ||
| 1190 | |||
| 1191 | lockdep_assert_held(&local->mtx); | ||
| 1192 | lockdep_assert_held(&local->chanctx_mtx); | ||
| 1193 | |||
| 1194 | vif_chsw = kzalloc(sizeof(vif_chsw[0]) * n_vifs, GFP_KERNEL); | ||
| 1195 | if (!vif_chsw) | ||
| 1196 | return -ENOMEM; | ||
| 1197 | |||
| 1198 | i = 0; | ||
| 1199 | list_for_each_entry(ctx, &local->chanctx_list, list) { | ||
| 1200 | if (ctx->replace_state != IEEE80211_CHANCTX_REPLACES_OTHER) | ||
| 1201 | continue; | ||
| 1202 | |||
| 1203 | if (WARN_ON(!ctx->replace_ctx)) { | ||
| 1204 | err = -EINVAL; | ||
| 1021 | goto out; | 1205 | goto out; |
| 1022 | } | 1206 | } |
| 1023 | 1207 | ||
| 1024 | if (sdata->vif.type == NL80211_IFTYPE_AP) | 1208 | list_for_each_entry(sdata, &ctx->reserved_vifs, |
| 1025 | __ieee80211_vif_copy_chanctx_to_vlans(sdata, false); | 1209 | reserved_chanctx_list) { |
| 1210 | if (!ieee80211_vif_has_in_place_reservation( | ||
| 1211 | sdata)) | ||
| 1212 | continue; | ||
| 1213 | |||
| 1214 | old_ctx = ieee80211_vif_get_chanctx(sdata); | ||
| 1215 | vif_chsw[i].vif = &sdata->vif; | ||
| 1216 | vif_chsw[i].old_ctx = &old_ctx->conf; | ||
| 1217 | vif_chsw[i].new_ctx = &ctx->conf; | ||
| 1218 | |||
| 1219 | i++; | ||
| 1220 | } | ||
| 1026 | } | 1221 | } |
| 1027 | 1222 | ||
| 1028 | *changed = tmp_changed; | 1223 | err = drv_switch_vif_chanctx(local, vif_chsw, n_vifs, |
| 1224 | CHANCTX_SWMODE_SWAP_CONTEXTS); | ||
| 1029 | 1225 | ||
| 1030 | ieee80211_recalc_chanctx_chantype(local, ctx); | ||
| 1031 | ieee80211_recalc_smps_chanctx(local, ctx); | ||
| 1032 | ieee80211_recalc_radar_chanctx(local, ctx); | ||
| 1033 | ieee80211_recalc_chanctx_min_def(local, ctx); | ||
| 1034 | out: | 1226 | out: |
| 1035 | mutex_unlock(&local->chanctx_mtx); | 1227 | kfree(vif_chsw); |
| 1036 | return ret; | 1228 | return err; |
| 1229 | } | ||
| 1230 | |||
| 1231 | static int ieee80211_chsw_switch_ctxs(struct ieee80211_local *local) | ||
| 1232 | { | ||
| 1233 | struct ieee80211_chanctx *ctx; | ||
| 1234 | int err; | ||
| 1235 | |||
| 1236 | lockdep_assert_held(&local->mtx); | ||
| 1237 | lockdep_assert_held(&local->chanctx_mtx); | ||
| 1238 | |||
| 1239 | list_for_each_entry(ctx, &local->chanctx_list, list) { | ||
| 1240 | if (ctx->replace_state != IEEE80211_CHANCTX_REPLACES_OTHER) | ||
| 1241 | continue; | ||
| 1242 | |||
| 1243 | if (!list_empty(&ctx->replace_ctx->assigned_vifs)) | ||
| 1244 | continue; | ||
| 1245 | |||
| 1246 | ieee80211_del_chanctx(local, ctx->replace_ctx); | ||
| 1247 | err = ieee80211_add_chanctx(local, ctx); | ||
| 1248 | if (err) | ||
| 1249 | goto err; | ||
| 1250 | } | ||
| 1251 | |||
| 1252 | return 0; | ||
| 1253 | |||
| 1254 | err: | ||
| 1255 | WARN_ON(ieee80211_add_chanctx(local, ctx)); | ||
| 1256 | list_for_each_entry_continue_reverse(ctx, &local->chanctx_list, list) { | ||
| 1257 | if (ctx->replace_state != IEEE80211_CHANCTX_REPLACES_OTHER) | ||
| 1258 | continue; | ||
| 1259 | |||
| 1260 | if (!list_empty(&ctx->replace_ctx->assigned_vifs)) | ||
| 1261 | continue; | ||
| 1262 | |||
| 1263 | ieee80211_del_chanctx(local, ctx); | ||
| 1264 | WARN_ON(ieee80211_add_chanctx(local, ctx->replace_ctx)); | ||
| 1265 | } | ||
| 1266 | |||
| 1267 | return err; | ||
| 1268 | } | ||
| 1269 | |||
| 1270 | int | ||
| 1271 | ieee80211_vif_use_reserved_switch(struct ieee80211_local *local) | ||
| 1272 | { | ||
| 1273 | struct ieee80211_sub_if_data *sdata, *sdata_tmp; | ||
| 1274 | struct ieee80211_chanctx *ctx, *ctx_tmp, *old_ctx; | ||
| 1275 | struct ieee80211_chanctx *new_ctx = NULL; | ||
| 1276 | int i, err, n_assigned, n_reserved, n_ready; | ||
| 1277 | int n_ctx = 0, n_vifs_switch = 0, n_vifs_assign = 0, n_vifs_ctxless = 0; | ||
| 1278 | |||
| 1279 | lockdep_assert_held(&local->mtx); | ||
| 1280 | lockdep_assert_held(&local->chanctx_mtx); | ||
| 1281 | |||
| 1282 | /* | ||
| 1283 | * If there are 2 independent pairs of channel contexts performing | ||
| 1284 | * cross-switch of their vifs this code will still wait until both are | ||
| 1285 | * ready even though it could be possible to switch one before the | ||
| 1286 | * other is ready. | ||
| 1287 | * | ||
| 1288 | * For practical reasons and code simplicity just do a single huge | ||
| 1289 | * switch. | ||
| 1290 | */ | ||
| 1291 | |||
| 1292 | /* | ||
| 1293 | * Verify if the reservation is still feasible. | ||
| 1294 | * - if it's not then disconnect | ||
| 1295 | * - if it is but not all vifs necessary are ready then defer | ||
| 1296 | */ | ||
| 1297 | |||
| 1298 | list_for_each_entry(ctx, &local->chanctx_list, list) { | ||
| 1299 | if (ctx->replace_state != IEEE80211_CHANCTX_REPLACES_OTHER) | ||
| 1300 | continue; | ||
| 1301 | |||
| 1302 | if (WARN_ON(!ctx->replace_ctx)) { | ||
| 1303 | err = -EINVAL; | ||
| 1304 | goto err; | ||
| 1305 | } | ||
| 1306 | |||
| 1307 | if (!local->use_chanctx) | ||
| 1308 | new_ctx = ctx; | ||
| 1309 | |||
| 1310 | n_ctx++; | ||
| 1311 | |||
| 1312 | n_assigned = 0; | ||
| 1313 | n_reserved = 0; | ||
| 1314 | n_ready = 0; | ||
| 1315 | |||
| 1316 | list_for_each_entry(sdata, &ctx->replace_ctx->assigned_vifs, | ||
| 1317 | assigned_chanctx_list) { | ||
| 1318 | n_assigned++; | ||
| 1319 | if (sdata->reserved_chanctx) { | ||
| 1320 | n_reserved++; | ||
| 1321 | if (sdata->reserved_ready) | ||
| 1322 | n_ready++; | ||
| 1323 | } | ||
| 1324 | } | ||
| 1325 | |||
| 1326 | if (n_assigned != n_reserved) { | ||
| 1327 | if (n_ready == n_reserved) { | ||
| 1328 | wiphy_info(local->hw.wiphy, | ||
| 1329 | "channel context reservation cannot be finalized because some interfaces aren't switching\n"); | ||
| 1330 | err = -EBUSY; | ||
| 1331 | goto err; | ||
| 1332 | } | ||
| 1333 | |||
| 1334 | return -EAGAIN; | ||
| 1335 | } | ||
| 1336 | |||
| 1337 | ctx->conf.radar_enabled = false; | ||
| 1338 | list_for_each_entry(sdata, &ctx->reserved_vifs, | ||
| 1339 | reserved_chanctx_list) { | ||
| 1340 | if (ieee80211_vif_has_in_place_reservation(sdata) && | ||
| 1341 | !sdata->reserved_ready) | ||
| 1342 | return -EAGAIN; | ||
| 1343 | |||
| 1344 | old_ctx = ieee80211_vif_get_chanctx(sdata); | ||
| 1345 | if (old_ctx) { | ||
| 1346 | if (old_ctx->replace_state == | ||
| 1347 | IEEE80211_CHANCTX_WILL_BE_REPLACED) | ||
| 1348 | n_vifs_switch++; | ||
| 1349 | else | ||
| 1350 | n_vifs_assign++; | ||
| 1351 | } else { | ||
| 1352 | n_vifs_ctxless++; | ||
| 1353 | } | ||
| 1354 | |||
| 1355 | if (sdata->reserved_radar_required) | ||
| 1356 | ctx->conf.radar_enabled = true; | ||
| 1357 | } | ||
| 1358 | } | ||
| 1359 | |||
| 1360 | if (WARN_ON(n_ctx == 0) || | ||
| 1361 | WARN_ON(n_vifs_switch == 0 && | ||
| 1362 | n_vifs_assign == 0 && | ||
| 1363 | n_vifs_ctxless == 0) || | ||
| 1364 | WARN_ON(n_ctx > 1 && !local->use_chanctx) || | ||
| 1365 | WARN_ON(!new_ctx && !local->use_chanctx)) { | ||
| 1366 | err = -EINVAL; | ||
| 1367 | goto err; | ||
| 1368 | } | ||
| 1369 | |||
| 1370 | /* | ||
| 1371 | * All necessary vifs are ready. Perform the switch now depending on | ||
| 1372 | * reservations and driver capabilities. | ||
| 1373 | */ | ||
| 1374 | |||
| 1375 | if (local->use_chanctx) { | ||
| 1376 | if (n_vifs_switch > 0) { | ||
| 1377 | err = ieee80211_chsw_switch_vifs(local, n_vifs_switch); | ||
| 1378 | if (err) | ||
| 1379 | goto err; | ||
| 1380 | } | ||
| 1381 | |||
| 1382 | if (n_vifs_assign > 0 || n_vifs_ctxless > 0) { | ||
| 1383 | err = ieee80211_chsw_switch_ctxs(local); | ||
| 1384 | if (err) | ||
| 1385 | goto err; | ||
| 1386 | } | ||
| 1387 | } else { | ||
| 1388 | err = ieee80211_chsw_switch_hwconf(local, new_ctx); | ||
| 1389 | if (err) | ||
| 1390 | goto err; | ||
| 1391 | } | ||
| 1392 | |||
| 1393 | /* | ||
| 1394 | * Update all structures, values and pointers to point to new channel | ||
| 1395 | * context(s). | ||
| 1396 | */ | ||
| 1397 | |||
| 1398 | i = 0; | ||
| 1399 | list_for_each_entry(ctx, &local->chanctx_list, list) { | ||
| 1400 | if (ctx->replace_state != IEEE80211_CHANCTX_REPLACES_OTHER) | ||
| 1401 | continue; | ||
| 1402 | |||
| 1403 | if (WARN_ON(!ctx->replace_ctx)) { | ||
| 1404 | err = -EINVAL; | ||
| 1405 | goto err; | ||
| 1406 | } | ||
| 1407 | |||
| 1408 | list_for_each_entry(sdata, &ctx->reserved_vifs, | ||
| 1409 | reserved_chanctx_list) { | ||
| 1410 | u32 changed = 0; | ||
| 1411 | |||
| 1412 | if (!ieee80211_vif_has_in_place_reservation(sdata)) | ||
| 1413 | continue; | ||
| 1414 | |||
| 1415 | rcu_assign_pointer(sdata->vif.chanctx_conf, &ctx->conf); | ||
| 1416 | |||
| 1417 | if (sdata->vif.type == NL80211_IFTYPE_AP) | ||
| 1418 | __ieee80211_vif_copy_chanctx_to_vlans(sdata, | ||
| 1419 | false); | ||
| 1420 | |||
| 1421 | sdata->radar_required = sdata->reserved_radar_required; | ||
| 1422 | |||
| 1423 | if (sdata->vif.bss_conf.chandef.width != | ||
| 1424 | sdata->reserved_chandef.width) | ||
| 1425 | changed = BSS_CHANGED_BANDWIDTH; | ||
| 1426 | |||
| 1427 | sdata->vif.bss_conf.chandef = sdata->reserved_chandef; | ||
| 1428 | if (changed) | ||
| 1429 | ieee80211_bss_info_change_notify(sdata, | ||
| 1430 | changed); | ||
| 1431 | |||
| 1432 | ieee80211_recalc_txpower(sdata); | ||
| 1433 | } | ||
| 1434 | |||
| 1435 | ieee80211_recalc_chanctx_chantype(local, ctx); | ||
| 1436 | ieee80211_recalc_smps_chanctx(local, ctx); | ||
| 1437 | ieee80211_recalc_radar_chanctx(local, ctx); | ||
| 1438 | ieee80211_recalc_chanctx_min_def(local, ctx); | ||
| 1439 | |||
| 1440 | list_for_each_entry_safe(sdata, sdata_tmp, &ctx->reserved_vifs, | ||
| 1441 | reserved_chanctx_list) { | ||
| 1442 | if (ieee80211_vif_get_chanctx(sdata) != ctx) | ||
| 1443 | continue; | ||
| 1444 | |||
| 1445 | list_del(&sdata->reserved_chanctx_list); | ||
| 1446 | list_move(&sdata->assigned_chanctx_list, | ||
| 1447 | &new_ctx->assigned_vifs); | ||
| 1448 | sdata->reserved_chanctx = NULL; | ||
| 1449 | |||
| 1450 | ieee80211_vif_chanctx_reservation_complete(sdata); | ||
| 1451 | } | ||
| 1452 | |||
| 1453 | /* | ||
| 1454 | * This context might have been a dependency for an already | ||
| 1455 | * ready re-assign reservation interface that was deferred. Do | ||
| 1456 | * not propagate error to the caller though. The in-place | ||
| 1457 | * reservation for originally requested interface has already | ||
| 1458 | * succeeded at this point. | ||
| 1459 | */ | ||
| 1460 | list_for_each_entry_safe(sdata, sdata_tmp, &ctx->reserved_vifs, | ||
| 1461 | reserved_chanctx_list) { | ||
| 1462 | if (WARN_ON(ieee80211_vif_has_in_place_reservation( | ||
| 1463 | sdata))) | ||
| 1464 | continue; | ||
| 1465 | |||
| 1466 | if (WARN_ON(sdata->reserved_chanctx != ctx)) | ||
| 1467 | continue; | ||
| 1468 | |||
| 1469 | if (!sdata->reserved_ready) | ||
| 1470 | continue; | ||
| 1471 | |||
| 1472 | if (ieee80211_vif_get_chanctx(sdata)) | ||
| 1473 | err = ieee80211_vif_use_reserved_reassign( | ||
| 1474 | sdata); | ||
| 1475 | else | ||
| 1476 | err = ieee80211_vif_use_reserved_assign(sdata); | ||
| 1477 | |||
| 1478 | if (err) { | ||
| 1479 | sdata_info(sdata, | ||
| 1480 | "failed to finalize (re-)assign reservation (err=%d)\n", | ||
| 1481 | err); | ||
| 1482 | ieee80211_vif_unreserve_chanctx(sdata); | ||
| 1483 | cfg80211_stop_iface(local->hw.wiphy, | ||
| 1484 | &sdata->wdev, | ||
| 1485 | GFP_KERNEL); | ||
| 1486 | } | ||
| 1487 | } | ||
| 1488 | } | ||
| 1489 | |||
| 1490 | /* | ||
| 1491 | * Finally free old contexts | ||
| 1492 | */ | ||
| 1493 | |||
| 1494 | list_for_each_entry_safe(ctx, ctx_tmp, &local->chanctx_list, list) { | ||
| 1495 | if (ctx->replace_state != IEEE80211_CHANCTX_WILL_BE_REPLACED) | ||
| 1496 | continue; | ||
| 1497 | |||
| 1498 | ctx->replace_ctx->replace_ctx = NULL; | ||
| 1499 | ctx->replace_ctx->replace_state = | ||
| 1500 | IEEE80211_CHANCTX_REPLACE_NONE; | ||
| 1501 | |||
| 1502 | list_del_rcu(&ctx->list); | ||
| 1503 | kfree_rcu(ctx, rcu_head); | ||
| 1504 | } | ||
| 1505 | |||
| 1506 | return 0; | ||
| 1507 | |||
| 1508 | err: | ||
| 1509 | list_for_each_entry(ctx, &local->chanctx_list, list) { | ||
| 1510 | if (ctx->replace_state != IEEE80211_CHANCTX_REPLACES_OTHER) | ||
| 1511 | continue; | ||
| 1512 | |||
| 1513 | list_for_each_entry_safe(sdata, sdata_tmp, &ctx->reserved_vifs, | ||
| 1514 | reserved_chanctx_list) { | ||
| 1515 | ieee80211_vif_unreserve_chanctx(sdata); | ||
| 1516 | ieee80211_vif_chanctx_reservation_complete(sdata); | ||
| 1517 | } | ||
| 1518 | } | ||
| 1519 | |||
| 1520 | return err; | ||
| 1521 | } | ||
| 1522 | |||
| 1523 | int ieee80211_vif_use_reserved_context(struct ieee80211_sub_if_data *sdata) | ||
| 1524 | { | ||
| 1525 | struct ieee80211_local *local = sdata->local; | ||
| 1526 | struct ieee80211_chanctx *new_ctx; | ||
| 1527 | struct ieee80211_chanctx *old_ctx; | ||
| 1528 | int err; | ||
| 1529 | |||
| 1530 | lockdep_assert_held(&local->mtx); | ||
| 1531 | lockdep_assert_held(&local->chanctx_mtx); | ||
| 1532 | |||
| 1533 | new_ctx = sdata->reserved_chanctx; | ||
| 1534 | old_ctx = ieee80211_vif_get_chanctx(sdata); | ||
| 1535 | |||
| 1536 | if (WARN_ON(!new_ctx)) | ||
| 1537 | return -EINVAL; | ||
| 1538 | |||
| 1539 | if (WARN_ON(new_ctx->replace_state == | ||
| 1540 | IEEE80211_CHANCTX_WILL_BE_REPLACED)) | ||
| 1541 | return -EINVAL; | ||
| 1542 | |||
| 1543 | if (WARN_ON(sdata->reserved_ready)) | ||
| 1544 | return -EINVAL; | ||
| 1545 | |||
| 1546 | sdata->reserved_ready = true; | ||
| 1547 | |||
| 1548 | if (new_ctx->replace_state == IEEE80211_CHANCTX_REPLACE_NONE) { | ||
| 1549 | if (old_ctx) | ||
| 1550 | err = ieee80211_vif_use_reserved_reassign(sdata); | ||
| 1551 | else | ||
| 1552 | err = ieee80211_vif_use_reserved_assign(sdata); | ||
| 1553 | |||
| 1554 | if (err) | ||
| 1555 | return err; | ||
| 1556 | } | ||
| 1557 | |||
| 1558 | /* | ||
| 1559 | * In-place reservation may need to be finalized now either if: | ||
| 1560 | * a) sdata is taking part in the swapping itself and is the last one | ||
| 1561 | * b) sdata has switched with a re-assign reservation to an existing | ||
| 1562 | * context readying in-place switching of old_ctx | ||
| 1563 | * | ||
| 1564 | * In case of (b) do not propagate the error up because the requested | ||
| 1565 | * sdata already switched successfully. Just spill an extra warning. | ||
| 1566 | * The ieee80211_vif_use_reserved_switch() already stops all necessary | ||
| 1567 | * interfaces upon failure. | ||
| 1568 | */ | ||
| 1569 | if ((old_ctx && | ||
| 1570 | old_ctx->replace_state == IEEE80211_CHANCTX_WILL_BE_REPLACED) || | ||
| 1571 | new_ctx->replace_state == IEEE80211_CHANCTX_REPLACES_OTHER) { | ||
| 1572 | err = ieee80211_vif_use_reserved_switch(local); | ||
| 1573 | if (err && err != -EAGAIN) { | ||
| 1574 | if (new_ctx->replace_state == | ||
| 1575 | IEEE80211_CHANCTX_REPLACES_OTHER) | ||
| 1576 | return err; | ||
| 1577 | |||
| 1578 | wiphy_info(local->hw.wiphy, | ||
| 1579 | "depending in-place reservation failed (err=%d)\n", | ||
| 1580 | err); | ||
| 1581 | } | ||
| 1582 | } | ||
| 1583 | |||
| 1584 | return 0; | ||
| 1037 | } | 1585 | } |
| 1038 | 1586 | ||
| 1039 | int ieee80211_vif_change_bandwidth(struct ieee80211_sub_if_data *sdata, | 1587 | int ieee80211_vif_change_bandwidth(struct ieee80211_sub_if_data *sdata, |
| @@ -1043,6 +1591,7 @@ int ieee80211_vif_change_bandwidth(struct ieee80211_sub_if_data *sdata, | |||
| 1043 | struct ieee80211_local *local = sdata->local; | 1591 | struct ieee80211_local *local = sdata->local; |
| 1044 | struct ieee80211_chanctx_conf *conf; | 1592 | struct ieee80211_chanctx_conf *conf; |
| 1045 | struct ieee80211_chanctx *ctx; | 1593 | struct ieee80211_chanctx *ctx; |
| 1594 | const struct cfg80211_chan_def *compat; | ||
| 1046 | int ret; | 1595 | int ret; |
| 1047 | 1596 | ||
| 1048 | if (!cfg80211_chandef_usable(sdata->local->hw.wiphy, chandef, | 1597 | if (!cfg80211_chandef_usable(sdata->local->hw.wiphy, chandef, |
| @@ -1069,11 +1618,33 @@ int ieee80211_vif_change_bandwidth(struct ieee80211_sub_if_data *sdata, | |||
| 1069 | } | 1618 | } |
| 1070 | 1619 | ||
| 1071 | ctx = container_of(conf, struct ieee80211_chanctx, conf); | 1620 | ctx = container_of(conf, struct ieee80211_chanctx, conf); |
| 1072 | if (!cfg80211_chandef_compatible(&conf->def, chandef)) { | 1621 | |
| 1622 | compat = cfg80211_chandef_compatible(&conf->def, chandef); | ||
| 1623 | if (!compat) { | ||
| 1073 | ret = -EINVAL; | 1624 | ret = -EINVAL; |
| 1074 | goto out; | 1625 | goto out; |
| 1075 | } | 1626 | } |
| 1076 | 1627 | ||
| 1628 | switch (ctx->replace_state) { | ||
| 1629 | case IEEE80211_CHANCTX_REPLACE_NONE: | ||
| 1630 | if (!ieee80211_chanctx_reserved_chandef(local, ctx, compat)) { | ||
| 1631 | ret = -EBUSY; | ||
| 1632 | goto out; | ||
| 1633 | } | ||
| 1634 | break; | ||
| 1635 | case IEEE80211_CHANCTX_WILL_BE_REPLACED: | ||
| 1636 | /* TODO: Perhaps the bandwith change could be treated as a | ||
| 1637 | * reservation itself? */ | ||
| 1638 | ret = -EBUSY; | ||
| 1639 | goto out; | ||
| 1640 | case IEEE80211_CHANCTX_REPLACES_OTHER: | ||
| 1641 | /* channel context that is going to replace another channel | ||
| 1642 | * context doesn't really exist and shouldn't be assigned | ||
| 1643 | * anywhere yet */ | ||
| 1644 | WARN_ON(1); | ||
| 1645 | break; | ||
| 1646 | } | ||
| 1647 | |||
| 1077 | sdata->vif.bss_conf.chandef = *chandef; | 1648 | sdata->vif.bss_conf.chandef = *chandef; |
| 1078 | 1649 | ||
| 1079 | ieee80211_recalc_chanctx_chantype(local, ctx); | 1650 | ieee80211_recalc_chanctx_chantype(local, ctx); |
diff --git a/net/mac80211/debugfs_sta.c b/net/mac80211/debugfs_sta.c index 2ecb4deddb5d..3db96648b45a 100644 --- a/net/mac80211/debugfs_sta.c +++ b/net/mac80211/debugfs_sta.c | |||
| @@ -124,7 +124,7 @@ static ssize_t sta_connected_time_read(struct file *file, char __user *userbuf, | |||
| 124 | long connected_time_secs; | 124 | long connected_time_secs; |
| 125 | char buf[100]; | 125 | char buf[100]; |
| 126 | int res; | 126 | int res; |
| 127 | do_posix_clock_monotonic_gettime(&uptime); | 127 | ktime_get_ts(&uptime); |
| 128 | connected_time_secs = uptime.tv_sec - sta->last_connected; | 128 | connected_time_secs = uptime.tv_sec - sta->last_connected; |
| 129 | time_to_tm(connected_time_secs, 0, &result); | 129 | time_to_tm(connected_time_secs, 0, &result); |
| 130 | result.tm_year -= 70; | 130 | result.tm_year -= 70; |
| @@ -587,7 +587,6 @@ void ieee80211_sta_debugfs_add(struct sta_info *sta) | |||
| 587 | DEBUGFS_ADD_COUNTER(tx_filtered, tx_filtered_count); | 587 | DEBUGFS_ADD_COUNTER(tx_filtered, tx_filtered_count); |
| 588 | DEBUGFS_ADD_COUNTER(tx_retry_failed, tx_retry_failed); | 588 | DEBUGFS_ADD_COUNTER(tx_retry_failed, tx_retry_failed); |
| 589 | DEBUGFS_ADD_COUNTER(tx_retry_count, tx_retry_count); | 589 | DEBUGFS_ADD_COUNTER(tx_retry_count, tx_retry_count); |
| 590 | DEBUGFS_ADD_COUNTER(wep_weak_iv_count, wep_weak_iv_count); | ||
| 591 | 590 | ||
| 592 | if (sizeof(sta->driver_buffered_tids) == sizeof(u32)) | 591 | if (sizeof(sta->driver_buffered_tids) == sizeof(u32)) |
| 593 | debugfs_create_x32("driver_buffered_tids", 0400, | 592 | debugfs_create_x32("driver_buffered_tids", 0400, |
diff --git a/net/mac80211/driver-ops.h b/net/mac80211/driver-ops.h index bd782dcffcc7..11423958116a 100644 --- a/net/mac80211/driver-ops.h +++ b/net/mac80211/driver-ops.h | |||
| @@ -314,7 +314,7 @@ static inline void drv_update_tkip_key(struct ieee80211_local *local, | |||
| 314 | 314 | ||
| 315 | static inline int drv_hw_scan(struct ieee80211_local *local, | 315 | static inline int drv_hw_scan(struct ieee80211_local *local, |
| 316 | struct ieee80211_sub_if_data *sdata, | 316 | struct ieee80211_sub_if_data *sdata, |
| 317 | struct cfg80211_scan_request *req) | 317 | struct ieee80211_scan_request *req) |
| 318 | { | 318 | { |
| 319 | int ret; | 319 | int ret; |
| 320 | 320 | ||
| @@ -346,7 +346,7 @@ static inline int | |||
| 346 | drv_sched_scan_start(struct ieee80211_local *local, | 346 | drv_sched_scan_start(struct ieee80211_local *local, |
| 347 | struct ieee80211_sub_if_data *sdata, | 347 | struct ieee80211_sub_if_data *sdata, |
| 348 | struct cfg80211_sched_scan_request *req, | 348 | struct cfg80211_sched_scan_request *req, |
| 349 | struct ieee80211_sched_scan_ies *ies) | 349 | struct ieee80211_scan_ies *ies) |
| 350 | { | 350 | { |
| 351 | int ret; | 351 | int ret; |
| 352 | 352 | ||
| @@ -970,6 +970,22 @@ static inline void drv_mgd_prepare_tx(struct ieee80211_local *local, | |||
| 970 | trace_drv_return_void(local); | 970 | trace_drv_return_void(local); |
| 971 | } | 971 | } |
| 972 | 972 | ||
| 973 | static inline void | ||
| 974 | drv_mgd_protect_tdls_discover(struct ieee80211_local *local, | ||
| 975 | struct ieee80211_sub_if_data *sdata) | ||
| 976 | { | ||
| 977 | might_sleep(); | ||
| 978 | |||
| 979 | if (!check_sdata_in_driver(sdata)) | ||
| 980 | return; | ||
| 981 | WARN_ON_ONCE(sdata->vif.type != NL80211_IFTYPE_STATION); | ||
| 982 | |||
| 983 | trace_drv_mgd_protect_tdls_discover(local, sdata); | ||
| 984 | if (local->ops->mgd_protect_tdls_discover) | ||
| 985 | local->ops->mgd_protect_tdls_discover(&local->hw, &sdata->vif); | ||
| 986 | trace_drv_return_void(local); | ||
| 987 | } | ||
| 988 | |||
| 973 | static inline int drv_add_chanctx(struct ieee80211_local *local, | 989 | static inline int drv_add_chanctx(struct ieee80211_local *local, |
| 974 | struct ieee80211_chanctx *ctx) | 990 | struct ieee80211_chanctx *ctx) |
| 975 | { | 991 | { |
diff --git a/net/mac80211/ethtool.c b/net/mac80211/ethtool.c new file mode 100644 index 000000000000..ebfc8091557b --- /dev/null +++ b/net/mac80211/ethtool.c | |||
| @@ -0,0 +1,244 @@ | |||
| 1 | /* | ||
| 2 | * mac80211 ethtool hooks for cfg80211 | ||
| 3 | * | ||
| 4 | * Copied from cfg.c - originally | ||
| 5 | * Copyright 2006-2010 Johannes Berg <johannes@sipsolutions.net> | ||
| 6 | * Copyright 2014 Intel Corporation (Author: Johannes Berg) | ||
| 7 | * | ||
| 8 | * This file is GPLv2 as found in COPYING. | ||
| 9 | */ | ||
| 10 | #include <linux/types.h> | ||
| 11 | #include <net/cfg80211.h> | ||
| 12 | #include "ieee80211_i.h" | ||
| 13 | #include "sta_info.h" | ||
| 14 | #include "driver-ops.h" | ||
| 15 | |||
| 16 | static int ieee80211_set_ringparam(struct net_device *dev, | ||
| 17 | struct ethtool_ringparam *rp) | ||
| 18 | { | ||
| 19 | struct ieee80211_local *local = wiphy_priv(dev->ieee80211_ptr->wiphy); | ||
| 20 | |||
| 21 | if (rp->rx_mini_pending != 0 || rp->rx_jumbo_pending != 0) | ||
| 22 | return -EINVAL; | ||
| 23 | |||
| 24 | return drv_set_ringparam(local, rp->tx_pending, rp->rx_pending); | ||
| 25 | } | ||
| 26 | |||
| 27 | static void ieee80211_get_ringparam(struct net_device *dev, | ||
| 28 | struct ethtool_ringparam *rp) | ||
| 29 | { | ||
| 30 | struct ieee80211_local *local = wiphy_priv(dev->ieee80211_ptr->wiphy); | ||
| 31 | |||
| 32 | memset(rp, 0, sizeof(*rp)); | ||
| 33 | |||
| 34 | drv_get_ringparam(local, &rp->tx_pending, &rp->tx_max_pending, | ||
| 35 | &rp->rx_pending, &rp->rx_max_pending); | ||
| 36 | } | ||
| 37 | |||
| 38 | static const char ieee80211_gstrings_sta_stats[][ETH_GSTRING_LEN] = { | ||
| 39 | "rx_packets", "rx_bytes", | ||
| 40 | "rx_duplicates", "rx_fragments", "rx_dropped", | ||
| 41 | "tx_packets", "tx_bytes", "tx_fragments", | ||
| 42 | "tx_filtered", "tx_retry_failed", "tx_retries", | ||
| 43 | "beacon_loss", "sta_state", "txrate", "rxrate", "signal", | ||
| 44 | "channel", "noise", "ch_time", "ch_time_busy", | ||
| 45 | "ch_time_ext_busy", "ch_time_rx", "ch_time_tx" | ||
| 46 | }; | ||
| 47 | #define STA_STATS_LEN ARRAY_SIZE(ieee80211_gstrings_sta_stats) | ||
| 48 | |||
| 49 | static int ieee80211_get_sset_count(struct net_device *dev, int sset) | ||
| 50 | { | ||
| 51 | struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); | ||
| 52 | int rv = 0; | ||
| 53 | |||
| 54 | if (sset == ETH_SS_STATS) | ||
| 55 | rv += STA_STATS_LEN; | ||
| 56 | |||
| 57 | rv += drv_get_et_sset_count(sdata, sset); | ||
| 58 | |||
| 59 | if (rv == 0) | ||
| 60 | return -EOPNOTSUPP; | ||
| 61 | return rv; | ||
| 62 | } | ||
| 63 | |||
| 64 | static void ieee80211_get_stats(struct net_device *dev, | ||
| 65 | struct ethtool_stats *stats, | ||
| 66 | u64 *data) | ||
| 67 | { | ||
| 68 | struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); | ||
| 69 | struct ieee80211_chanctx_conf *chanctx_conf; | ||
| 70 | struct ieee80211_channel *channel; | ||
| 71 | struct sta_info *sta; | ||
| 72 | struct ieee80211_local *local = sdata->local; | ||
| 73 | struct station_info sinfo; | ||
| 74 | struct survey_info survey; | ||
| 75 | int i, q; | ||
| 76 | #define STA_STATS_SURVEY_LEN 7 | ||
| 77 | |||
| 78 | memset(data, 0, sizeof(u64) * STA_STATS_LEN); | ||
| 79 | |||
| 80 | #define ADD_STA_STATS(sta) \ | ||
| 81 | do { \ | ||
| 82 | data[i++] += sta->rx_packets; \ | ||
| 83 | data[i++] += sta->rx_bytes; \ | ||
| 84 | data[i++] += sta->num_duplicates; \ | ||
| 85 | data[i++] += sta->rx_fragments; \ | ||
| 86 | data[i++] += sta->rx_dropped; \ | ||
| 87 | \ | ||
| 88 | data[i++] += sinfo.tx_packets; \ | ||
| 89 | data[i++] += sinfo.tx_bytes; \ | ||
| 90 | data[i++] += sta->tx_fragments; \ | ||
| 91 | data[i++] += sta->tx_filtered_count; \ | ||
| 92 | data[i++] += sta->tx_retry_failed; \ | ||
| 93 | data[i++] += sta->tx_retry_count; \ | ||
| 94 | data[i++] += sta->beacon_loss_count; \ | ||
| 95 | } while (0) | ||
| 96 | |||
| 97 | /* For Managed stations, find the single station based on BSSID | ||
| 98 | * and use that. For interface types, iterate through all available | ||
| 99 | * stations and add stats for any station that is assigned to this | ||
| 100 | * network device. | ||
| 101 | */ | ||
| 102 | |||
| 103 | mutex_lock(&local->sta_mtx); | ||
| 104 | |||
| 105 | if (sdata->vif.type == NL80211_IFTYPE_STATION) { | ||
| 106 | sta = sta_info_get_bss(sdata, sdata->u.mgd.bssid); | ||
| 107 | |||
| 108 | if (!(sta && !WARN_ON(sta->sdata->dev != dev))) | ||
| 109 | goto do_survey; | ||
| 110 | |||
| 111 | sinfo.filled = 0; | ||
| 112 | sta_set_sinfo(sta, &sinfo); | ||
| 113 | |||
| 114 | i = 0; | ||
| 115 | ADD_STA_STATS(sta); | ||
| 116 | |||
| 117 | data[i++] = sta->sta_state; | ||
| 118 | |||
| 119 | |||
| 120 | if (sinfo.filled & STATION_INFO_TX_BITRATE) | ||
| 121 | data[i] = 100000 * | ||
| 122 | cfg80211_calculate_bitrate(&sinfo.txrate); | ||
| 123 | i++; | ||
| 124 | if (sinfo.filled & STATION_INFO_RX_BITRATE) | ||
| 125 | data[i] = 100000 * | ||
| 126 | cfg80211_calculate_bitrate(&sinfo.rxrate); | ||
| 127 | i++; | ||
| 128 | |||
| 129 | if (sinfo.filled & STATION_INFO_SIGNAL_AVG) | ||
| 130 | data[i] = (u8)sinfo.signal_avg; | ||
| 131 | i++; | ||
| 132 | } else { | ||
| 133 | list_for_each_entry(sta, &local->sta_list, list) { | ||
| 134 | /* Make sure this station belongs to the proper dev */ | ||
| 135 | if (sta->sdata->dev != dev) | ||
| 136 | continue; | ||
| 137 | |||
| 138 | sinfo.filled = 0; | ||
| 139 | sta_set_sinfo(sta, &sinfo); | ||
| 140 | i = 0; | ||
| 141 | ADD_STA_STATS(sta); | ||
| 142 | } | ||
| 143 | } | ||
| 144 | |||
| 145 | do_survey: | ||
| 146 | i = STA_STATS_LEN - STA_STATS_SURVEY_LEN; | ||
| 147 | /* Get survey stats for current channel */ | ||
| 148 | survey.filled = 0; | ||
| 149 | |||
| 150 | rcu_read_lock(); | ||
| 151 | chanctx_conf = rcu_dereference(sdata->vif.chanctx_conf); | ||
| 152 | if (chanctx_conf) | ||
| 153 | channel = chanctx_conf->def.chan; | ||
| 154 | else | ||
| 155 | channel = NULL; | ||
| 156 | rcu_read_unlock(); | ||
| 157 | |||
| 158 | if (channel) { | ||
| 159 | q = 0; | ||
| 160 | do { | ||
| 161 | survey.filled = 0; | ||
| 162 | if (drv_get_survey(local, q, &survey) != 0) { | ||
| 163 | survey.filled = 0; | ||
| 164 | break; | ||
| 165 | } | ||
| 166 | q++; | ||
| 167 | } while (channel != survey.channel); | ||
| 168 | } | ||
| 169 | |||
| 170 | if (survey.filled) | ||
| 171 | data[i++] = survey.channel->center_freq; | ||
| 172 | else | ||
| 173 | data[i++] = 0; | ||
| 174 | if (survey.filled & SURVEY_INFO_NOISE_DBM) | ||
| 175 | data[i++] = (u8)survey.noise; | ||
| 176 | else | ||
| 177 | data[i++] = -1LL; | ||
| 178 | if (survey.filled & SURVEY_INFO_CHANNEL_TIME) | ||
| 179 | data[i++] = survey.channel_time; | ||
| 180 | else | ||
| 181 | data[i++] = -1LL; | ||
| 182 | if (survey.filled & SURVEY_INFO_CHANNEL_TIME_BUSY) | ||
| 183 | data[i++] = survey.channel_time_busy; | ||
| 184 | else | ||
| 185 | data[i++] = -1LL; | ||
| 186 | if (survey.filled & SURVEY_INFO_CHANNEL_TIME_EXT_BUSY) | ||
| 187 | data[i++] = survey.channel_time_ext_busy; | ||
| 188 | else | ||
| 189 | data[i++] = -1LL; | ||
| 190 | if (survey.filled & SURVEY_INFO_CHANNEL_TIME_RX) | ||
| 191 | data[i++] = survey.channel_time_rx; | ||
| 192 | else | ||
| 193 | data[i++] = -1LL; | ||
| 194 | if (survey.filled & SURVEY_INFO_CHANNEL_TIME_TX) | ||
| 195 | data[i++] = survey.channel_time_tx; | ||
| 196 | else | ||
| 197 | data[i++] = -1LL; | ||
| 198 | |||
| 199 | mutex_unlock(&local->sta_mtx); | ||
| 200 | |||
| 201 | if (WARN_ON(i != STA_STATS_LEN)) | ||
| 202 | return; | ||
| 203 | |||
| 204 | drv_get_et_stats(sdata, stats, &(data[STA_STATS_LEN])); | ||
| 205 | } | ||
| 206 | |||
| 207 | static void ieee80211_get_strings(struct net_device *dev, u32 sset, u8 *data) | ||
| 208 | { | ||
| 209 | struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); | ||
| 210 | int sz_sta_stats = 0; | ||
| 211 | |||
| 212 | if (sset == ETH_SS_STATS) { | ||
| 213 | sz_sta_stats = sizeof(ieee80211_gstrings_sta_stats); | ||
| 214 | memcpy(data, ieee80211_gstrings_sta_stats, sz_sta_stats); | ||
| 215 | } | ||
| 216 | drv_get_et_strings(sdata, sset, &(data[sz_sta_stats])); | ||
| 217 | } | ||
| 218 | |||
| 219 | static int ieee80211_get_regs_len(struct net_device *dev) | ||
| 220 | { | ||
| 221 | return 0; | ||
| 222 | } | ||
| 223 | |||
| 224 | static void ieee80211_get_regs(struct net_device *dev, | ||
| 225 | struct ethtool_regs *regs, | ||
| 226 | void *data) | ||
| 227 | { | ||
| 228 | struct wireless_dev *wdev = dev->ieee80211_ptr; | ||
| 229 | |||
| 230 | regs->version = wdev->wiphy->hw_version; | ||
| 231 | regs->len = 0; | ||
| 232 | } | ||
| 233 | |||
| 234 | const struct ethtool_ops ieee80211_ethtool_ops = { | ||
| 235 | .get_drvinfo = cfg80211_get_drvinfo, | ||
| 236 | .get_regs_len = ieee80211_get_regs_len, | ||
| 237 | .get_regs = ieee80211_get_regs, | ||
| 238 | .get_link = ethtool_op_get_link, | ||
| 239 | .get_ringparam = ieee80211_get_ringparam, | ||
| 240 | .set_ringparam = ieee80211_set_ringparam, | ||
| 241 | .get_strings = ieee80211_get_strings, | ||
| 242 | .get_ethtool_stats = ieee80211_get_stats, | ||
| 243 | .get_sset_count = ieee80211_get_sset_count, | ||
| 244 | }; | ||
diff --git a/net/mac80211/ht.c b/net/mac80211/ht.c index 15702ff64a4c..ff630be2ca75 100644 --- a/net/mac80211/ht.c +++ b/net/mac80211/ht.c | |||
| @@ -150,13 +150,12 @@ bool ieee80211_ht_cap_ie_to_sta_ht_cap(struct ieee80211_sub_if_data *sdata, | |||
| 150 | 150 | ||
| 151 | /* | 151 | /* |
| 152 | * If user has specified capability over-rides, take care | 152 | * If user has specified capability over-rides, take care |
| 153 | * of that if the station we're setting up is the AP that | 153 | * of that if the station we're setting up is the AP or TDLS peer that |
| 154 | * we advertised a restricted capability set to. Override | 154 | * we advertised a restricted capability set to. Override |
| 155 | * our own capabilities and then use those below. | 155 | * our own capabilities and then use those below. |
| 156 | */ | 156 | */ |
| 157 | if ((sdata->vif.type == NL80211_IFTYPE_STATION || | 157 | if (sdata->vif.type == NL80211_IFTYPE_STATION || |
| 158 | sdata->vif.type == NL80211_IFTYPE_ADHOC) && | 158 | sdata->vif.type == NL80211_IFTYPE_ADHOC) |
| 159 | !test_sta_flag(sta, WLAN_STA_TDLS_PEER)) | ||
| 160 | ieee80211_apply_htcap_overrides(sdata, &own_cap); | 159 | ieee80211_apply_htcap_overrides(sdata, &own_cap); |
| 161 | 160 | ||
| 162 | /* | 161 | /* |
| @@ -228,6 +227,9 @@ bool ieee80211_ht_cap_ie_to_sta_ht_cap(struct ieee80211_sub_if_data *sdata, | |||
| 228 | if (own_cap.mcs.rx_mask[32/8] & ht_cap_ie->mcs.rx_mask[32/8] & 1) | 227 | if (own_cap.mcs.rx_mask[32/8] & ht_cap_ie->mcs.rx_mask[32/8] & 1) |
| 229 | ht_cap.mcs.rx_mask[32/8] |= 1; | 228 | ht_cap.mcs.rx_mask[32/8] |= 1; |
| 230 | 229 | ||
| 230 | /* set Rx highest rate */ | ||
| 231 | ht_cap.mcs.rx_highest = ht_cap_ie->mcs.rx_highest; | ||
| 232 | |||
| 231 | apply: | 233 | apply: |
| 232 | changed = memcmp(&sta->sta.ht_cap, &ht_cap, sizeof(ht_cap)); | 234 | changed = memcmp(&sta->sta.ht_cap, &ht_cap, sizeof(ht_cap)); |
| 233 | 235 | ||
diff --git a/net/mac80211/ibss.c b/net/mac80211/ibss.c index 18ee0a256b1e..9713dc54ea4b 100644 --- a/net/mac80211/ibss.c +++ b/net/mac80211/ibss.c | |||
| @@ -143,7 +143,7 @@ ieee80211_ibss_build_presp(struct ieee80211_sub_if_data *sdata, | |||
| 143 | *pos++ = csa_settings->block_tx ? 1 : 0; | 143 | *pos++ = csa_settings->block_tx ? 1 : 0; |
| 144 | *pos++ = ieee80211_frequency_to_channel( | 144 | *pos++ = ieee80211_frequency_to_channel( |
| 145 | csa_settings->chandef.chan->center_freq); | 145 | csa_settings->chandef.chan->center_freq); |
| 146 | sdata->csa_counter_offset_beacon[0] = (pos - presp->head); | 146 | presp->csa_counter_offsets[0] = (pos - presp->head); |
| 147 | *pos++ = csa_settings->count; | 147 | *pos++ = csa_settings->count; |
| 148 | } | 148 | } |
| 149 | 149 | ||
| @@ -189,17 +189,8 @@ ieee80211_ibss_build_presp(struct ieee80211_sub_if_data *sdata, | |||
| 189 | chandef, 0); | 189 | chandef, 0); |
| 190 | } | 190 | } |
| 191 | 191 | ||
| 192 | if (local->hw.queues >= IEEE80211_NUM_ACS) { | 192 | if (local->hw.queues >= IEEE80211_NUM_ACS) |
| 193 | *pos++ = WLAN_EID_VENDOR_SPECIFIC; | 193 | pos = ieee80211_add_wmm_info_ie(pos, 0); /* U-APSD not in use */ |
| 194 | *pos++ = 7; /* len */ | ||
| 195 | *pos++ = 0x00; /* Microsoft OUI 00:50:F2 */ | ||
| 196 | *pos++ = 0x50; | ||
| 197 | *pos++ = 0xf2; | ||
| 198 | *pos++ = 2; /* WME */ | ||
| 199 | *pos++ = 0; /* WME info */ | ||
| 200 | *pos++ = 1; /* WME ver */ | ||
| 201 | *pos++ = 0; /* U-APSD no in use */ | ||
| 202 | } | ||
| 203 | 194 | ||
| 204 | presp->head_len = pos - presp->head; | 195 | presp->head_len = pos - presp->head; |
| 205 | if (WARN_ON(presp->head_len > frame_len)) | 196 | if (WARN_ON(presp->head_len > frame_len)) |
diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index ac9836e0aab3..ef7a089ac546 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h | |||
| @@ -229,16 +229,29 @@ struct ieee80211_rx_data { | |||
| 229 | u16 tkip_iv16; | 229 | u16 tkip_iv16; |
| 230 | }; | 230 | }; |
| 231 | 231 | ||
| 232 | struct ieee80211_csa_settings { | ||
| 233 | const u16 *counter_offsets_beacon; | ||
| 234 | const u16 *counter_offsets_presp; | ||
| 235 | |||
| 236 | int n_counter_offsets_beacon; | ||
| 237 | int n_counter_offsets_presp; | ||
| 238 | |||
| 239 | u8 count; | ||
| 240 | }; | ||
| 241 | |||
| 232 | struct beacon_data { | 242 | struct beacon_data { |
| 233 | u8 *head, *tail; | 243 | u8 *head, *tail; |
| 234 | int head_len, tail_len; | 244 | int head_len, tail_len; |
| 235 | struct ieee80211_meshconf_ie *meshconf; | 245 | struct ieee80211_meshconf_ie *meshconf; |
| 246 | u16 csa_counter_offsets[IEEE80211_MAX_CSA_COUNTERS_NUM]; | ||
| 247 | u8 csa_current_counter; | ||
| 236 | struct rcu_head rcu_head; | 248 | struct rcu_head rcu_head; |
| 237 | }; | 249 | }; |
| 238 | 250 | ||
| 239 | struct probe_resp { | 251 | struct probe_resp { |
| 240 | struct rcu_head rcu_head; | 252 | struct rcu_head rcu_head; |
| 241 | int len; | 253 | int len; |
| 254 | u16 csa_counter_offsets[IEEE80211_MAX_CSA_COUNTERS_NUM]; | ||
| 242 | u8 data[0]; | 255 | u8 data[0]; |
| 243 | }; | 256 | }; |
| 244 | 257 | ||
| @@ -332,7 +345,6 @@ enum ieee80211_sta_flags { | |||
| 332 | IEEE80211_STA_CONNECTION_POLL = BIT(1), | 345 | IEEE80211_STA_CONNECTION_POLL = BIT(1), |
| 333 | IEEE80211_STA_CONTROL_PORT = BIT(2), | 346 | IEEE80211_STA_CONTROL_PORT = BIT(2), |
| 334 | IEEE80211_STA_DISABLE_HT = BIT(4), | 347 | IEEE80211_STA_DISABLE_HT = BIT(4), |
| 335 | IEEE80211_STA_CSA_RECEIVED = BIT(5), | ||
| 336 | IEEE80211_STA_MFP_ENABLED = BIT(6), | 348 | IEEE80211_STA_MFP_ENABLED = BIT(6), |
| 337 | IEEE80211_STA_UAPSD_ENABLED = BIT(7), | 349 | IEEE80211_STA_UAPSD_ENABLED = BIT(7), |
| 338 | IEEE80211_STA_NULLFUNC_ACKED = BIT(8), | 350 | IEEE80211_STA_NULLFUNC_ACKED = BIT(8), |
| @@ -490,6 +502,9 @@ struct ieee80211_if_managed { | |||
| 490 | struct ieee80211_ht_cap ht_capa_mask; /* Valid parts of ht_capa */ | 502 | struct ieee80211_ht_cap ht_capa_mask; /* Valid parts of ht_capa */ |
| 491 | struct ieee80211_vht_cap vht_capa; /* configured VHT overrides */ | 503 | struct ieee80211_vht_cap vht_capa; /* configured VHT overrides */ |
| 492 | struct ieee80211_vht_cap vht_capa_mask; /* Valid parts of vht_capa */ | 504 | struct ieee80211_vht_cap vht_capa_mask; /* Valid parts of vht_capa */ |
| 505 | |||
| 506 | u8 tdls_peer[ETH_ALEN] __aligned(2); | ||
| 507 | struct delayed_work tdls_peer_del_work; | ||
| 493 | }; | 508 | }; |
| 494 | 509 | ||
| 495 | struct ieee80211_if_ibss { | 510 | struct ieee80211_if_ibss { |
| @@ -688,6 +703,24 @@ enum ieee80211_chanctx_mode { | |||
| 688 | IEEE80211_CHANCTX_EXCLUSIVE | 703 | IEEE80211_CHANCTX_EXCLUSIVE |
| 689 | }; | 704 | }; |
| 690 | 705 | ||
| 706 | /** | ||
| 707 | * enum ieee80211_chanctx_replace_state - channel context replacement state | ||
| 708 | * | ||
| 709 | * This is used for channel context in-place reservations that require channel | ||
| 710 | * context switch/swap. | ||
| 711 | * | ||
| 712 | * @IEEE80211_CHANCTX_REPLACE_NONE: no replacement is taking place | ||
| 713 | * @IEEE80211_CHANCTX_WILL_BE_REPLACED: this channel context will be replaced | ||
| 714 | * by a (not yet registered) channel context pointed by %replace_ctx. | ||
| 715 | * @IEEE80211_CHANCTX_REPLACES_OTHER: this (not yet registered) channel context | ||
| 716 | * replaces an existing channel context pointed to by %replace_ctx. | ||
| 717 | */ | ||
| 718 | enum ieee80211_chanctx_replace_state { | ||
| 719 | IEEE80211_CHANCTX_REPLACE_NONE, | ||
| 720 | IEEE80211_CHANCTX_WILL_BE_REPLACED, | ||
| 721 | IEEE80211_CHANCTX_REPLACES_OTHER, | ||
| 722 | }; | ||
| 723 | |||
| 691 | struct ieee80211_chanctx { | 724 | struct ieee80211_chanctx { |
| 692 | struct list_head list; | 725 | struct list_head list; |
| 693 | struct rcu_head rcu_head; | 726 | struct rcu_head rcu_head; |
| @@ -695,6 +728,9 @@ struct ieee80211_chanctx { | |||
| 695 | struct list_head assigned_vifs; | 728 | struct list_head assigned_vifs; |
| 696 | struct list_head reserved_vifs; | 729 | struct list_head reserved_vifs; |
| 697 | 730 | ||
| 731 | enum ieee80211_chanctx_replace_state replace_state; | ||
| 732 | struct ieee80211_chanctx *replace_ctx; | ||
| 733 | |||
| 698 | enum ieee80211_chanctx_mode mode; | 734 | enum ieee80211_chanctx_mode mode; |
| 699 | bool driver_present; | 735 | bool driver_present; |
| 700 | 736 | ||
| @@ -754,9 +790,6 @@ struct ieee80211_sub_if_data { | |||
| 754 | struct mac80211_qos_map __rcu *qos_map; | 790 | struct mac80211_qos_map __rcu *qos_map; |
| 755 | 791 | ||
| 756 | struct work_struct csa_finalize_work; | 792 | struct work_struct csa_finalize_work; |
| 757 | u16 csa_counter_offset_beacon[IEEE80211_MAX_CSA_COUNTERS_NUM]; | ||
| 758 | u16 csa_counter_offset_presp[IEEE80211_MAX_CSA_COUNTERS_NUM]; | ||
| 759 | bool csa_radar_required; | ||
| 760 | bool csa_block_tx; /* write-protected by sdata_lock and local->mtx */ | 793 | bool csa_block_tx; /* write-protected by sdata_lock and local->mtx */ |
| 761 | struct cfg80211_chan_def csa_chandef; | 794 | struct cfg80211_chan_def csa_chandef; |
| 762 | 795 | ||
| @@ -767,7 +800,7 @@ struct ieee80211_sub_if_data { | |||
| 767 | struct ieee80211_chanctx *reserved_chanctx; | 800 | struct ieee80211_chanctx *reserved_chanctx; |
| 768 | struct cfg80211_chan_def reserved_chandef; | 801 | struct cfg80211_chan_def reserved_chandef; |
| 769 | bool reserved_radar_required; | 802 | bool reserved_radar_required; |
| 770 | u8 csa_current_counter; | 803 | bool reserved_ready; |
| 771 | 804 | ||
| 772 | /* used to reconfigure hardware SM PS */ | 805 | /* used to reconfigure hardware SM PS */ |
| 773 | struct work_struct recalc_smps; | 806 | struct work_struct recalc_smps; |
| @@ -892,10 +925,17 @@ ieee80211_vif_get_shift(struct ieee80211_vif *vif) | |||
| 892 | return shift; | 925 | return shift; |
| 893 | } | 926 | } |
| 894 | 927 | ||
| 928 | struct ieee80211_rx_agg { | ||
| 929 | u8 addr[ETH_ALEN]; | ||
| 930 | u16 tid; | ||
| 931 | }; | ||
| 932 | |||
| 895 | enum sdata_queue_type { | 933 | enum sdata_queue_type { |
| 896 | IEEE80211_SDATA_QUEUE_TYPE_FRAME = 0, | 934 | IEEE80211_SDATA_QUEUE_TYPE_FRAME = 0, |
| 897 | IEEE80211_SDATA_QUEUE_AGG_START = 1, | 935 | IEEE80211_SDATA_QUEUE_AGG_START = 1, |
| 898 | IEEE80211_SDATA_QUEUE_AGG_STOP = 2, | 936 | IEEE80211_SDATA_QUEUE_AGG_STOP = 2, |
| 937 | IEEE80211_SDATA_QUEUE_RX_AGG_START = 3, | ||
| 938 | IEEE80211_SDATA_QUEUE_RX_AGG_STOP = 4, | ||
| 899 | }; | 939 | }; |
| 900 | 940 | ||
| 901 | enum { | 941 | enum { |
| @@ -912,6 +952,9 @@ enum queue_stop_reason { | |||
| 912 | IEEE80211_QUEUE_STOP_REASON_SKB_ADD, | 952 | IEEE80211_QUEUE_STOP_REASON_SKB_ADD, |
| 913 | IEEE80211_QUEUE_STOP_REASON_OFFCHANNEL, | 953 | IEEE80211_QUEUE_STOP_REASON_OFFCHANNEL, |
| 914 | IEEE80211_QUEUE_STOP_REASON_FLUSH, | 954 | IEEE80211_QUEUE_STOP_REASON_FLUSH, |
| 955 | IEEE80211_QUEUE_STOP_REASON_TDLS_TEARDOWN, | ||
| 956 | |||
| 957 | IEEE80211_QUEUE_STOP_REASONS, | ||
| 915 | }; | 958 | }; |
| 916 | 959 | ||
| 917 | #ifdef CONFIG_MAC80211_LEDS | 960 | #ifdef CONFIG_MAC80211_LEDS |
| @@ -1008,6 +1051,7 @@ struct ieee80211_local { | |||
| 1008 | struct workqueue_struct *workqueue; | 1051 | struct workqueue_struct *workqueue; |
| 1009 | 1052 | ||
| 1010 | unsigned long queue_stop_reasons[IEEE80211_MAX_QUEUES]; | 1053 | unsigned long queue_stop_reasons[IEEE80211_MAX_QUEUES]; |
| 1054 | int q_stop_reasons[IEEE80211_MAX_QUEUES][IEEE80211_QUEUE_STOP_REASONS]; | ||
| 1011 | /* also used to protect ampdu_ac_queue and amdpu_ac_stop_refcnt */ | 1055 | /* also used to protect ampdu_ac_queue and amdpu_ac_stop_refcnt */ |
| 1012 | spinlock_t queue_stop_reason_lock; | 1056 | spinlock_t queue_stop_reason_lock; |
| 1013 | 1057 | ||
| @@ -1135,7 +1179,8 @@ struct ieee80211_local { | |||
| 1135 | unsigned long scanning; | 1179 | unsigned long scanning; |
| 1136 | struct cfg80211_ssid scan_ssid; | 1180 | struct cfg80211_ssid scan_ssid; |
| 1137 | struct cfg80211_scan_request *int_scan_req; | 1181 | struct cfg80211_scan_request *int_scan_req; |
| 1138 | struct cfg80211_scan_request *scan_req, *hw_scan_req; | 1182 | struct cfg80211_scan_request *scan_req; |
| 1183 | struct ieee80211_scan_request *hw_scan_req; | ||
| 1139 | struct cfg80211_chan_def scan_chandef; | 1184 | struct cfg80211_chan_def scan_chandef; |
| 1140 | enum ieee80211_band hw_scan_band; | 1185 | enum ieee80211_band hw_scan_band; |
| 1141 | int scan_channel_idx; | 1186 | int scan_channel_idx; |
| @@ -1476,7 +1521,6 @@ void ieee80211_sw_roc_work(struct work_struct *work); | |||
| 1476 | void ieee80211_handle_roc_started(struct ieee80211_roc_work *roc); | 1521 | void ieee80211_handle_roc_started(struct ieee80211_roc_work *roc); |
| 1477 | 1522 | ||
| 1478 | /* channel switch handling */ | 1523 | /* channel switch handling */ |
| 1479 | bool ieee80211_csa_needs_block_tx(struct ieee80211_local *local); | ||
| 1480 | void ieee80211_csa_finalize_work(struct work_struct *work); | 1524 | void ieee80211_csa_finalize_work(struct work_struct *work); |
| 1481 | int ieee80211_channel_switch(struct wiphy *wiphy, struct net_device *dev, | 1525 | int ieee80211_channel_switch(struct wiphy *wiphy, struct net_device *dev, |
| 1482 | struct cfg80211_csa_settings *params); | 1526 | struct cfg80211_csa_settings *params); |
| @@ -1540,6 +1584,10 @@ void ___ieee80211_stop_rx_ba_session(struct sta_info *sta, u16 tid, | |||
| 1540 | u16 initiator, u16 reason, bool stop); | 1584 | u16 initiator, u16 reason, bool stop); |
| 1541 | void __ieee80211_stop_rx_ba_session(struct sta_info *sta, u16 tid, | 1585 | void __ieee80211_stop_rx_ba_session(struct sta_info *sta, u16 tid, |
| 1542 | u16 initiator, u16 reason, bool stop); | 1586 | u16 initiator, u16 reason, bool stop); |
| 1587 | void __ieee80211_start_rx_ba_session(struct sta_info *sta, | ||
| 1588 | u8 dialog_token, u16 timeout, | ||
| 1589 | u16 start_seq_num, u16 ba_policy, u16 tid, | ||
| 1590 | u16 buf_size, bool tx); | ||
| 1543 | void ieee80211_sta_tear_down_BA_sessions(struct sta_info *sta, | 1591 | void ieee80211_sta_tear_down_BA_sessions(struct sta_info *sta, |
| 1544 | enum ieee80211_agg_stop_reason reason); | 1592 | enum ieee80211_agg_stop_reason reason); |
| 1545 | void ieee80211_process_delba(struct ieee80211_sub_if_data *sdata, | 1593 | void ieee80211_process_delba(struct ieee80211_sub_if_data *sdata, |
| @@ -1692,6 +1740,21 @@ static inline void ieee802_11_parse_elems(const u8 *start, size_t len, | |||
| 1692 | ieee802_11_parse_elems_crc(start, len, action, elems, 0, 0); | 1740 | ieee802_11_parse_elems_crc(start, len, action, elems, 0, 0); |
| 1693 | } | 1741 | } |
| 1694 | 1742 | ||
| 1743 | static inline bool ieee80211_rx_reorder_ready(struct sk_buff_head *frames) | ||
| 1744 | { | ||
| 1745 | struct sk_buff *tail = skb_peek_tail(frames); | ||
| 1746 | struct ieee80211_rx_status *status; | ||
| 1747 | |||
| 1748 | if (!tail) | ||
| 1749 | return false; | ||
| 1750 | |||
| 1751 | status = IEEE80211_SKB_RXCB(tail); | ||
| 1752 | if (status->flag & RX_FLAG_AMSDU_MORE) | ||
| 1753 | return false; | ||
| 1754 | |||
| 1755 | return true; | ||
| 1756 | } | ||
| 1757 | |||
| 1695 | void ieee80211_dynamic_ps_enable_work(struct work_struct *work); | 1758 | void ieee80211_dynamic_ps_enable_work(struct work_struct *work); |
| 1696 | void ieee80211_dynamic_ps_disable_work(struct work_struct *work); | 1759 | void ieee80211_dynamic_ps_disable_work(struct work_struct *work); |
| 1697 | void ieee80211_dynamic_ps_timer(unsigned long data); | 1760 | void ieee80211_dynamic_ps_timer(unsigned long data); |
| @@ -1705,14 +1768,24 @@ void ieee80211_sta_tx_notify(struct ieee80211_sub_if_data *sdata, | |||
| 1705 | 1768 | ||
| 1706 | void ieee80211_wake_queues_by_reason(struct ieee80211_hw *hw, | 1769 | void ieee80211_wake_queues_by_reason(struct ieee80211_hw *hw, |
| 1707 | unsigned long queues, | 1770 | unsigned long queues, |
| 1708 | enum queue_stop_reason reason); | 1771 | enum queue_stop_reason reason, |
| 1772 | bool refcounted); | ||
| 1773 | void ieee80211_stop_vif_queues(struct ieee80211_local *local, | ||
| 1774 | struct ieee80211_sub_if_data *sdata, | ||
| 1775 | enum queue_stop_reason reason); | ||
| 1776 | void ieee80211_wake_vif_queues(struct ieee80211_local *local, | ||
| 1777 | struct ieee80211_sub_if_data *sdata, | ||
| 1778 | enum queue_stop_reason reason); | ||
| 1709 | void ieee80211_stop_queues_by_reason(struct ieee80211_hw *hw, | 1779 | void ieee80211_stop_queues_by_reason(struct ieee80211_hw *hw, |
| 1710 | unsigned long queues, | 1780 | unsigned long queues, |
| 1711 | enum queue_stop_reason reason); | 1781 | enum queue_stop_reason reason, |
| 1782 | bool refcounted); | ||
| 1712 | void ieee80211_wake_queue_by_reason(struct ieee80211_hw *hw, int queue, | 1783 | void ieee80211_wake_queue_by_reason(struct ieee80211_hw *hw, int queue, |
| 1713 | enum queue_stop_reason reason); | 1784 | enum queue_stop_reason reason, |
| 1785 | bool refcounted); | ||
| 1714 | void ieee80211_stop_queue_by_reason(struct ieee80211_hw *hw, int queue, | 1786 | void ieee80211_stop_queue_by_reason(struct ieee80211_hw *hw, int queue, |
| 1715 | enum queue_stop_reason reason); | 1787 | enum queue_stop_reason reason, |
| 1788 | bool refcounted); | ||
| 1716 | void ieee80211_propagate_queue_wake(struct ieee80211_local *local, int queue); | 1789 | void ieee80211_propagate_queue_wake(struct ieee80211_local *local, int queue); |
| 1717 | void ieee80211_add_pending_skb(struct ieee80211_local *local, | 1790 | void ieee80211_add_pending_skb(struct ieee80211_local *local, |
| 1718 | struct sk_buff *skb); | 1791 | struct sk_buff *skb); |
| @@ -1730,8 +1803,10 @@ void ieee80211_send_deauth_disassoc(struct ieee80211_sub_if_data *sdata, | |||
| 1730 | const u8 *bssid, u16 stype, u16 reason, | 1803 | const u8 *bssid, u16 stype, u16 reason, |
| 1731 | bool send_frame, u8 *frame_buf); | 1804 | bool send_frame, u8 *frame_buf); |
| 1732 | int ieee80211_build_preq_ies(struct ieee80211_local *local, u8 *buffer, | 1805 | int ieee80211_build_preq_ies(struct ieee80211_local *local, u8 *buffer, |
| 1733 | size_t buffer_len, const u8 *ie, size_t ie_len, | 1806 | size_t buffer_len, |
| 1734 | enum ieee80211_band band, u32 rate_mask, | 1807 | struct ieee80211_scan_ies *ie_desc, |
| 1808 | const u8 *ie, size_t ie_len, | ||
| 1809 | u8 bands_used, u32 *rate_masks, | ||
| 1735 | struct cfg80211_chan_def *chandef); | 1810 | struct cfg80211_chan_def *chandef); |
| 1736 | struct sk_buff *ieee80211_build_probe_req(struct ieee80211_sub_if_data *sdata, | 1811 | struct sk_buff *ieee80211_build_probe_req(struct ieee80211_sub_if_data *sdata, |
| 1737 | u8 *dst, u32 ratemask, | 1812 | u8 *dst, u32 ratemask, |
| @@ -1774,6 +1849,7 @@ int ieee80211_add_srates_ie(struct ieee80211_sub_if_data *sdata, | |||
| 1774 | int ieee80211_add_ext_srates_ie(struct ieee80211_sub_if_data *sdata, | 1849 | int ieee80211_add_ext_srates_ie(struct ieee80211_sub_if_data *sdata, |
| 1775 | struct sk_buff *skb, bool need_basic, | 1850 | struct sk_buff *skb, bool need_basic, |
| 1776 | enum ieee80211_band band); | 1851 | enum ieee80211_band band); |
| 1852 | u8 *ieee80211_add_wmm_info_ie(u8 *buf, u8 qosinfo); | ||
| 1777 | 1853 | ||
| 1778 | /* channel management */ | 1854 | /* channel management */ |
| 1779 | void ieee80211_ht_oper_to_chandef(struct ieee80211_channel *control_chan, | 1855 | void ieee80211_ht_oper_to_chandef(struct ieee80211_channel *control_chan, |
| @@ -1791,18 +1867,14 @@ ieee80211_vif_reserve_chanctx(struct ieee80211_sub_if_data *sdata, | |||
| 1791 | enum ieee80211_chanctx_mode mode, | 1867 | enum ieee80211_chanctx_mode mode, |
| 1792 | bool radar_required); | 1868 | bool radar_required); |
| 1793 | int __must_check | 1869 | int __must_check |
| 1794 | ieee80211_vif_use_reserved_context(struct ieee80211_sub_if_data *sdata, | 1870 | ieee80211_vif_use_reserved_context(struct ieee80211_sub_if_data *sdata); |
| 1795 | u32 *changed); | ||
| 1796 | int ieee80211_vif_unreserve_chanctx(struct ieee80211_sub_if_data *sdata); | 1871 | int ieee80211_vif_unreserve_chanctx(struct ieee80211_sub_if_data *sdata); |
| 1872 | int ieee80211_vif_use_reserved_switch(struct ieee80211_local *local); | ||
| 1797 | 1873 | ||
| 1798 | int __must_check | 1874 | int __must_check |
| 1799 | ieee80211_vif_change_bandwidth(struct ieee80211_sub_if_data *sdata, | 1875 | ieee80211_vif_change_bandwidth(struct ieee80211_sub_if_data *sdata, |
| 1800 | const struct cfg80211_chan_def *chandef, | 1876 | const struct cfg80211_chan_def *chandef, |
| 1801 | u32 *changed); | 1877 | u32 *changed); |
| 1802 | /* NOTE: only use ieee80211_vif_change_channel() for channel switch */ | ||
| 1803 | int __must_check | ||
| 1804 | ieee80211_vif_change_channel(struct ieee80211_sub_if_data *sdata, | ||
| 1805 | u32 *changed); | ||
| 1806 | void ieee80211_vif_release_channel(struct ieee80211_sub_if_data *sdata); | 1878 | void ieee80211_vif_release_channel(struct ieee80211_sub_if_data *sdata); |
| 1807 | void ieee80211_vif_vlan_copy_chanctx(struct ieee80211_sub_if_data *sdata); | 1879 | void ieee80211_vif_vlan_copy_chanctx(struct ieee80211_sub_if_data *sdata); |
| 1808 | void ieee80211_vif_copy_chanctx_to_vlans(struct ieee80211_sub_if_data *sdata, | 1880 | void ieee80211_vif_copy_chanctx_to_vlans(struct ieee80211_sub_if_data *sdata, |
| @@ -1842,11 +1914,14 @@ int ieee80211_max_num_channels(struct ieee80211_local *local); | |||
| 1842 | int ieee80211_tdls_mgmt(struct wiphy *wiphy, struct net_device *dev, | 1914 | int ieee80211_tdls_mgmt(struct wiphy *wiphy, struct net_device *dev, |
| 1843 | const u8 *peer, u8 action_code, u8 dialog_token, | 1915 | const u8 *peer, u8 action_code, u8 dialog_token, |
| 1844 | u16 status_code, u32 peer_capability, | 1916 | u16 status_code, u32 peer_capability, |
| 1845 | const u8 *extra_ies, size_t extra_ies_len); | 1917 | bool initiator, const u8 *extra_ies, |
| 1918 | size_t extra_ies_len); | ||
| 1846 | int ieee80211_tdls_oper(struct wiphy *wiphy, struct net_device *dev, | 1919 | int ieee80211_tdls_oper(struct wiphy *wiphy, struct net_device *dev, |
| 1847 | const u8 *peer, enum nl80211_tdls_operation oper); | 1920 | const u8 *peer, enum nl80211_tdls_operation oper); |
| 1848 | 1921 | ||
| 1849 | 1922 | ||
| 1923 | extern const struct ethtool_ops ieee80211_ethtool_ops; | ||
| 1924 | |||
| 1850 | #ifdef CONFIG_MAC80211_NOINLINE | 1925 | #ifdef CONFIG_MAC80211_NOINLINE |
| 1851 | #define debug_noinline noinline | 1926 | #define debug_noinline noinline |
| 1852 | #else | 1927 | #else |
| @@ -1854,3 +1929,4 @@ int ieee80211_tdls_oper(struct wiphy *wiphy, struct net_device *dev, | |||
| 1854 | #endif | 1929 | #endif |
| 1855 | 1930 | ||
| 1856 | #endif /* IEEE80211_I_H */ | 1931 | #endif /* IEEE80211_I_H */ |
| 1932 | void ieee80211_tdls_peer_del_work(struct work_struct *wk); | ||
diff --git a/net/mac80211/iface.c b/net/mac80211/iface.c index 388b863e821c..01eede7406a5 100644 --- a/net/mac80211/iface.c +++ b/net/mac80211/iface.c | |||
| @@ -841,10 +841,11 @@ static void ieee80211_do_stop(struct ieee80211_sub_if_data *sdata, | |||
| 841 | sdata_lock(sdata); | 841 | sdata_lock(sdata); |
| 842 | mutex_lock(&local->mtx); | 842 | mutex_lock(&local->mtx); |
| 843 | sdata->vif.csa_active = false; | 843 | sdata->vif.csa_active = false; |
| 844 | if (!ieee80211_csa_needs_block_tx(local)) | 844 | if (sdata->csa_block_tx) { |
| 845 | ieee80211_wake_queues_by_reason(&local->hw, | 845 | ieee80211_wake_vif_queues(local, sdata, |
| 846 | IEEE80211_MAX_QUEUE_MAP, | 846 | IEEE80211_QUEUE_STOP_REASON_CSA); |
| 847 | IEEE80211_QUEUE_STOP_REASON_CSA); | 847 | sdata->csa_block_tx = false; |
| 848 | } | ||
| 848 | mutex_unlock(&local->mtx); | 849 | mutex_unlock(&local->mtx); |
| 849 | sdata_unlock(sdata); | 850 | sdata_unlock(sdata); |
| 850 | 851 | ||
| @@ -1139,6 +1140,7 @@ static void ieee80211_iface_work(struct work_struct *work) | |||
| 1139 | struct sk_buff *skb; | 1140 | struct sk_buff *skb; |
| 1140 | struct sta_info *sta; | 1141 | struct sta_info *sta; |
| 1141 | struct ieee80211_ra_tid *ra_tid; | 1142 | struct ieee80211_ra_tid *ra_tid; |
| 1143 | struct ieee80211_rx_agg *rx_agg; | ||
| 1142 | 1144 | ||
| 1143 | if (!ieee80211_sdata_running(sdata)) | 1145 | if (!ieee80211_sdata_running(sdata)) |
| 1144 | return; | 1146 | return; |
| @@ -1166,6 +1168,34 @@ static void ieee80211_iface_work(struct work_struct *work) | |||
| 1166 | ra_tid = (void *)&skb->cb; | 1168 | ra_tid = (void *)&skb->cb; |
| 1167 | ieee80211_stop_tx_ba_cb(&sdata->vif, ra_tid->ra, | 1169 | ieee80211_stop_tx_ba_cb(&sdata->vif, ra_tid->ra, |
| 1168 | ra_tid->tid); | 1170 | ra_tid->tid); |
| 1171 | } else if (skb->pkt_type == IEEE80211_SDATA_QUEUE_RX_AGG_START) { | ||
| 1172 | rx_agg = (void *)&skb->cb; | ||
| 1173 | mutex_lock(&local->sta_mtx); | ||
| 1174 | sta = sta_info_get_bss(sdata, rx_agg->addr); | ||
| 1175 | if (sta) { | ||
| 1176 | u16 last_seq; | ||
| 1177 | |||
| 1178 | last_seq = le16_to_cpu( | ||
| 1179 | sta->last_seq_ctrl[rx_agg->tid]); | ||
| 1180 | |||
| 1181 | __ieee80211_start_rx_ba_session(sta, | ||
| 1182 | 0, 0, | ||
| 1183 | ieee80211_sn_inc(last_seq), | ||
| 1184 | 1, rx_agg->tid, | ||
| 1185 | IEEE80211_MAX_AMPDU_BUF, | ||
| 1186 | false); | ||
| 1187 | } | ||
| 1188 | mutex_unlock(&local->sta_mtx); | ||
| 1189 | } else if (skb->pkt_type == IEEE80211_SDATA_QUEUE_RX_AGG_STOP) { | ||
| 1190 | rx_agg = (void *)&skb->cb; | ||
| 1191 | mutex_lock(&local->sta_mtx); | ||
| 1192 | sta = sta_info_get_bss(sdata, rx_agg->addr); | ||
| 1193 | if (sta) | ||
| 1194 | __ieee80211_stop_rx_ba_session(sta, | ||
| 1195 | rx_agg->tid, | ||
| 1196 | WLAN_BACK_RECIPIENT, 0, | ||
| 1197 | false); | ||
| 1198 | mutex_unlock(&local->sta_mtx); | ||
| 1169 | } else if (ieee80211_is_action(mgmt->frame_control) && | 1199 | } else if (ieee80211_is_action(mgmt->frame_control) && |
| 1170 | mgmt->u.action.category == WLAN_CATEGORY_BACK) { | 1200 | mgmt->u.action.category == WLAN_CATEGORY_BACK) { |
| 1171 | int len = skb->len; | 1201 | int len = skb->len; |
| @@ -1623,9 +1653,9 @@ int ieee80211_if_add(struct ieee80211_local *local, const char *name, | |||
| 1623 | if (local->hw.queues >= IEEE80211_NUM_ACS) | 1653 | if (local->hw.queues >= IEEE80211_NUM_ACS) |
| 1624 | txqs = IEEE80211_NUM_ACS; | 1654 | txqs = IEEE80211_NUM_ACS; |
| 1625 | 1655 | ||
| 1626 | ndev = alloc_netdev_mqs(sizeof(*sdata) + | 1656 | ndev = alloc_netdev_mqs(sizeof(*sdata) + local->hw.vif_data_size, |
| 1627 | local->hw.vif_data_size, | 1657 | name, NET_NAME_UNKNOWN, |
| 1628 | name, ieee80211_if_setup, txqs, 1); | 1658 | ieee80211_if_setup, txqs, 1); |
| 1629 | if (!ndev) | 1659 | if (!ndev) |
| 1630 | return -ENOMEM; | 1660 | return -ENOMEM; |
| 1631 | dev_net_set(ndev, wiphy_net(local->hw.wiphy)); | 1661 | dev_net_set(ndev, wiphy_net(local->hw.wiphy)); |
| @@ -1705,6 +1735,8 @@ int ieee80211_if_add(struct ieee80211_local *local, const char *name, | |||
| 1705 | 1735 | ||
| 1706 | ndev->features |= local->hw.netdev_features; | 1736 | ndev->features |= local->hw.netdev_features; |
| 1707 | 1737 | ||
| 1738 | netdev_set_default_ethtool_ops(ndev, &ieee80211_ethtool_ops); | ||
| 1739 | |||
| 1708 | ret = register_netdevice(ndev); | 1740 | ret = register_netdevice(ndev); |
| 1709 | if (ret) { | 1741 | if (ret) { |
| 1710 | free_netdev(ndev); | 1742 | free_netdev(ndev); |
diff --git a/net/mac80211/key.c b/net/mac80211/key.c index 16d97f044a20..d808cff80153 100644 --- a/net/mac80211/key.c +++ b/net/mac80211/key.c | |||
| @@ -482,9 +482,6 @@ int ieee80211_key_link(struct ieee80211_key *key, | |||
| 482 | int idx, ret; | 482 | int idx, ret; |
| 483 | bool pairwise; | 483 | bool pairwise; |
| 484 | 484 | ||
| 485 | if (WARN_ON(!sdata || !key)) | ||
| 486 | return -EINVAL; | ||
| 487 | |||
| 488 | pairwise = key->conf.flags & IEEE80211_KEY_FLAG_PAIRWISE; | 485 | pairwise = key->conf.flags & IEEE80211_KEY_FLAG_PAIRWISE; |
| 489 | idx = key->conf.keyidx; | 486 | idx = key->conf.keyidx; |
| 490 | key->local = sdata->local; | 487 | key->local = sdata->local; |
diff --git a/net/mac80211/main.c b/net/mac80211/main.c index d17c26d6e369..e0ab4320a078 100644 --- a/net/mac80211/main.c +++ b/net/mac80211/main.c | |||
| @@ -272,7 +272,8 @@ void ieee80211_restart_hw(struct ieee80211_hw *hw) | |||
| 272 | 272 | ||
| 273 | /* use this reason, ieee80211_reconfig will unblock it */ | 273 | /* use this reason, ieee80211_reconfig will unblock it */ |
| 274 | ieee80211_stop_queues_by_reason(hw, IEEE80211_MAX_QUEUE_MAP, | 274 | ieee80211_stop_queues_by_reason(hw, IEEE80211_MAX_QUEUE_MAP, |
| 275 | IEEE80211_QUEUE_STOP_REASON_SUSPEND); | 275 | IEEE80211_QUEUE_STOP_REASON_SUSPEND, |
| 276 | false); | ||
| 276 | 277 | ||
| 277 | /* | 278 | /* |
| 278 | * Stop all Rx during the reconfig. We don't want state changes | 279 | * Stop all Rx during the reconfig. We don't want state changes |
| @@ -1187,18 +1188,12 @@ static int __init ieee80211_init(void) | |||
| 1187 | if (ret) | 1188 | if (ret) |
| 1188 | goto err_minstrel; | 1189 | goto err_minstrel; |
| 1189 | 1190 | ||
| 1190 | ret = rc80211_pid_init(); | ||
| 1191 | if (ret) | ||
| 1192 | goto err_pid; | ||
| 1193 | |||
| 1194 | ret = ieee80211_iface_init(); | 1191 | ret = ieee80211_iface_init(); |
| 1195 | if (ret) | 1192 | if (ret) |
| 1196 | goto err_netdev; | 1193 | goto err_netdev; |
| 1197 | 1194 | ||
| 1198 | return 0; | 1195 | return 0; |
| 1199 | err_netdev: | 1196 | err_netdev: |
| 1200 | rc80211_pid_exit(); | ||
| 1201 | err_pid: | ||
| 1202 | rc80211_minstrel_ht_exit(); | 1197 | rc80211_minstrel_ht_exit(); |
| 1203 | err_minstrel: | 1198 | err_minstrel: |
| 1204 | rc80211_minstrel_exit(); | 1199 | rc80211_minstrel_exit(); |
| @@ -1208,7 +1203,6 @@ static int __init ieee80211_init(void) | |||
| 1208 | 1203 | ||
| 1209 | static void __exit ieee80211_exit(void) | 1204 | static void __exit ieee80211_exit(void) |
| 1210 | { | 1205 | { |
| 1211 | rc80211_pid_exit(); | ||
| 1212 | rc80211_minstrel_ht_exit(); | 1206 | rc80211_minstrel_ht_exit(); |
| 1213 | rc80211_minstrel_exit(); | 1207 | rc80211_minstrel_exit(); |
| 1214 | 1208 | ||
diff --git a/net/mac80211/mesh.c b/net/mac80211/mesh.c index 6495a3f0428d..e9f99c1e3fad 100644 --- a/net/mac80211/mesh.c +++ b/net/mac80211/mesh.c | |||
| @@ -679,7 +679,7 @@ ieee80211_mesh_build_beacon(struct ieee80211_if_mesh *ifmsh) | |||
| 679 | *pos++ = 0x0; | 679 | *pos++ = 0x0; |
| 680 | *pos++ = ieee80211_frequency_to_channel( | 680 | *pos++ = ieee80211_frequency_to_channel( |
| 681 | csa->settings.chandef.chan->center_freq); | 681 | csa->settings.chandef.chan->center_freq); |
| 682 | sdata->csa_counter_offset_beacon[0] = hdr_len + 6; | 682 | bcn->csa_counter_offsets[0] = hdr_len + 6; |
| 683 | *pos++ = csa->settings.count; | 683 | *pos++ = csa->settings.count; |
| 684 | *pos++ = WLAN_EID_CHAN_SWITCH_PARAM; | 684 | *pos++ = WLAN_EID_CHAN_SWITCH_PARAM; |
| 685 | *pos++ = 6; | 685 | *pos++ = 6; |
| @@ -1122,7 +1122,7 @@ static int mesh_fwd_csa_frame(struct ieee80211_sub_if_data *sdata, | |||
| 1122 | mgmt_fwd = (struct ieee80211_mgmt *) skb_put(skb, len); | 1122 | mgmt_fwd = (struct ieee80211_mgmt *) skb_put(skb, len); |
| 1123 | 1123 | ||
| 1124 | /* offset_ttl is based on whether the secondary channel | 1124 | /* offset_ttl is based on whether the secondary channel |
| 1125 | * offset is available or not. Substract 1 from the mesh TTL | 1125 | * offset is available or not. Subtract 1 from the mesh TTL |
| 1126 | * and disable the initiator flag before forwarding. | 1126 | * and disable the initiator flag before forwarding. |
| 1127 | */ | 1127 | */ |
| 1128 | offset_ttl = (len < 42) ? 7 : 10; | 1128 | offset_ttl = (len < 42) ? 7 : 10; |
diff --git a/net/mac80211/mesh_hwmp.c b/net/mac80211/mesh_hwmp.c index 94758b9c9ed4..214e63b84e5c 100644 --- a/net/mac80211/mesh_hwmp.c +++ b/net/mac80211/mesh_hwmp.c | |||
| @@ -157,7 +157,6 @@ static int mesh_path_sel_frame_tx(enum mpath_frame_type action, u8 flags, | |||
| 157 | default: | 157 | default: |
| 158 | kfree_skb(skb); | 158 | kfree_skb(skb); |
| 159 | return -ENOTSUPP; | 159 | return -ENOTSUPP; |
| 160 | break; | ||
| 161 | } | 160 | } |
| 162 | *pos++ = ie_len; | 161 | *pos++ = ie_len; |
| 163 | *pos++ = flags; | 162 | *pos++ = flags; |
diff --git a/net/mac80211/mesh_plink.c b/net/mac80211/mesh_plink.c index e8f60aa2e848..63b874101b27 100644 --- a/net/mac80211/mesh_plink.c +++ b/net/mac80211/mesh_plink.c | |||
| @@ -551,11 +551,30 @@ static void mesh_plink_timer(unsigned long data) | |||
| 551 | return; | 551 | return; |
| 552 | 552 | ||
| 553 | spin_lock_bh(&sta->lock); | 553 | spin_lock_bh(&sta->lock); |
| 554 | if (sta->ignore_plink_timer) { | 554 | |
| 555 | sta->ignore_plink_timer = false; | 555 | /* If a timer fires just before a state transition on another CPU, |
| 556 | * we may have already extended the timeout and changed state by the | ||
| 557 | * time we've acquired the lock and arrived here. In that case, | ||
| 558 | * skip this timer and wait for the new one. | ||
| 559 | */ | ||
| 560 | if (time_before(jiffies, sta->plink_timer.expires)) { | ||
| 561 | mpl_dbg(sta->sdata, | ||
| 562 | "Ignoring timer for %pM in state %s (timer adjusted)", | ||
| 563 | sta->sta.addr, mplstates[sta->plink_state]); | ||
| 556 | spin_unlock_bh(&sta->lock); | 564 | spin_unlock_bh(&sta->lock); |
| 557 | return; | 565 | return; |
| 558 | } | 566 | } |
| 567 | |||
| 568 | /* del_timer() and handler may race when entering these states */ | ||
| 569 | if (sta->plink_state == NL80211_PLINK_LISTEN || | ||
| 570 | sta->plink_state == NL80211_PLINK_ESTAB) { | ||
| 571 | mpl_dbg(sta->sdata, | ||
| 572 | "Ignoring timer for %pM in state %s (timer deleted)", | ||
| 573 | sta->sta.addr, mplstates[sta->plink_state]); | ||
| 574 | spin_unlock_bh(&sta->lock); | ||
| 575 | return; | ||
| 576 | } | ||
| 577 | |||
| 559 | mpl_dbg(sta->sdata, | 578 | mpl_dbg(sta->sdata, |
| 560 | "Mesh plink timer for %pM fired on state %s\n", | 579 | "Mesh plink timer for %pM fired on state %s\n", |
| 561 | sta->sta.addr, mplstates[sta->plink_state]); | 580 | sta->sta.addr, mplstates[sta->plink_state]); |
| @@ -773,9 +792,7 @@ static u32 mesh_plink_fsm(struct ieee80211_sub_if_data *sdata, | |||
| 773 | break; | 792 | break; |
| 774 | case CNF_ACPT: | 793 | case CNF_ACPT: |
| 775 | sta->plink_state = NL80211_PLINK_CNF_RCVD; | 794 | sta->plink_state = NL80211_PLINK_CNF_RCVD; |
| 776 | if (!mod_plink_timer(sta, | 795 | mod_plink_timer(sta, mshcfg->dot11MeshConfirmTimeout); |
| 777 | mshcfg->dot11MeshConfirmTimeout)) | ||
| 778 | sta->ignore_plink_timer = true; | ||
| 779 | break; | 796 | break; |
| 780 | default: | 797 | default: |
| 781 | break; | 798 | break; |
| @@ -834,8 +851,7 @@ static u32 mesh_plink_fsm(struct ieee80211_sub_if_data *sdata, | |||
| 834 | case NL80211_PLINK_HOLDING: | 851 | case NL80211_PLINK_HOLDING: |
| 835 | switch (event) { | 852 | switch (event) { |
| 836 | case CLS_ACPT: | 853 | case CLS_ACPT: |
| 837 | if (del_timer(&sta->plink_timer)) | 854 | del_timer(&sta->plink_timer); |
| 838 | sta->ignore_plink_timer = 1; | ||
| 839 | mesh_plink_fsm_restart(sta); | 855 | mesh_plink_fsm_restart(sta); |
| 840 | break; | 856 | break; |
| 841 | case OPN_ACPT: | 857 | case OPN_ACPT: |
diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index 3345401be1b3..31a8afaf7332 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c | |||
| @@ -830,16 +830,7 @@ static void ieee80211_send_assoc(struct ieee80211_sub_if_data *sdata) | |||
| 830 | qos_info = 0; | 830 | qos_info = 0; |
| 831 | } | 831 | } |
| 832 | 832 | ||
| 833 | pos = skb_put(skb, 9); | 833 | pos = ieee80211_add_wmm_info_ie(skb_put(skb, 9), qos_info); |
| 834 | *pos++ = WLAN_EID_VENDOR_SPECIFIC; | ||
| 835 | *pos++ = 7; /* len */ | ||
| 836 | *pos++ = 0x00; /* Microsoft OUI 00:50:F2 */ | ||
| 837 | *pos++ = 0x50; | ||
| 838 | *pos++ = 0xf2; | ||
| 839 | *pos++ = 2; /* WME */ | ||
| 840 | *pos++ = 0; /* WME info */ | ||
| 841 | *pos++ = 1; /* WME ver */ | ||
| 842 | *pos++ = qos_info; | ||
| 843 | } | 834 | } |
| 844 | 835 | ||
| 845 | /* add any remaining custom (i.e. vendor specific here) IEs */ | 836 | /* add any remaining custom (i.e. vendor specific here) IEs */ |
| @@ -940,58 +931,77 @@ static void ieee80211_chswitch_work(struct work_struct *work) | |||
| 940 | container_of(work, struct ieee80211_sub_if_data, u.mgd.chswitch_work); | 931 | container_of(work, struct ieee80211_sub_if_data, u.mgd.chswitch_work); |
| 941 | struct ieee80211_local *local = sdata->local; | 932 | struct ieee80211_local *local = sdata->local; |
| 942 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; | 933 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; |
| 943 | u32 changed = 0; | ||
| 944 | int ret; | 934 | int ret; |
| 945 | 935 | ||
| 946 | if (!ieee80211_sdata_running(sdata)) | 936 | if (!ieee80211_sdata_running(sdata)) |
| 947 | return; | 937 | return; |
| 948 | 938 | ||
| 949 | sdata_lock(sdata); | 939 | sdata_lock(sdata); |
| 940 | mutex_lock(&local->mtx); | ||
| 941 | mutex_lock(&local->chanctx_mtx); | ||
| 942 | |||
| 950 | if (!ifmgd->associated) | 943 | if (!ifmgd->associated) |
| 951 | goto out; | 944 | goto out; |
| 952 | 945 | ||
| 953 | mutex_lock(&local->mtx); | 946 | if (!sdata->vif.csa_active) |
| 954 | ret = ieee80211_vif_change_channel(sdata, &changed); | 947 | goto out; |
| 955 | mutex_unlock(&local->mtx); | 948 | |
| 956 | if (ret) { | 949 | /* |
| 950 | * using reservation isn't immediate as it may be deferred until later | ||
| 951 | * with multi-vif. once reservation is complete it will re-schedule the | ||
| 952 | * work with no reserved_chanctx so verify chandef to check if it | ||
| 953 | * completed successfully | ||
| 954 | */ | ||
| 955 | |||
| 956 | if (sdata->reserved_chanctx) { | ||
| 957 | /* | ||
| 958 | * with multi-vif csa driver may call ieee80211_csa_finish() | ||
| 959 | * many times while waiting for other interfaces to use their | ||
| 960 | * reservations | ||
| 961 | */ | ||
| 962 | if (sdata->reserved_ready) | ||
| 963 | goto out; | ||
| 964 | |||
| 965 | ret = ieee80211_vif_use_reserved_context(sdata); | ||
| 966 | if (ret) { | ||
| 967 | sdata_info(sdata, | ||
| 968 | "failed to use reserved channel context, disconnecting (err=%d)\n", | ||
| 969 | ret); | ||
| 970 | ieee80211_queue_work(&sdata->local->hw, | ||
| 971 | &ifmgd->csa_connection_drop_work); | ||
| 972 | goto out; | ||
| 973 | } | ||
| 974 | |||
| 975 | goto out; | ||
| 976 | } | ||
| 977 | |||
| 978 | if (!cfg80211_chandef_identical(&sdata->vif.bss_conf.chandef, | ||
| 979 | &sdata->csa_chandef)) { | ||
| 957 | sdata_info(sdata, | 980 | sdata_info(sdata, |
| 958 | "vif channel switch failed, disconnecting\n"); | 981 | "failed to finalize channel switch, disconnecting\n"); |
| 959 | ieee80211_queue_work(&sdata->local->hw, | 982 | ieee80211_queue_work(&sdata->local->hw, |
| 960 | &ifmgd->csa_connection_drop_work); | 983 | &ifmgd->csa_connection_drop_work); |
| 961 | goto out; | 984 | goto out; |
| 962 | } | 985 | } |
| 963 | 986 | ||
| 964 | if (!local->use_chanctx) { | ||
| 965 | local->_oper_chandef = sdata->csa_chandef; | ||
| 966 | /* Call "hw_config" only if doing sw channel switch. | ||
| 967 | * Otherwise update the channel directly | ||
| 968 | */ | ||
| 969 | if (!local->ops->channel_switch) | ||
| 970 | ieee80211_hw_config(local, 0); | ||
| 971 | else | ||
| 972 | local->hw.conf.chandef = local->_oper_chandef; | ||
| 973 | } | ||
| 974 | |||
| 975 | /* XXX: shouldn't really modify cfg80211-owned data! */ | 987 | /* XXX: shouldn't really modify cfg80211-owned data! */ |
| 976 | ifmgd->associated->channel = sdata->csa_chandef.chan; | 988 | ifmgd->associated->channel = sdata->csa_chandef.chan; |
| 977 | 989 | ||
| 978 | ieee80211_bss_info_change_notify(sdata, changed); | ||
| 979 | |||
| 980 | mutex_lock(&local->mtx); | ||
| 981 | sdata->vif.csa_active = false; | 990 | sdata->vif.csa_active = false; |
| 982 | /* XXX: wait for a beacon first? */ | ||
| 983 | if (!ieee80211_csa_needs_block_tx(local)) | ||
| 984 | ieee80211_wake_queues_by_reason(&local->hw, | ||
| 985 | IEEE80211_MAX_QUEUE_MAP, | ||
| 986 | IEEE80211_QUEUE_STOP_REASON_CSA); | ||
| 987 | mutex_unlock(&local->mtx); | ||
| 988 | 991 | ||
| 989 | ifmgd->flags &= ~IEEE80211_STA_CSA_RECEIVED; | 992 | /* XXX: wait for a beacon first? */ |
| 993 | if (sdata->csa_block_tx) { | ||
| 994 | ieee80211_wake_vif_queues(local, sdata, | ||
| 995 | IEEE80211_QUEUE_STOP_REASON_CSA); | ||
| 996 | sdata->csa_block_tx = false; | ||
| 997 | } | ||
| 990 | 998 | ||
| 991 | ieee80211_sta_reset_beacon_monitor(sdata); | 999 | ieee80211_sta_reset_beacon_monitor(sdata); |
| 992 | ieee80211_sta_reset_conn_monitor(sdata); | 1000 | ieee80211_sta_reset_conn_monitor(sdata); |
| 993 | 1001 | ||
| 994 | out: | 1002 | out: |
| 1003 | mutex_unlock(&local->chanctx_mtx); | ||
| 1004 | mutex_unlock(&local->mtx); | ||
| 995 | sdata_unlock(sdata); | 1005 | sdata_unlock(sdata); |
| 996 | } | 1006 | } |
| 997 | 1007 | ||
| @@ -1028,6 +1038,7 @@ ieee80211_sta_process_chanswitch(struct ieee80211_sub_if_data *sdata, | |||
| 1028 | struct ieee80211_local *local = sdata->local; | 1038 | struct ieee80211_local *local = sdata->local; |
| 1029 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; | 1039 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; |
| 1030 | struct cfg80211_bss *cbss = ifmgd->associated; | 1040 | struct cfg80211_bss *cbss = ifmgd->associated; |
| 1041 | struct ieee80211_chanctx_conf *conf; | ||
| 1031 | struct ieee80211_chanctx *chanctx; | 1042 | struct ieee80211_chanctx *chanctx; |
| 1032 | enum ieee80211_band current_band; | 1043 | enum ieee80211_band current_band; |
| 1033 | struct ieee80211_csa_ie csa_ie; | 1044 | struct ieee80211_csa_ie csa_ie; |
| @@ -1042,7 +1053,7 @@ ieee80211_sta_process_chanswitch(struct ieee80211_sub_if_data *sdata, | |||
| 1042 | return; | 1053 | return; |
| 1043 | 1054 | ||
| 1044 | /* disregard subsequent announcements if we are already processing */ | 1055 | /* disregard subsequent announcements if we are already processing */ |
| 1045 | if (ifmgd->flags & IEEE80211_STA_CSA_RECEIVED) | 1056 | if (sdata->vif.csa_active) |
| 1046 | return; | 1057 | return; |
| 1047 | 1058 | ||
| 1048 | current_band = cbss->channel->band; | 1059 | current_band = cbss->channel->band; |
| @@ -1069,9 +1080,22 @@ ieee80211_sta_process_chanswitch(struct ieee80211_sub_if_data *sdata, | |||
| 1069 | return; | 1080 | return; |
| 1070 | } | 1081 | } |
| 1071 | 1082 | ||
| 1072 | ifmgd->flags |= IEEE80211_STA_CSA_RECEIVED; | 1083 | mutex_lock(&local->mtx); |
| 1073 | |||
| 1074 | mutex_lock(&local->chanctx_mtx); | 1084 | mutex_lock(&local->chanctx_mtx); |
| 1085 | conf = rcu_dereference_protected(sdata->vif.chanctx_conf, | ||
| 1086 | lockdep_is_held(&local->chanctx_mtx)); | ||
| 1087 | if (!conf) { | ||
| 1088 | sdata_info(sdata, | ||
| 1089 | "no channel context assigned to vif?, disconnecting\n"); | ||
| 1090 | ieee80211_queue_work(&local->hw, | ||
| 1091 | &ifmgd->csa_connection_drop_work); | ||
| 1092 | mutex_unlock(&local->chanctx_mtx); | ||
| 1093 | mutex_unlock(&local->mtx); | ||
| 1094 | return; | ||
| 1095 | } | ||
| 1096 | |||
| 1097 | chanctx = container_of(conf, struct ieee80211_chanctx, conf); | ||
| 1098 | |||
| 1075 | if (local->use_chanctx) { | 1099 | if (local->use_chanctx) { |
| 1076 | u32 num_chanctx = 0; | 1100 | u32 num_chanctx = 0; |
| 1077 | list_for_each_entry(chanctx, &local->chanctx_list, list) | 1101 | list_for_each_entry(chanctx, &local->chanctx_list, list) |
| @@ -1084,38 +1108,32 @@ ieee80211_sta_process_chanswitch(struct ieee80211_sub_if_data *sdata, | |||
| 1084 | ieee80211_queue_work(&local->hw, | 1108 | ieee80211_queue_work(&local->hw, |
| 1085 | &ifmgd->csa_connection_drop_work); | 1109 | &ifmgd->csa_connection_drop_work); |
| 1086 | mutex_unlock(&local->chanctx_mtx); | 1110 | mutex_unlock(&local->chanctx_mtx); |
| 1111 | mutex_unlock(&local->mtx); | ||
| 1087 | return; | 1112 | return; |
| 1088 | } | 1113 | } |
| 1089 | } | 1114 | } |
| 1090 | 1115 | ||
| 1091 | if (WARN_ON(!rcu_access_pointer(sdata->vif.chanctx_conf))) { | 1116 | res = ieee80211_vif_reserve_chanctx(sdata, &csa_ie.chandef, |
| 1092 | ieee80211_queue_work(&local->hw, | 1117 | chanctx->mode, false); |
| 1093 | &ifmgd->csa_connection_drop_work); | 1118 | if (res) { |
| 1094 | mutex_unlock(&local->chanctx_mtx); | ||
| 1095 | return; | ||
| 1096 | } | ||
| 1097 | chanctx = container_of(rcu_access_pointer(sdata->vif.chanctx_conf), | ||
| 1098 | struct ieee80211_chanctx, conf); | ||
| 1099 | if (ieee80211_chanctx_refcount(local, chanctx) > 1) { | ||
| 1100 | sdata_info(sdata, | 1119 | sdata_info(sdata, |
| 1101 | "channel switch with multiple interfaces on the same channel, disconnecting\n"); | 1120 | "failed to reserve channel context for channel switch, disconnecting (err=%d)\n", |
| 1121 | res); | ||
| 1102 | ieee80211_queue_work(&local->hw, | 1122 | ieee80211_queue_work(&local->hw, |
| 1103 | &ifmgd->csa_connection_drop_work); | 1123 | &ifmgd->csa_connection_drop_work); |
| 1104 | mutex_unlock(&local->chanctx_mtx); | 1124 | mutex_unlock(&local->chanctx_mtx); |
| 1125 | mutex_unlock(&local->mtx); | ||
| 1105 | return; | 1126 | return; |
| 1106 | } | 1127 | } |
| 1107 | mutex_unlock(&local->chanctx_mtx); | 1128 | mutex_unlock(&local->chanctx_mtx); |
| 1108 | 1129 | ||
| 1109 | sdata->csa_chandef = csa_ie.chandef; | ||
| 1110 | |||
| 1111 | mutex_lock(&local->mtx); | ||
| 1112 | sdata->vif.csa_active = true; | 1130 | sdata->vif.csa_active = true; |
| 1131 | sdata->csa_chandef = csa_ie.chandef; | ||
| 1113 | sdata->csa_block_tx = csa_ie.mode; | 1132 | sdata->csa_block_tx = csa_ie.mode; |
| 1114 | 1133 | ||
| 1115 | if (sdata->csa_block_tx) | 1134 | if (sdata->csa_block_tx) |
| 1116 | ieee80211_stop_queues_by_reason(&local->hw, | 1135 | ieee80211_stop_vif_queues(local, sdata, |
| 1117 | IEEE80211_MAX_QUEUE_MAP, | 1136 | IEEE80211_QUEUE_STOP_REASON_CSA); |
| 1118 | IEEE80211_QUEUE_STOP_REASON_CSA); | ||
| 1119 | mutex_unlock(&local->mtx); | 1137 | mutex_unlock(&local->mtx); |
| 1120 | 1138 | ||
| 1121 | if (local->ops->channel_switch) { | 1139 | if (local->ops->channel_switch) { |
| @@ -1385,7 +1403,8 @@ void ieee80211_dynamic_ps_disable_work(struct work_struct *work) | |||
| 1385 | 1403 | ||
| 1386 | ieee80211_wake_queues_by_reason(&local->hw, | 1404 | ieee80211_wake_queues_by_reason(&local->hw, |
| 1387 | IEEE80211_MAX_QUEUE_MAP, | 1405 | IEEE80211_MAX_QUEUE_MAP, |
| 1388 | IEEE80211_QUEUE_STOP_REASON_PS); | 1406 | IEEE80211_QUEUE_STOP_REASON_PS, |
| 1407 | false); | ||
| 1389 | } | 1408 | } |
| 1390 | 1409 | ||
| 1391 | void ieee80211_dynamic_ps_enable_work(struct work_struct *work) | 1410 | void ieee80211_dynamic_ps_enable_work(struct work_struct *work) |
| @@ -1830,10 +1849,11 @@ static void ieee80211_set_disassoc(struct ieee80211_sub_if_data *sdata, | |||
| 1830 | ieee80211_vif_release_channel(sdata); | 1849 | ieee80211_vif_release_channel(sdata); |
| 1831 | 1850 | ||
| 1832 | sdata->vif.csa_active = false; | 1851 | sdata->vif.csa_active = false; |
| 1833 | if (!ieee80211_csa_needs_block_tx(local)) | 1852 | if (sdata->csa_block_tx) { |
| 1834 | ieee80211_wake_queues_by_reason(&local->hw, | 1853 | ieee80211_wake_vif_queues(local, sdata, |
| 1835 | IEEE80211_MAX_QUEUE_MAP, | 1854 | IEEE80211_QUEUE_STOP_REASON_CSA); |
| 1836 | IEEE80211_QUEUE_STOP_REASON_CSA); | 1855 | sdata->csa_block_tx = false; |
| 1856 | } | ||
| 1837 | mutex_unlock(&local->mtx); | 1857 | mutex_unlock(&local->mtx); |
| 1838 | 1858 | ||
| 1839 | sdata->encrypt_headroom = IEEE80211_ENCRYPT_HEADROOM; | 1859 | sdata->encrypt_headroom = IEEE80211_ENCRYPT_HEADROOM; |
| @@ -2075,14 +2095,13 @@ static void __ieee80211_disconnect(struct ieee80211_sub_if_data *sdata) | |||
| 2075 | ieee80211_set_disassoc(sdata, IEEE80211_STYPE_DEAUTH, | 2095 | ieee80211_set_disassoc(sdata, IEEE80211_STYPE_DEAUTH, |
| 2076 | WLAN_REASON_DISASSOC_DUE_TO_INACTIVITY, | 2096 | WLAN_REASON_DISASSOC_DUE_TO_INACTIVITY, |
| 2077 | true, frame_buf); | 2097 | true, frame_buf); |
| 2078 | ifmgd->flags &= ~IEEE80211_STA_CSA_RECEIVED; | ||
| 2079 | |||
| 2080 | mutex_lock(&local->mtx); | 2098 | mutex_lock(&local->mtx); |
| 2081 | sdata->vif.csa_active = false; | 2099 | sdata->vif.csa_active = false; |
| 2082 | if (!ieee80211_csa_needs_block_tx(local)) | 2100 | if (sdata->csa_block_tx) { |
| 2083 | ieee80211_wake_queues_by_reason(&local->hw, | 2101 | ieee80211_wake_vif_queues(local, sdata, |
| 2084 | IEEE80211_MAX_QUEUE_MAP, | 2102 | IEEE80211_QUEUE_STOP_REASON_CSA); |
| 2085 | IEEE80211_QUEUE_STOP_REASON_CSA); | 2103 | sdata->csa_block_tx = false; |
| 2104 | } | ||
| 2086 | mutex_unlock(&local->mtx); | 2105 | mutex_unlock(&local->mtx); |
| 2087 | 2106 | ||
| 2088 | cfg80211_tx_mlme_mgmt(sdata->dev, frame_buf, | 2107 | cfg80211_tx_mlme_mgmt(sdata->dev, frame_buf, |
| @@ -3688,6 +3707,8 @@ void ieee80211_sta_setup_sdata(struct ieee80211_sub_if_data *sdata) | |||
| 3688 | INIT_WORK(&ifmgd->csa_connection_drop_work, | 3707 | INIT_WORK(&ifmgd->csa_connection_drop_work, |
| 3689 | ieee80211_csa_connection_drop_work); | 3708 | ieee80211_csa_connection_drop_work); |
| 3690 | INIT_WORK(&ifmgd->request_smps_work, ieee80211_request_smps_mgd_work); | 3709 | INIT_WORK(&ifmgd->request_smps_work, ieee80211_request_smps_mgd_work); |
| 3710 | INIT_DELAYED_WORK(&ifmgd->tdls_peer_del_work, | ||
| 3711 | ieee80211_tdls_peer_del_work); | ||
| 3691 | setup_timer(&ifmgd->timer, ieee80211_sta_timer, | 3712 | setup_timer(&ifmgd->timer, ieee80211_sta_timer, |
| 3692 | (unsigned long) sdata); | 3713 | (unsigned long) sdata); |
| 3693 | setup_timer(&ifmgd->bcn_mon_timer, ieee80211_sta_bcn_mon_timer, | 3714 | setup_timer(&ifmgd->bcn_mon_timer, ieee80211_sta_bcn_mon_timer, |
| @@ -4551,6 +4572,7 @@ void ieee80211_mgd_stop(struct ieee80211_sub_if_data *sdata) | |||
| 4551 | cancel_work_sync(&ifmgd->request_smps_work); | 4572 | cancel_work_sync(&ifmgd->request_smps_work); |
| 4552 | cancel_work_sync(&ifmgd->csa_connection_drop_work); | 4573 | cancel_work_sync(&ifmgd->csa_connection_drop_work); |
| 4553 | cancel_work_sync(&ifmgd->chswitch_work); | 4574 | cancel_work_sync(&ifmgd->chswitch_work); |
| 4575 | cancel_delayed_work_sync(&ifmgd->tdls_peer_del_work); | ||
| 4554 | 4576 | ||
| 4555 | sdata_lock(sdata); | 4577 | sdata_lock(sdata); |
| 4556 | if (ifmgd->assoc_data) { | 4578 | if (ifmgd->assoc_data) { |
diff --git a/net/mac80211/offchannel.c b/net/mac80211/offchannel.c index 7a17decd27f9..ff20b2ebdb30 100644 --- a/net/mac80211/offchannel.c +++ b/net/mac80211/offchannel.c | |||
| @@ -119,7 +119,8 @@ void ieee80211_offchannel_stop_vifs(struct ieee80211_local *local) | |||
| 119 | * before sending nullfunc to enable powersave at the AP. | 119 | * before sending nullfunc to enable powersave at the AP. |
| 120 | */ | 120 | */ |
| 121 | ieee80211_stop_queues_by_reason(&local->hw, IEEE80211_MAX_QUEUE_MAP, | 121 | ieee80211_stop_queues_by_reason(&local->hw, IEEE80211_MAX_QUEUE_MAP, |
| 122 | IEEE80211_QUEUE_STOP_REASON_OFFCHANNEL); | 122 | IEEE80211_QUEUE_STOP_REASON_OFFCHANNEL, |
| 123 | false); | ||
| 123 | ieee80211_flush_queues(local, NULL); | 124 | ieee80211_flush_queues(local, NULL); |
| 124 | 125 | ||
| 125 | mutex_lock(&local->iflist_mtx); | 126 | mutex_lock(&local->iflist_mtx); |
| @@ -182,7 +183,8 @@ void ieee80211_offchannel_return(struct ieee80211_local *local) | |||
| 182 | mutex_unlock(&local->iflist_mtx); | 183 | mutex_unlock(&local->iflist_mtx); |
| 183 | 184 | ||
| 184 | ieee80211_wake_queues_by_reason(&local->hw, IEEE80211_MAX_QUEUE_MAP, | 185 | ieee80211_wake_queues_by_reason(&local->hw, IEEE80211_MAX_QUEUE_MAP, |
| 185 | IEEE80211_QUEUE_STOP_REASON_OFFCHANNEL); | 186 | IEEE80211_QUEUE_STOP_REASON_OFFCHANNEL, |
| 187 | false); | ||
| 186 | } | 188 | } |
| 187 | 189 | ||
| 188 | void ieee80211_handle_roc_started(struct ieee80211_roc_work *roc) | 190 | void ieee80211_handle_roc_started(struct ieee80211_roc_work *roc) |
diff --git a/net/mac80211/pm.c b/net/mac80211/pm.c index d478b880a0af..4c5192e0d66c 100644 --- a/net/mac80211/pm.c +++ b/net/mac80211/pm.c | |||
| @@ -35,7 +35,8 @@ int __ieee80211_suspend(struct ieee80211_hw *hw, struct cfg80211_wowlan *wowlan) | |||
| 35 | 35 | ||
| 36 | ieee80211_stop_queues_by_reason(hw, | 36 | ieee80211_stop_queues_by_reason(hw, |
| 37 | IEEE80211_MAX_QUEUE_MAP, | 37 | IEEE80211_MAX_QUEUE_MAP, |
| 38 | IEEE80211_QUEUE_STOP_REASON_SUSPEND); | 38 | IEEE80211_QUEUE_STOP_REASON_SUSPEND, |
| 39 | false); | ||
| 39 | 40 | ||
| 40 | /* flush out all packets */ | 41 | /* flush out all packets */ |
| 41 | synchronize_net(); | 42 | synchronize_net(); |
| @@ -74,7 +75,8 @@ int __ieee80211_suspend(struct ieee80211_hw *hw, struct cfg80211_wowlan *wowlan) | |||
| 74 | } | 75 | } |
| 75 | ieee80211_wake_queues_by_reason(hw, | 76 | ieee80211_wake_queues_by_reason(hw, |
| 76 | IEEE80211_MAX_QUEUE_MAP, | 77 | IEEE80211_MAX_QUEUE_MAP, |
| 77 | IEEE80211_QUEUE_STOP_REASON_SUSPEND); | 78 | IEEE80211_QUEUE_STOP_REASON_SUSPEND, |
| 79 | false); | ||
| 78 | return err; | 80 | return err; |
| 79 | } else if (err > 0) { | 81 | } else if (err > 0) { |
| 80 | WARN_ON(err != 1); | 82 | WARN_ON(err != 1); |
diff --git a/net/mac80211/rate.h b/net/mac80211/rate.h index 9aa2a1190a86..18babe302832 100644 --- a/net/mac80211/rate.h +++ b/net/mac80211/rate.h | |||
| @@ -143,19 +143,6 @@ void rate_control_deinitialize(struct ieee80211_local *local); | |||
| 143 | 143 | ||
| 144 | 144 | ||
| 145 | /* Rate control algorithms */ | 145 | /* Rate control algorithms */ |
| 146 | #ifdef CONFIG_MAC80211_RC_PID | ||
| 147 | int rc80211_pid_init(void); | ||
| 148 | void rc80211_pid_exit(void); | ||
| 149 | #else | ||
| 150 | static inline int rc80211_pid_init(void) | ||
| 151 | { | ||
| 152 | return 0; | ||
| 153 | } | ||
| 154 | static inline void rc80211_pid_exit(void) | ||
| 155 | { | ||
| 156 | } | ||
| 157 | #endif | ||
| 158 | |||
| 159 | #ifdef CONFIG_MAC80211_RC_MINSTREL | 146 | #ifdef CONFIG_MAC80211_RC_MINSTREL |
| 160 | int rc80211_minstrel_init(void); | 147 | int rc80211_minstrel_init(void); |
| 161 | void rc80211_minstrel_exit(void); | 148 | void rc80211_minstrel_exit(void); |
diff --git a/net/mac80211/rc80211_pid.h b/net/mac80211/rc80211_pid.h deleted file mode 100644 index 19111c7bf454..000000000000 --- a/net/mac80211/rc80211_pid.h +++ /dev/null | |||
| @@ -1,278 +0,0 @@ | |||
| 1 | /* | ||
| 2 | * Copyright 2007, Mattias Nissler <mattias.nissler@gmx.de> | ||
| 3 | * Copyright 2007, Stefano Brivio <stefano.brivio@polimi.it> | ||
| 4 | * | ||
| 5 | * This program is free software; you can redistribute it and/or modify | ||
| 6 | * it under the terms of the GNU General Public License version 2 as | ||
| 7 | * published by the Free Software Foundation. | ||
| 8 | */ | ||
| 9 | |||
| 10 | #ifndef RC80211_PID_H | ||
| 11 | #define RC80211_PID_H | ||
| 12 | |||
| 13 | /* Sampling period for measuring percentage of failed frames in ms. */ | ||
| 14 | #define RC_PID_INTERVAL 125 | ||
| 15 | |||
| 16 | /* Exponential averaging smoothness (used for I part of PID controller) */ | ||
| 17 | #define RC_PID_SMOOTHING_SHIFT 3 | ||
| 18 | #define RC_PID_SMOOTHING (1 << RC_PID_SMOOTHING_SHIFT) | ||
| 19 | |||
| 20 | /* Sharpening factor (used for D part of PID controller) */ | ||
| 21 | #define RC_PID_SHARPENING_FACTOR 0 | ||
| 22 | #define RC_PID_SHARPENING_DURATION 0 | ||
| 23 | |||
| 24 | /* Fixed point arithmetic shifting amount. */ | ||
| 25 | #define RC_PID_ARITH_SHIFT 8 | ||
| 26 | |||
| 27 | /* Proportional PID component coefficient. */ | ||
| 28 | #define RC_PID_COEFF_P 15 | ||
| 29 | /* Integral PID component coefficient. */ | ||
| 30 | #define RC_PID_COEFF_I 9 | ||
| 31 | /* Derivative PID component coefficient. */ | ||
| 32 | #define RC_PID_COEFF_D 15 | ||
| 33 | |||
| 34 | /* Target failed frames rate for the PID controller. NB: This effectively gives | ||
| 35 | * maximum failed frames percentage we're willing to accept. If the wireless | ||
| 36 | * link quality is good, the controller will fail to adjust failed frames | ||
| 37 | * percentage to the target. This is intentional. | ||
| 38 | */ | ||
| 39 | #define RC_PID_TARGET_PF 14 | ||
| 40 | |||
| 41 | /* Rate behaviour normalization quantity over time. */ | ||
| 42 | #define RC_PID_NORM_OFFSET 3 | ||
| 43 | |||
| 44 | /* Push high rates right after loading. */ | ||
| 45 | #define RC_PID_FAST_START 0 | ||
| 46 | |||
| 47 | /* Arithmetic right shift for positive and negative values for ISO C. */ | ||
| 48 | #define RC_PID_DO_ARITH_RIGHT_SHIFT(x, y) \ | ||
| 49 | ((x) < 0 ? -((-(x)) >> (y)) : (x) >> (y)) | ||
| 50 | |||
| 51 | enum rc_pid_event_type { | ||
| 52 | RC_PID_EVENT_TYPE_TX_STATUS, | ||
| 53 | RC_PID_EVENT_TYPE_RATE_CHANGE, | ||
| 54 | RC_PID_EVENT_TYPE_TX_RATE, | ||
| 55 | RC_PID_EVENT_TYPE_PF_SAMPLE, | ||
| 56 | }; | ||
| 57 | |||
| 58 | union rc_pid_event_data { | ||
| 59 | /* RC_PID_EVENT_TX_STATUS */ | ||
| 60 | struct { | ||
| 61 | u32 flags; | ||
| 62 | struct ieee80211_tx_info tx_status; | ||
| 63 | }; | ||
| 64 | /* RC_PID_EVENT_TYPE_RATE_CHANGE */ | ||
| 65 | /* RC_PID_EVENT_TYPE_TX_RATE */ | ||
| 66 | struct { | ||
| 67 | int index; | ||
| 68 | int rate; | ||
| 69 | }; | ||
| 70 | /* RC_PID_EVENT_TYPE_PF_SAMPLE */ | ||
| 71 | struct { | ||
| 72 | s32 pf_sample; | ||
| 73 | s32 prop_err; | ||
| 74 | s32 int_err; | ||
| 75 | s32 der_err; | ||
| 76 | }; | ||
| 77 | }; | ||
| 78 | |||
| 79 | struct rc_pid_event { | ||
| 80 | /* The time when the event occurred */ | ||
| 81 | unsigned long timestamp; | ||
| 82 | |||
| 83 | /* Event ID number */ | ||
| 84 | unsigned int id; | ||
| 85 | |||
| 86 | /* Type of event */ | ||
| 87 | enum rc_pid_event_type type; | ||
| 88 | |||
| 89 | /* type specific data */ | ||
| 90 | union rc_pid_event_data data; | ||
| 91 | }; | ||
| 92 | |||
| 93 | /* Size of the event ring buffer. */ | ||
| 94 | #define RC_PID_EVENT_RING_SIZE 32 | ||
| 95 | |||
| 96 | struct rc_pid_event_buffer { | ||
| 97 | /* Counter that generates event IDs */ | ||
| 98 | unsigned int ev_count; | ||
| 99 | |||
| 100 | /* Ring buffer of events */ | ||
| 101 | struct rc_pid_event ring[RC_PID_EVENT_RING_SIZE]; | ||
| 102 | |||
| 103 | /* Index to the entry in events_buf to be reused */ | ||
| 104 | unsigned int next_entry; | ||
| 105 | |||
| 106 | /* Lock that guards against concurrent access to this buffer struct */ | ||
| 107 | spinlock_t lock; | ||
| 108 | |||
| 109 | /* Wait queue for poll/select and blocking I/O */ | ||
| 110 | wait_queue_head_t waitqueue; | ||
| 111 | }; | ||
| 112 | |||
| 113 | struct rc_pid_events_file_info { | ||
| 114 | /* The event buffer we read */ | ||
| 115 | struct rc_pid_event_buffer *events; | ||
| 116 | |||
| 117 | /* The entry we have should read next */ | ||
| 118 | unsigned int next_entry; | ||
| 119 | }; | ||
| 120 | |||
| 121 | /** | ||
| 122 | * struct rc_pid_debugfs_entries - tunable parameters | ||
| 123 | * | ||
| 124 | * Algorithm parameters, tunable via debugfs. | ||
| 125 | * @target: target percentage for failed frames | ||
| 126 | * @sampling_period: error sampling interval in milliseconds | ||
| 127 | * @coeff_p: absolute value of the proportional coefficient | ||
| 128 | * @coeff_i: absolute value of the integral coefficient | ||
| 129 | * @coeff_d: absolute value of the derivative coefficient | ||
| 130 | * @smoothing_shift: absolute value of the integral smoothing factor (i.e. | ||
| 131 | * amount of smoothing introduced by the exponential moving average) | ||
| 132 | * @sharpen_factor: absolute value of the derivative sharpening factor (i.e. | ||
| 133 | * amount of emphasis given to the derivative term after low activity | ||
| 134 | * events) | ||
| 135 | * @sharpen_duration: duration of the sharpening effect after the detected low | ||
| 136 | * activity event, relative to sampling_period | ||
| 137 | * @norm_offset: amount of normalization periodically performed on the learnt | ||
| 138 | * rate behaviour values (lower means we should trust more what we learnt | ||
| 139 | * about behaviour of rates, higher means we should trust more the natural | ||
| 140 | * ordering of rates) | ||
| 141 | */ | ||
| 142 | struct rc_pid_debugfs_entries { | ||
| 143 | struct dentry *target; | ||
| 144 | struct dentry *sampling_period; | ||
| 145 | struct dentry *coeff_p; | ||
| 146 | struct dentry *coeff_i; | ||
| 147 | struct dentry *coeff_d; | ||
| 148 | struct dentry *smoothing_shift; | ||
| 149 | struct dentry *sharpen_factor; | ||
| 150 | struct dentry *sharpen_duration; | ||
| 151 | struct dentry *norm_offset; | ||
| 152 | }; | ||
| 153 | |||
| 154 | void rate_control_pid_event_tx_status(struct rc_pid_event_buffer *buf, | ||
| 155 | struct ieee80211_tx_info *stat); | ||
| 156 | |||
| 157 | void rate_control_pid_event_rate_change(struct rc_pid_event_buffer *buf, | ||
| 158 | int index, int rate); | ||
| 159 | |||
| 160 | void rate_control_pid_event_tx_rate(struct rc_pid_event_buffer *buf, | ||
| 161 | int index, int rate); | ||
| 162 | |||
| 163 | void rate_control_pid_event_pf_sample(struct rc_pid_event_buffer *buf, | ||
| 164 | s32 pf_sample, s32 prop_err, | ||
| 165 | s32 int_err, s32 der_err); | ||
| 166 | |||
| 167 | void rate_control_pid_add_sta_debugfs(void *priv, void *priv_sta, | ||
| 168 | struct dentry *dir); | ||
| 169 | |||
| 170 | void rate_control_pid_remove_sta_debugfs(void *priv, void *priv_sta); | ||
| 171 | |||
| 172 | struct rc_pid_sta_info { | ||
| 173 | unsigned long last_change; | ||
| 174 | unsigned long last_sample; | ||
| 175 | |||
| 176 | u32 tx_num_failed; | ||
| 177 | u32 tx_num_xmit; | ||
| 178 | |||
| 179 | int txrate_idx; | ||
| 180 | |||
| 181 | /* Average failed frames percentage error (i.e. actual vs. target | ||
| 182 | * percentage), scaled by RC_PID_SMOOTHING. This value is computed | ||
| 183 | * using using an exponential weighted average technique: | ||
| 184 | * | ||
| 185 | * (RC_PID_SMOOTHING - 1) * err_avg_old + err | ||
| 186 | * err_avg = ------------------------------------------ | ||
| 187 | * RC_PID_SMOOTHING | ||
| 188 | * | ||
| 189 | * where err_avg is the new approximation, err_avg_old the previous one | ||
| 190 | * and err is the error w.r.t. to the current failed frames percentage | ||
| 191 | * sample. Note that the bigger RC_PID_SMOOTHING the more weight is | ||
| 192 | * given to the previous estimate, resulting in smoother behavior (i.e. | ||
| 193 | * corresponding to a longer integration window). | ||
| 194 | * | ||
| 195 | * For computation, we actually don't use the above formula, but this | ||
| 196 | * one: | ||
| 197 | * | ||
| 198 | * err_avg_scaled = err_avg_old_scaled - err_avg_old + err | ||
| 199 | * | ||
| 200 | * where: | ||
| 201 | * err_avg_scaled = err * RC_PID_SMOOTHING | ||
| 202 | * err_avg_old_scaled = err_avg_old * RC_PID_SMOOTHING | ||
| 203 | * | ||
| 204 | * This avoids floating point numbers and the per_failed_old value can | ||
| 205 | * easily be obtained by shifting per_failed_old_scaled right by | ||
| 206 | * RC_PID_SMOOTHING_SHIFT. | ||
| 207 | */ | ||
| 208 | s32 err_avg_sc; | ||
| 209 | |||
| 210 | /* Last framed failes percentage sample. */ | ||
| 211 | u32 last_pf; | ||
| 212 | |||
| 213 | /* Sharpening needed. */ | ||
| 214 | u8 sharp_cnt; | ||
| 215 | |||
| 216 | #ifdef CONFIG_MAC80211_DEBUGFS | ||
| 217 | /* Event buffer */ | ||
| 218 | struct rc_pid_event_buffer events; | ||
| 219 | |||
| 220 | /* Events debugfs file entry */ | ||
| 221 | struct dentry *events_entry; | ||
| 222 | #endif | ||
| 223 | }; | ||
| 224 | |||
| 225 | /* Algorithm parameters. We keep them on a per-algorithm approach, so they can | ||
| 226 | * be tuned individually for each interface. | ||
| 227 | */ | ||
| 228 | struct rc_pid_rateinfo { | ||
| 229 | |||
| 230 | /* Map sorted rates to rates in ieee80211_hw_mode. */ | ||
| 231 | int index; | ||
| 232 | |||
| 233 | /* Map rates in ieee80211_hw_mode to sorted rates. */ | ||
| 234 | int rev_index; | ||
| 235 | |||
| 236 | /* Did we do any measurement on this rate? */ | ||
| 237 | bool valid; | ||
| 238 | |||
| 239 | /* Comparison with the lowest rate. */ | ||
| 240 | int diff; | ||
| 241 | }; | ||
| 242 | |||
| 243 | struct rc_pid_info { | ||
| 244 | |||
| 245 | /* The failed frames percentage target. */ | ||
| 246 | unsigned int target; | ||
| 247 | |||
| 248 | /* Rate at which failed frames percentage is sampled in 0.001s. */ | ||
| 249 | unsigned int sampling_period; | ||
| 250 | |||
| 251 | /* P, I and D coefficients. */ | ||
| 252 | int coeff_p; | ||
| 253 | int coeff_i; | ||
| 254 | int coeff_d; | ||
| 255 | |||
| 256 | /* Exponential averaging shift. */ | ||
| 257 | unsigned int smoothing_shift; | ||
| 258 | |||
| 259 | /* Sharpening factor and duration. */ | ||
| 260 | unsigned int sharpen_factor; | ||
| 261 | unsigned int sharpen_duration; | ||
| 262 | |||
| 263 | /* Normalization offset. */ | ||
| 264 | unsigned int norm_offset; | ||
| 265 | |||
| 266 | /* Rates information. */ | ||
| 267 | struct rc_pid_rateinfo *rinfo; | ||
| 268 | |||
| 269 | /* Index of the last used rate. */ | ||
| 270 | int oldrate; | ||
| 271 | |||
| 272 | #ifdef CONFIG_MAC80211_DEBUGFS | ||
| 273 | /* Debugfs entries created for the parameters above. */ | ||
| 274 | struct rc_pid_debugfs_entries dentries; | ||
| 275 | #endif | ||
| 276 | }; | ||
| 277 | |||
| 278 | #endif /* RC80211_PID_H */ | ||
diff --git a/net/mac80211/rc80211_pid_algo.c b/net/mac80211/rc80211_pid_algo.c deleted file mode 100644 index d0da2a70fe68..000000000000 --- a/net/mac80211/rc80211_pid_algo.c +++ /dev/null | |||
| @@ -1,478 +0,0 @@ | |||
| 1 | /* | ||
| 2 | * Copyright 2002-2005, Instant802 Networks, Inc. | ||
| 3 | * Copyright 2005, Devicescape Software, Inc. | ||
| 4 | * Copyright 2007, Mattias Nissler <mattias.nissler@gmx.de> | ||
| 5 | * Copyright 2007-2008, Stefano Brivio <stefano.brivio@polimi.it> | ||
| 6 | * | ||
| 7 | * This program is free software; you can redistribute it and/or modify | ||
| 8 | * it under the terms of the GNU General Public License version 2 as | ||
| 9 | * published by the Free Software Foundation. | ||
| 10 | */ | ||
| 11 | |||
| 12 | #include <linux/netdevice.h> | ||
| 13 | #include <linux/types.h> | ||
| 14 | #include <linux/skbuff.h> | ||
| 15 | #include <linux/debugfs.h> | ||
| 16 | #include <linux/slab.h> | ||
| 17 | #include <net/mac80211.h> | ||
| 18 | #include "rate.h" | ||
| 19 | #include "mesh.h" | ||
| 20 | #include "rc80211_pid.h" | ||
| 21 | |||
| 22 | |||
| 23 | /* This is an implementation of a TX rate control algorithm that uses a PID | ||
| 24 | * controller. Given a target failed frames rate, the controller decides about | ||
| 25 | * TX rate changes to meet the target failed frames rate. | ||
| 26 | * | ||
| 27 | * The controller basically computes the following: | ||
| 28 | * | ||
| 29 | * adj = CP * err + CI * err_avg + CD * (err - last_err) * (1 + sharpening) | ||
| 30 | * | ||
| 31 | * where | ||
| 32 | * adj adjustment value that is used to switch TX rate (see below) | ||
| 33 | * err current error: target vs. current failed frames percentage | ||
| 34 | * last_err last error | ||
| 35 | * err_avg average (i.e. poor man's integral) of recent errors | ||
| 36 | * sharpening non-zero when fast response is needed (i.e. right after | ||
| 37 | * association or no frames sent for a long time), heading | ||
| 38 | * to zero over time | ||
| 39 | * CP Proportional coefficient | ||
| 40 | * CI Integral coefficient | ||
| 41 | * CD Derivative coefficient | ||
| 42 | * | ||
| 43 | * CP, CI, CD are subject to careful tuning. | ||
| 44 | * | ||
| 45 | * The integral component uses a exponential moving average approach instead of | ||
| 46 | * an actual sliding window. The advantage is that we don't need to keep an | ||
| 47 | * array of the last N error values and computation is easier. | ||
| 48 | * | ||
| 49 | * Once we have the adj value, we map it to a rate by means of a learning | ||
| 50 | * algorithm. This algorithm keeps the state of the percentual failed frames | ||
| 51 | * difference between rates. The behaviour of the lowest available rate is kept | ||
| 52 | * as a reference value, and every time we switch between two rates, we compute | ||
| 53 | * the difference between the failed frames each rate exhibited. By doing so, | ||
| 54 | * we compare behaviours which different rates exhibited in adjacent timeslices, | ||
| 55 | * thus the comparison is minimally affected by external conditions. This | ||
| 56 | * difference gets propagated to the whole set of measurements, so that the | ||
| 57 | * reference is always the same. Periodically, we normalize this set so that | ||
| 58 | * recent events weigh the most. By comparing the adj value with this set, we | ||
| 59 | * avoid pejorative switches to lower rates and allow for switches to higher | ||
| 60 | * rates if they behaved well. | ||
| 61 | * | ||
| 62 | * Note that for the computations we use a fixed-point representation to avoid | ||
| 63 | * floating point arithmetic. Hence, all values are shifted left by | ||
| 64 | * RC_PID_ARITH_SHIFT. | ||
| 65 | */ | ||
| 66 | |||
| 67 | |||
| 68 | /* Adjust the rate while ensuring that we won't switch to a lower rate if it | ||
| 69 | * exhibited a worse failed frames behaviour and we'll choose the highest rate | ||
| 70 | * whose failed frames behaviour is not worse than the one of the original rate | ||
| 71 | * target. While at it, check that the new rate is valid. */ | ||
| 72 | static void rate_control_pid_adjust_rate(struct ieee80211_supported_band *sband, | ||
| 73 | struct ieee80211_sta *sta, | ||
| 74 | struct rc_pid_sta_info *spinfo, int adj, | ||
| 75 | struct rc_pid_rateinfo *rinfo) | ||
| 76 | { | ||
| 77 | int cur_sorted, new_sorted, probe, tmp, n_bitrates, band; | ||
| 78 | int cur = spinfo->txrate_idx; | ||
| 79 | |||
| 80 | band = sband->band; | ||
| 81 | n_bitrates = sband->n_bitrates; | ||
| 82 | |||
| 83 | /* Map passed arguments to sorted values. */ | ||
| 84 | cur_sorted = rinfo[cur].rev_index; | ||
| 85 | new_sorted = cur_sorted + adj; | ||
| 86 | |||
| 87 | /* Check limits. */ | ||
| 88 | if (new_sorted < 0) | ||
| 89 | new_sorted = rinfo[0].rev_index; | ||
| 90 | else if (new_sorted >= n_bitrates) | ||
| 91 | new_sorted = rinfo[n_bitrates - 1].rev_index; | ||
| 92 | |||
| 93 | tmp = new_sorted; | ||
| 94 | |||
| 95 | if (adj < 0) { | ||
| 96 | /* Ensure that the rate decrease isn't disadvantageous. */ | ||
| 97 | for (probe = cur_sorted; probe >= new_sorted; probe--) | ||
| 98 | if (rinfo[probe].diff <= rinfo[cur_sorted].diff && | ||
| 99 | rate_supported(sta, band, rinfo[probe].index)) | ||
| 100 | tmp = probe; | ||
| 101 | } else { | ||
| 102 | /* Look for rate increase with zero (or below) cost. */ | ||
| 103 | for (probe = new_sorted + 1; probe < n_bitrates; probe++) | ||
| 104 | if (rinfo[probe].diff <= rinfo[new_sorted].diff && | ||
| 105 | rate_supported(sta, band, rinfo[probe].index)) | ||
| 106 | tmp = probe; | ||
| 107 | } | ||
| 108 | |||
| 109 | /* Fit the rate found to the nearest supported rate. */ | ||
| 110 | do { | ||
| 111 | if (rate_supported(sta, band, rinfo[tmp].index)) { | ||
| 112 | spinfo->txrate_idx = rinfo[tmp].index; | ||
| 113 | break; | ||
| 114 | } | ||
| 115 | if (adj < 0) | ||
| 116 | tmp--; | ||
| 117 | else | ||
| 118 | tmp++; | ||
| 119 | } while (tmp < n_bitrates && tmp >= 0); | ||
| 120 | |||
| 121 | #ifdef CONFIG_MAC80211_DEBUGFS | ||
| 122 | rate_control_pid_event_rate_change(&spinfo->events, | ||
| 123 | spinfo->txrate_idx, | ||
| 124 | sband->bitrates[spinfo->txrate_idx].bitrate); | ||
| 125 | #endif | ||
| 126 | } | ||
| 127 | |||
| 128 | /* Normalize the failed frames per-rate differences. */ | ||
| 129 | static void rate_control_pid_normalize(struct rc_pid_info *pinfo, int l) | ||
| 130 | { | ||
| 131 | int i, norm_offset = pinfo->norm_offset; | ||
| 132 | struct rc_pid_rateinfo *r = pinfo->rinfo; | ||
| 133 | |||
| 134 | if (r[0].diff > norm_offset) | ||
| 135 | r[0].diff -= norm_offset; | ||
| 136 | else if (r[0].diff < -norm_offset) | ||
| 137 | r[0].diff += norm_offset; | ||
| 138 | for (i = 0; i < l - 1; i++) | ||
| 139 | if (r[i + 1].diff > r[i].diff + norm_offset) | ||
| 140 | r[i + 1].diff -= norm_offset; | ||
| 141 | else if (r[i + 1].diff <= r[i].diff) | ||
| 142 | r[i + 1].diff += norm_offset; | ||
| 143 | } | ||
| 144 | |||
| 145 | static void rate_control_pid_sample(struct rc_pid_info *pinfo, | ||
| 146 | struct ieee80211_supported_band *sband, | ||
| 147 | struct ieee80211_sta *sta, | ||
| 148 | struct rc_pid_sta_info *spinfo) | ||
| 149 | { | ||
| 150 | struct rc_pid_rateinfo *rinfo = pinfo->rinfo; | ||
| 151 | u32 pf; | ||
| 152 | s32 err_avg; | ||
| 153 | u32 err_prop; | ||
| 154 | u32 err_int; | ||
| 155 | u32 err_der; | ||
| 156 | int adj, i, j, tmp; | ||
| 157 | unsigned long period; | ||
| 158 | |||
| 159 | /* In case nothing happened during the previous control interval, turn | ||
| 160 | * the sharpening factor on. */ | ||
| 161 | period = msecs_to_jiffies(pinfo->sampling_period); | ||
| 162 | if (jiffies - spinfo->last_sample > 2 * period) | ||
| 163 | spinfo->sharp_cnt = pinfo->sharpen_duration; | ||
| 164 | |||
| 165 | spinfo->last_sample = jiffies; | ||
| 166 | |||
| 167 | /* This should never happen, but in case, we assume the old sample is | ||
| 168 | * still a good measurement and copy it. */ | ||
| 169 | if (unlikely(spinfo->tx_num_xmit == 0)) | ||
| 170 | pf = spinfo->last_pf; | ||
| 171 | else | ||
| 172 | pf = spinfo->tx_num_failed * 100 / spinfo->tx_num_xmit; | ||
| 173 | |||
| 174 | spinfo->tx_num_xmit = 0; | ||
| 175 | spinfo->tx_num_failed = 0; | ||
| 176 | |||
| 177 | /* If we just switched rate, update the rate behaviour info. */ | ||
| 178 | if (pinfo->oldrate != spinfo->txrate_idx) { | ||
| 179 | |||
| 180 | i = rinfo[pinfo->oldrate].rev_index; | ||
| 181 | j = rinfo[spinfo->txrate_idx].rev_index; | ||
| 182 | |||
| 183 | tmp = (pf - spinfo->last_pf); | ||
| 184 | tmp = RC_PID_DO_ARITH_RIGHT_SHIFT(tmp, RC_PID_ARITH_SHIFT); | ||
| 185 | |||
| 186 | rinfo[j].diff = rinfo[i].diff + tmp; | ||
| 187 | pinfo->oldrate = spinfo->txrate_idx; | ||
| 188 | } | ||
| 189 | rate_control_pid_normalize(pinfo, sband->n_bitrates); | ||
| 190 | |||
| 191 | /* Compute the proportional, integral and derivative errors. */ | ||
| 192 | err_prop = (pinfo->target - pf) << RC_PID_ARITH_SHIFT; | ||
| 193 | |||
| 194 | err_avg = spinfo->err_avg_sc >> pinfo->smoothing_shift; | ||
| 195 | spinfo->err_avg_sc = spinfo->err_avg_sc - err_avg + err_prop; | ||
| 196 | err_int = spinfo->err_avg_sc >> pinfo->smoothing_shift; | ||
| 197 | |||
| 198 | err_der = (pf - spinfo->last_pf) * | ||
| 199 | (1 + pinfo->sharpen_factor * spinfo->sharp_cnt); | ||
| 200 | spinfo->last_pf = pf; | ||
| 201 | if (spinfo->sharp_cnt) | ||
| 202 | spinfo->sharp_cnt--; | ||
| 203 | |||
| 204 | #ifdef CONFIG_MAC80211_DEBUGFS | ||
| 205 | rate_control_pid_event_pf_sample(&spinfo->events, pf, err_prop, err_int, | ||
| 206 | err_der); | ||
| 207 | #endif | ||
| 208 | |||
| 209 | /* Compute the controller output. */ | ||
| 210 | adj = (err_prop * pinfo->coeff_p + err_int * pinfo->coeff_i | ||
| 211 | + err_der * pinfo->coeff_d); | ||
| 212 | adj = RC_PID_DO_ARITH_RIGHT_SHIFT(adj, 2 * RC_PID_ARITH_SHIFT); | ||
| 213 | |||
| 214 | /* Change rate. */ | ||
| 215 | if (adj) | ||
| 216 | rate_control_pid_adjust_rate(sband, sta, spinfo, adj, rinfo); | ||
| 217 | } | ||
| 218 | |||
| 219 | static void rate_control_pid_tx_status(void *priv, struct ieee80211_supported_band *sband, | ||
| 220 | struct ieee80211_sta *sta, void *priv_sta, | ||
| 221 | struct sk_buff *skb) | ||
| 222 | { | ||
| 223 | struct rc_pid_info *pinfo = priv; | ||
| 224 | struct rc_pid_sta_info *spinfo = priv_sta; | ||
| 225 | unsigned long period; | ||
| 226 | struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); | ||
| 227 | |||
| 228 | if (!spinfo) | ||
| 229 | return; | ||
| 230 | |||
| 231 | /* Ignore all frames that were sent with a different rate than the rate | ||
| 232 | * we currently advise mac80211 to use. */ | ||
| 233 | if (info->status.rates[0].idx != spinfo->txrate_idx) | ||
| 234 | return; | ||
| 235 | |||
| 236 | spinfo->tx_num_xmit++; | ||
| 237 | |||
| 238 | #ifdef CONFIG_MAC80211_DEBUGFS | ||
| 239 | rate_control_pid_event_tx_status(&spinfo->events, info); | ||
| 240 | #endif | ||
| 241 | |||
| 242 | /* We count frames that totally failed to be transmitted as two bad | ||
| 243 | * frames, those that made it out but had some retries as one good and | ||
| 244 | * one bad frame. */ | ||
| 245 | if (!(info->flags & IEEE80211_TX_STAT_ACK)) { | ||
| 246 | spinfo->tx_num_failed += 2; | ||
| 247 | spinfo->tx_num_xmit++; | ||
| 248 | } else if (info->status.rates[0].count > 1) { | ||
| 249 | spinfo->tx_num_failed++; | ||
| 250 | spinfo->tx_num_xmit++; | ||
| 251 | } | ||
| 252 | |||
| 253 | /* Update PID controller state. */ | ||
| 254 | period = msecs_to_jiffies(pinfo->sampling_period); | ||
| 255 | if (time_after(jiffies, spinfo->last_sample + period)) | ||
| 256 | rate_control_pid_sample(pinfo, sband, sta, spinfo); | ||
| 257 | } | ||
| 258 | |||
| 259 | static void | ||
| 260 | rate_control_pid_get_rate(void *priv, struct ieee80211_sta *sta, | ||
| 261 | void *priv_sta, | ||
| 262 | struct ieee80211_tx_rate_control *txrc) | ||
| 263 | { | ||
| 264 | struct sk_buff *skb = txrc->skb; | ||
| 265 | struct ieee80211_supported_band *sband = txrc->sband; | ||
| 266 | struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); | ||
| 267 | struct rc_pid_sta_info *spinfo = priv_sta; | ||
| 268 | int rateidx; | ||
| 269 | |||
| 270 | if (txrc->rts) | ||
| 271 | info->control.rates[0].count = | ||
| 272 | txrc->hw->conf.long_frame_max_tx_count; | ||
| 273 | else | ||
| 274 | info->control.rates[0].count = | ||
| 275 | txrc->hw->conf.short_frame_max_tx_count; | ||
| 276 | |||
| 277 | /* Send management frames and NO_ACK data using lowest rate. */ | ||
| 278 | if (rate_control_send_low(sta, priv_sta, txrc)) | ||
| 279 | return; | ||
| 280 | |||
| 281 | rateidx = spinfo->txrate_idx; | ||
| 282 | |||
| 283 | if (rateidx >= sband->n_bitrates) | ||
| 284 | rateidx = sband->n_bitrates - 1; | ||
| 285 | |||
| 286 | info->control.rates[0].idx = rateidx; | ||
| 287 | |||
| 288 | #ifdef CONFIG_MAC80211_DEBUGFS | ||
| 289 | rate_control_pid_event_tx_rate(&spinfo->events, | ||
| 290 | rateidx, sband->bitrates[rateidx].bitrate); | ||
| 291 | #endif | ||
| 292 | } | ||
| 293 | |||
| 294 | static void | ||
| 295 | rate_control_pid_rate_init(void *priv, struct ieee80211_supported_band *sband, | ||
| 296 | struct cfg80211_chan_def *chandef, | ||
| 297 | struct ieee80211_sta *sta, void *priv_sta) | ||
| 298 | { | ||
| 299 | struct rc_pid_sta_info *spinfo = priv_sta; | ||
| 300 | struct rc_pid_info *pinfo = priv; | ||
| 301 | struct rc_pid_rateinfo *rinfo = pinfo->rinfo; | ||
| 302 | int i, j, tmp; | ||
| 303 | bool s; | ||
| 304 | |||
| 305 | /* TODO: This routine should consider using RSSI from previous packets | ||
| 306 | * as we need to have IEEE 802.1X auth succeed immediately after assoc.. | ||
| 307 | * Until that method is implemented, we will use the lowest supported | ||
| 308 | * rate as a workaround. */ | ||
| 309 | |||
| 310 | /* Sort the rates. This is optimized for the most common case (i.e. | ||
| 311 | * almost-sorted CCK+OFDM rates). Kind of bubble-sort with reversed | ||
| 312 | * mapping too. */ | ||
| 313 | for (i = 0; i < sband->n_bitrates; i++) { | ||
| 314 | rinfo[i].index = i; | ||
| 315 | rinfo[i].rev_index = i; | ||
| 316 | if (RC_PID_FAST_START) | ||
| 317 | rinfo[i].diff = 0; | ||
| 318 | else | ||
| 319 | rinfo[i].diff = i * pinfo->norm_offset; | ||
| 320 | } | ||
| 321 | for (i = 1; i < sband->n_bitrates; i++) { | ||
| 322 | s = false; | ||
| 323 | for (j = 0; j < sband->n_bitrates - i; j++) | ||
| 324 | if (unlikely(sband->bitrates[rinfo[j].index].bitrate > | ||
| 325 | sband->bitrates[rinfo[j + 1].index].bitrate)) { | ||
| 326 | tmp = rinfo[j].index; | ||
| 327 | rinfo[j].index = rinfo[j + 1].index; | ||
| 328 | rinfo[j + 1].index = tmp; | ||
| 329 | rinfo[rinfo[j].index].rev_index = j; | ||
| 330 | rinfo[rinfo[j + 1].index].rev_index = j + 1; | ||
| 331 | s = true; | ||
| 332 | } | ||
| 333 | if (!s) | ||
| 334 | break; | ||
| 335 | } | ||
| 336 | |||
| 337 | spinfo->txrate_idx = rate_lowest_index(sband, sta); | ||
| 338 | } | ||
| 339 | |||
| 340 | static void *rate_control_pid_alloc(struct ieee80211_hw *hw, | ||
| 341 | struct dentry *debugfsdir) | ||
| 342 | { | ||
| 343 | struct rc_pid_info *pinfo; | ||
| 344 | struct rc_pid_rateinfo *rinfo; | ||
| 345 | struct ieee80211_supported_band *sband; | ||
| 346 | int i, max_rates = 0; | ||
| 347 | #ifdef CONFIG_MAC80211_DEBUGFS | ||
| 348 | struct rc_pid_debugfs_entries *de; | ||
| 349 | #endif | ||
| 350 | |||
| 351 | pinfo = kmalloc(sizeof(*pinfo), GFP_ATOMIC); | ||
| 352 | if (!pinfo) | ||
| 353 | return NULL; | ||
| 354 | |||
| 355 | for (i = 0; i < IEEE80211_NUM_BANDS; i++) { | ||
| 356 | sband = hw->wiphy->bands[i]; | ||
| 357 | if (sband && sband->n_bitrates > max_rates) | ||
| 358 | max_rates = sband->n_bitrates; | ||
| 359 | } | ||
| 360 | |||
| 361 | rinfo = kmalloc(sizeof(*rinfo) * max_rates, GFP_ATOMIC); | ||
| 362 | if (!rinfo) { | ||
| 363 | kfree(pinfo); | ||
| 364 | return NULL; | ||
| 365 | } | ||
| 366 | |||
| 367 | pinfo->target = RC_PID_TARGET_PF; | ||
| 368 | pinfo->sampling_period = RC_PID_INTERVAL; | ||
| 369 | pinfo->coeff_p = RC_PID_COEFF_P; | ||
| 370 | pinfo->coeff_i = RC_PID_COEFF_I; | ||
| 371 | pinfo->coeff_d = RC_PID_COEFF_D; | ||
| 372 | pinfo->smoothing_shift = RC_PID_SMOOTHING_SHIFT; | ||
| 373 | pinfo->sharpen_factor = RC_PID_SHARPENING_FACTOR; | ||
| 374 | pinfo->sharpen_duration = RC_PID_SHARPENING_DURATION; | ||
| 375 | pinfo->norm_offset = RC_PID_NORM_OFFSET; | ||
| 376 | pinfo->rinfo = rinfo; | ||
| 377 | pinfo->oldrate = 0; | ||
| 378 | |||
| 379 | #ifdef CONFIG_MAC80211_DEBUGFS | ||
| 380 | de = &pinfo->dentries; | ||
| 381 | de->target = debugfs_create_u32("target_pf", S_IRUSR | S_IWUSR, | ||
| 382 | debugfsdir, &pinfo->target); | ||
| 383 | de->sampling_period = debugfs_create_u32("sampling_period", | ||
| 384 | S_IRUSR | S_IWUSR, debugfsdir, | ||
| 385 | &pinfo->sampling_period); | ||
| 386 | de->coeff_p = debugfs_create_u32("coeff_p", S_IRUSR | S_IWUSR, | ||
| 387 | debugfsdir, (u32 *)&pinfo->coeff_p); | ||
| 388 | de->coeff_i = debugfs_create_u32("coeff_i", S_IRUSR | S_IWUSR, | ||
| 389 | debugfsdir, (u32 *)&pinfo->coeff_i); | ||
| 390 | de->coeff_d = debugfs_create_u32("coeff_d", S_IRUSR | S_IWUSR, | ||
| 391 | debugfsdir, (u32 *)&pinfo->coeff_d); | ||
| 392 | de->smoothing_shift = debugfs_create_u32("smoothing_shift", | ||
| 393 | S_IRUSR | S_IWUSR, debugfsdir, | ||
| 394 | &pinfo->smoothing_shift); | ||
| 395 | de->sharpen_factor = debugfs_create_u32("sharpen_factor", | ||
| 396 | S_IRUSR | S_IWUSR, debugfsdir, | ||
| 397 | &pinfo->sharpen_factor); | ||
| 398 | de->sharpen_duration = debugfs_create_u32("sharpen_duration", | ||
| 399 | S_IRUSR | S_IWUSR, debugfsdir, | ||
| 400 | &pinfo->sharpen_duration); | ||
| 401 | de->norm_offset = debugfs_create_u32("norm_offset", | ||
| 402 | S_IRUSR | S_IWUSR, debugfsdir, | ||
| 403 | &pinfo->norm_offset); | ||
| 404 | #endif | ||
| 405 | |||
| 406 | return pinfo; | ||
| 407 | } | ||
| 408 | |||
| 409 | static void rate_control_pid_free(void *priv) | ||
| 410 | { | ||
| 411 | struct rc_pid_info *pinfo = priv; | ||
| 412 | #ifdef CONFIG_MAC80211_DEBUGFS | ||
| 413 | struct rc_pid_debugfs_entries *de = &pinfo->dentries; | ||
| 414 | |||
| 415 | debugfs_remove(de->norm_offset); | ||
| 416 | debugfs_remove(de->sharpen_duration); | ||
| 417 | debugfs_remove(de->sharpen_factor); | ||
| 418 | debugfs_remove(de->smoothing_shift); | ||
| 419 | debugfs_remove(de->coeff_d); | ||
| 420 | debugfs_remove(de->coeff_i); | ||
| 421 | debugfs_remove(de->coeff_p); | ||
| 422 | debugfs_remove(de->sampling_period); | ||
| 423 | debugfs_remove(de->target); | ||
| 424 | #endif | ||
| 425 | |||
| 426 | kfree(pinfo->rinfo); | ||
| 427 | kfree(pinfo); | ||
| 428 | } | ||
| 429 | |||
| 430 | static void *rate_control_pid_alloc_sta(void *priv, struct ieee80211_sta *sta, | ||
| 431 | gfp_t gfp) | ||
| 432 | { | ||
| 433 | struct rc_pid_sta_info *spinfo; | ||
| 434 | |||
| 435 | spinfo = kzalloc(sizeof(*spinfo), gfp); | ||
| 436 | if (spinfo == NULL) | ||
| 437 | return NULL; | ||
| 438 | |||
| 439 | spinfo->last_sample = jiffies; | ||
| 440 | |||
| 441 | #ifdef CONFIG_MAC80211_DEBUGFS | ||
| 442 | spin_lock_init(&spinfo->events.lock); | ||
| 443 | init_waitqueue_head(&spinfo->events.waitqueue); | ||
| 444 | #endif | ||
| 445 | |||
| 446 | return spinfo; | ||
| 447 | } | ||
| 448 | |||
| 449 | static void rate_control_pid_free_sta(void *priv, struct ieee80211_sta *sta, | ||
| 450 | void *priv_sta) | ||
| 451 | { | ||
| 452 | kfree(priv_sta); | ||
| 453 | } | ||
| 454 | |||
| 455 | static const struct rate_control_ops mac80211_rcpid = { | ||
| 456 | .name = "pid", | ||
| 457 | .tx_status = rate_control_pid_tx_status, | ||
| 458 | .get_rate = rate_control_pid_get_rate, | ||
| 459 | .rate_init = rate_control_pid_rate_init, | ||
| 460 | .alloc = rate_control_pid_alloc, | ||
| 461 | .free = rate_control_pid_free, | ||
| 462 | .alloc_sta = rate_control_pid_alloc_sta, | ||
| 463 | .free_sta = rate_control_pid_free_sta, | ||
| 464 | #ifdef CONFIG_MAC80211_DEBUGFS | ||
| 465 | .add_sta_debugfs = rate_control_pid_add_sta_debugfs, | ||
| 466 | .remove_sta_debugfs = rate_control_pid_remove_sta_debugfs, | ||
| 467 | #endif | ||
| 468 | }; | ||
| 469 | |||
| 470 | int __init rc80211_pid_init(void) | ||
| 471 | { | ||
| 472 | return ieee80211_rate_control_register(&mac80211_rcpid); | ||
| 473 | } | ||
| 474 | |||
| 475 | void rc80211_pid_exit(void) | ||
| 476 | { | ||
| 477 | ieee80211_rate_control_unregister(&mac80211_rcpid); | ||
| 478 | } | ||
diff --git a/net/mac80211/rc80211_pid_debugfs.c b/net/mac80211/rc80211_pid_debugfs.c deleted file mode 100644 index 6ff134650a84..000000000000 --- a/net/mac80211/rc80211_pid_debugfs.c +++ /dev/null | |||
| @@ -1,228 +0,0 @@ | |||
| 1 | /* | ||
| 2 | * Copyright 2007, Mattias Nissler <mattias.nissler@gmx.de> | ||
| 3 | * | ||
| 4 | * This program is free software; you can redistribute it and/or modify | ||
| 5 | * it under the terms of the GNU General Public License version 2 as | ||
| 6 | * published by the Free Software Foundation. | ||
| 7 | */ | ||
| 8 | |||
| 9 | #include <linux/sched.h> | ||
| 10 | #include <linux/spinlock.h> | ||
| 11 | #include <linux/poll.h> | ||
| 12 | #include <linux/netdevice.h> | ||
| 13 | #include <linux/types.h> | ||
| 14 | #include <linux/skbuff.h> | ||
| 15 | #include <linux/slab.h> | ||
| 16 | #include <linux/export.h> | ||
| 17 | |||
| 18 | #include <net/mac80211.h> | ||
| 19 | #include "rate.h" | ||
| 20 | |||
| 21 | #include "rc80211_pid.h" | ||
| 22 | |||
| 23 | static void rate_control_pid_event(struct rc_pid_event_buffer *buf, | ||
| 24 | enum rc_pid_event_type type, | ||
| 25 | union rc_pid_event_data *data) | ||
| 26 | { | ||
| 27 | struct rc_pid_event *ev; | ||
| 28 | unsigned long status; | ||
| 29 | |||
| 30 | spin_lock_irqsave(&buf->lock, status); | ||
| 31 | ev = &(buf->ring[buf->next_entry]); | ||
| 32 | buf->next_entry = (buf->next_entry + 1) % RC_PID_EVENT_RING_SIZE; | ||
| 33 | |||
| 34 | ev->timestamp = jiffies; | ||
| 35 | ev->id = buf->ev_count++; | ||
| 36 | ev->type = type; | ||
| 37 | ev->data = *data; | ||
| 38 | |||
| 39 | spin_unlock_irqrestore(&buf->lock, status); | ||
| 40 | |||
| 41 | wake_up_all(&buf->waitqueue); | ||
| 42 | } | ||
| 43 | |||
| 44 | void rate_control_pid_event_tx_status(struct rc_pid_event_buffer *buf, | ||
| 45 | struct ieee80211_tx_info *stat) | ||
| 46 | { | ||
| 47 | union rc_pid_event_data evd; | ||
| 48 | |||
| 49 | evd.flags = stat->flags; | ||
| 50 | memcpy(&evd.tx_status, stat, sizeof(struct ieee80211_tx_info)); | ||
| 51 | rate_control_pid_event(buf, RC_PID_EVENT_TYPE_TX_STATUS, &evd); | ||
| 52 | } | ||
| 53 | |||
| 54 | void rate_control_pid_event_rate_change(struct rc_pid_event_buffer *buf, | ||
| 55 | int index, int rate) | ||
| 56 | { | ||
| 57 | union rc_pid_event_data evd; | ||
| 58 | |||
| 59 | evd.index = index; | ||
| 60 | evd.rate = rate; | ||
| 61 | rate_control_pid_event(buf, RC_PID_EVENT_TYPE_RATE_CHANGE, &evd); | ||
| 62 | } | ||
| 63 | |||
| 64 | void rate_control_pid_event_tx_rate(struct rc_pid_event_buffer *buf, | ||
| 65 | int index, int rate) | ||
| 66 | { | ||
| 67 | union rc_pid_event_data evd; | ||
| 68 | |||
| 69 | evd.index = index; | ||
| 70 | evd.rate = rate; | ||
| 71 | rate_control_pid_event(buf, RC_PID_EVENT_TYPE_TX_RATE, &evd); | ||
| 72 | } | ||
| 73 | |||
| 74 | void rate_control_pid_event_pf_sample(struct rc_pid_event_buffer *buf, | ||
| 75 | s32 pf_sample, s32 prop_err, | ||
| 76 | s32 int_err, s32 der_err) | ||
| 77 | { | ||
| 78 | union rc_pid_event_data evd; | ||
| 79 | |||
| 80 | evd.pf_sample = pf_sample; | ||
| 81 | evd.prop_err = prop_err; | ||
| 82 | evd.int_err = int_err; | ||
| 83 | evd.der_err = der_err; | ||
| 84 | rate_control_pid_event(buf, RC_PID_EVENT_TYPE_PF_SAMPLE, &evd); | ||
| 85 | } | ||
| 86 | |||
| 87 | static int rate_control_pid_events_open(struct inode *inode, struct file *file) | ||
| 88 | { | ||
| 89 | struct rc_pid_sta_info *sinfo = inode->i_private; | ||
| 90 | struct rc_pid_event_buffer *events = &sinfo->events; | ||
| 91 | struct rc_pid_events_file_info *file_info; | ||
| 92 | unsigned long status; | ||
| 93 | |||
| 94 | /* Allocate a state struct */ | ||
| 95 | file_info = kmalloc(sizeof(*file_info), GFP_KERNEL); | ||
| 96 | if (file_info == NULL) | ||
| 97 | return -ENOMEM; | ||
| 98 | |||
| 99 | spin_lock_irqsave(&events->lock, status); | ||
| 100 | |||
| 101 | file_info->next_entry = events->next_entry; | ||
| 102 | file_info->events = events; | ||
| 103 | |||
| 104 | spin_unlock_irqrestore(&events->lock, status); | ||
| 105 | |||
| 106 | file->private_data = file_info; | ||
| 107 | |||
| 108 | return 0; | ||
| 109 | } | ||
| 110 | |||
| 111 | static int rate_control_pid_events_release(struct inode *inode, | ||
| 112 | struct file *file) | ||
| 113 | { | ||
| 114 | struct rc_pid_events_file_info *file_info = file->private_data; | ||
| 115 | |||
| 116 | kfree(file_info); | ||
| 117 | |||
| 118 | return 0; | ||
| 119 | } | ||
| 120 | |||
| 121 | static unsigned int rate_control_pid_events_poll(struct file *file, | ||
| 122 | poll_table *wait) | ||
| 123 | { | ||
| 124 | struct rc_pid_events_file_info *file_info = file->private_data; | ||
| 125 | |||
| 126 | poll_wait(file, &file_info->events->waitqueue, wait); | ||
| 127 | |||
| 128 | return POLLIN | POLLRDNORM; | ||
| 129 | } | ||
| 130 | |||
| 131 | #define RC_PID_PRINT_BUF_SIZE 64 | ||
| 132 | |||
| 133 | static ssize_t rate_control_pid_events_read(struct file *file, char __user *buf, | ||
| 134 | size_t length, loff_t *offset) | ||
| 135 | { | ||
| 136 | struct rc_pid_events_file_info *file_info = file->private_data; | ||
| 137 | struct rc_pid_event_buffer *events = file_info->events; | ||
| 138 | struct rc_pid_event *ev; | ||
| 139 | char pb[RC_PID_PRINT_BUF_SIZE]; | ||
| 140 | int ret; | ||
| 141 | int p; | ||
| 142 | unsigned long status; | ||
| 143 | |||
| 144 | /* Check if there is something to read. */ | ||
| 145 | if (events->next_entry == file_info->next_entry) { | ||
| 146 | if (file->f_flags & O_NONBLOCK) | ||
| 147 | return -EAGAIN; | ||
| 148 | |||
| 149 | /* Wait */ | ||
| 150 | ret = wait_event_interruptible(events->waitqueue, | ||
| 151 | events->next_entry != file_info->next_entry); | ||
| 152 | |||
| 153 | if (ret) | ||
| 154 | return ret; | ||
| 155 | } | ||
| 156 | |||
| 157 | /* Write out one event per call. I don't care whether it's a little | ||
| 158 | * inefficient, this is debugging code anyway. */ | ||
| 159 | spin_lock_irqsave(&events->lock, status); | ||
| 160 | |||
| 161 | /* Get an event */ | ||
| 162 | ev = &(events->ring[file_info->next_entry]); | ||
| 163 | file_info->next_entry = (file_info->next_entry + 1) % | ||
| 164 | RC_PID_EVENT_RING_SIZE; | ||
| 165 | |||
| 166 | /* Print information about the event. Note that userspace needs to | ||
| 167 | * provide large enough buffers. */ | ||
| 168 | length = length < RC_PID_PRINT_BUF_SIZE ? | ||
| 169 | length : RC_PID_PRINT_BUF_SIZE; | ||
| 170 | p = scnprintf(pb, length, "%u %lu ", ev->id, ev->timestamp); | ||
| 171 | switch (ev->type) { | ||
| 172 | case RC_PID_EVENT_TYPE_TX_STATUS: | ||
| 173 | p += scnprintf(pb + p, length - p, "tx_status %u %u", | ||
| 174 | !(ev->data.flags & IEEE80211_TX_STAT_ACK), | ||
| 175 | ev->data.tx_status.status.rates[0].idx); | ||
| 176 | break; | ||
| 177 | case RC_PID_EVENT_TYPE_RATE_CHANGE: | ||
| 178 | p += scnprintf(pb + p, length - p, "rate_change %d %d", | ||
| 179 | ev->data.index, ev->data.rate); | ||
| 180 | break; | ||
| 181 | case RC_PID_EVENT_TYPE_TX_RATE: | ||
| 182 | p += scnprintf(pb + p, length - p, "tx_rate %d %d", | ||
| 183 | ev->data.index, ev->data.rate); | ||
| 184 | break; | ||
| 185 | case RC_PID_EVENT_TYPE_PF_SAMPLE: | ||
| 186 | p += scnprintf(pb + p, length - p, | ||
| 187 | "pf_sample %d %d %d %d", | ||
| 188 | ev->data.pf_sample, ev->data.prop_err, | ||
| 189 | ev->data.int_err, ev->data.der_err); | ||
| 190 | break; | ||
| 191 | } | ||
| 192 | p += scnprintf(pb + p, length - p, "\n"); | ||
| 193 | |||
| 194 | spin_unlock_irqrestore(&events->lock, status); | ||
| 195 | |||
| 196 | if (copy_to_user(buf, pb, p)) | ||
| 197 | return -EFAULT; | ||
| 198 | |||
| 199 | return p; | ||
| 200 | } | ||
| 201 | |||
| 202 | #undef RC_PID_PRINT_BUF_SIZE | ||
| 203 | |||
| 204 | static const struct file_operations rc_pid_fop_events = { | ||
| 205 | .owner = THIS_MODULE, | ||
| 206 | .read = rate_control_pid_events_read, | ||
| 207 | .poll = rate_control_pid_events_poll, | ||
| 208 | .open = rate_control_pid_events_open, | ||
| 209 | .release = rate_control_pid_events_release, | ||
| 210 | .llseek = noop_llseek, | ||
| 211 | }; | ||
| 212 | |||
| 213 | void rate_control_pid_add_sta_debugfs(void *priv, void *priv_sta, | ||
| 214 | struct dentry *dir) | ||
| 215 | { | ||
| 216 | struct rc_pid_sta_info *spinfo = priv_sta; | ||
| 217 | |||
| 218 | spinfo->events_entry = debugfs_create_file("rc_pid_events", S_IRUGO, | ||
| 219 | dir, spinfo, | ||
| 220 | &rc_pid_fop_events); | ||
| 221 | } | ||
| 222 | |||
| 223 | void rate_control_pid_remove_sta_debugfs(void *priv, void *priv_sta) | ||
| 224 | { | ||
| 225 | struct rc_pid_sta_info *spinfo = priv_sta; | ||
| 226 | |||
| 227 | debugfs_remove(spinfo->events_entry); | ||
| 228 | } | ||
diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c index 394e201cde6d..bd2c9b22c945 100644 --- a/net/mac80211/rx.c +++ b/net/mac80211/rx.c | |||
| @@ -688,20 +688,27 @@ static void ieee80211_release_reorder_frame(struct ieee80211_sub_if_data *sdata, | |||
| 688 | int index, | 688 | int index, |
| 689 | struct sk_buff_head *frames) | 689 | struct sk_buff_head *frames) |
| 690 | { | 690 | { |
| 691 | struct sk_buff *skb = tid_agg_rx->reorder_buf[index]; | 691 | struct sk_buff_head *skb_list = &tid_agg_rx->reorder_buf[index]; |
| 692 | struct sk_buff *skb; | ||
| 692 | struct ieee80211_rx_status *status; | 693 | struct ieee80211_rx_status *status; |
| 693 | 694 | ||
| 694 | lockdep_assert_held(&tid_agg_rx->reorder_lock); | 695 | lockdep_assert_held(&tid_agg_rx->reorder_lock); |
| 695 | 696 | ||
| 696 | if (!skb) | 697 | if (skb_queue_empty(skb_list)) |
| 698 | goto no_frame; | ||
| 699 | |||
| 700 | if (!ieee80211_rx_reorder_ready(skb_list)) { | ||
| 701 | __skb_queue_purge(skb_list); | ||
| 697 | goto no_frame; | 702 | goto no_frame; |
| 703 | } | ||
| 698 | 704 | ||
| 699 | /* release the frame from the reorder ring buffer */ | 705 | /* release frames from the reorder ring buffer */ |
| 700 | tid_agg_rx->stored_mpdu_num--; | 706 | tid_agg_rx->stored_mpdu_num--; |
| 701 | tid_agg_rx->reorder_buf[index] = NULL; | 707 | while ((skb = __skb_dequeue(skb_list))) { |
| 702 | status = IEEE80211_SKB_RXCB(skb); | 708 | status = IEEE80211_SKB_RXCB(skb); |
| 703 | status->rx_flags |= IEEE80211_RX_DEFERRED_RELEASE; | 709 | status->rx_flags |= IEEE80211_RX_DEFERRED_RELEASE; |
| 704 | __skb_queue_tail(frames, skb); | 710 | __skb_queue_tail(frames, skb); |
| 711 | } | ||
| 705 | 712 | ||
| 706 | no_frame: | 713 | no_frame: |
| 707 | tid_agg_rx->head_seq_num = ieee80211_sn_inc(tid_agg_rx->head_seq_num); | 714 | tid_agg_rx->head_seq_num = ieee80211_sn_inc(tid_agg_rx->head_seq_num); |
| @@ -738,13 +745,13 @@ static void ieee80211_sta_reorder_release(struct ieee80211_sub_if_data *sdata, | |||
| 738 | struct tid_ampdu_rx *tid_agg_rx, | 745 | struct tid_ampdu_rx *tid_agg_rx, |
| 739 | struct sk_buff_head *frames) | 746 | struct sk_buff_head *frames) |
| 740 | { | 747 | { |
| 741 | int index, j; | 748 | int index, i, j; |
| 742 | 749 | ||
| 743 | lockdep_assert_held(&tid_agg_rx->reorder_lock); | 750 | lockdep_assert_held(&tid_agg_rx->reorder_lock); |
| 744 | 751 | ||
| 745 | /* release the buffer until next missing frame */ | 752 | /* release the buffer until next missing frame */ |
| 746 | index = tid_agg_rx->head_seq_num % tid_agg_rx->buf_size; | 753 | index = tid_agg_rx->head_seq_num % tid_agg_rx->buf_size; |
| 747 | if (!tid_agg_rx->reorder_buf[index] && | 754 | if (!ieee80211_rx_reorder_ready(&tid_agg_rx->reorder_buf[index]) && |
| 748 | tid_agg_rx->stored_mpdu_num) { | 755 | tid_agg_rx->stored_mpdu_num) { |
| 749 | /* | 756 | /* |
| 750 | * No buffers ready to be released, but check whether any | 757 | * No buffers ready to be released, but check whether any |
| @@ -753,7 +760,8 @@ static void ieee80211_sta_reorder_release(struct ieee80211_sub_if_data *sdata, | |||
| 753 | int skipped = 1; | 760 | int skipped = 1; |
| 754 | for (j = (index + 1) % tid_agg_rx->buf_size; j != index; | 761 | for (j = (index + 1) % tid_agg_rx->buf_size; j != index; |
| 755 | j = (j + 1) % tid_agg_rx->buf_size) { | 762 | j = (j + 1) % tid_agg_rx->buf_size) { |
| 756 | if (!tid_agg_rx->reorder_buf[j]) { | 763 | if (!ieee80211_rx_reorder_ready( |
| 764 | &tid_agg_rx->reorder_buf[j])) { | ||
| 757 | skipped++; | 765 | skipped++; |
| 758 | continue; | 766 | continue; |
| 759 | } | 767 | } |
| @@ -762,6 +770,11 @@ static void ieee80211_sta_reorder_release(struct ieee80211_sub_if_data *sdata, | |||
| 762 | HT_RX_REORDER_BUF_TIMEOUT)) | 770 | HT_RX_REORDER_BUF_TIMEOUT)) |
| 763 | goto set_release_timer; | 771 | goto set_release_timer; |
| 764 | 772 | ||
| 773 | /* don't leave incomplete A-MSDUs around */ | ||
| 774 | for (i = (index + 1) % tid_agg_rx->buf_size; i != j; | ||
| 775 | i = (i + 1) % tid_agg_rx->buf_size) | ||
| 776 | __skb_queue_purge(&tid_agg_rx->reorder_buf[i]); | ||
| 777 | |||
| 765 | ht_dbg_ratelimited(sdata, | 778 | ht_dbg_ratelimited(sdata, |
| 766 | "release an RX reorder frame due to timeout on earlier frames\n"); | 779 | "release an RX reorder frame due to timeout on earlier frames\n"); |
| 767 | ieee80211_release_reorder_frame(sdata, tid_agg_rx, j, | 780 | ieee80211_release_reorder_frame(sdata, tid_agg_rx, j, |
| @@ -775,7 +788,8 @@ static void ieee80211_sta_reorder_release(struct ieee80211_sub_if_data *sdata, | |||
| 775 | skipped) & IEEE80211_SN_MASK; | 788 | skipped) & IEEE80211_SN_MASK; |
| 776 | skipped = 0; | 789 | skipped = 0; |
| 777 | } | 790 | } |
| 778 | } else while (tid_agg_rx->reorder_buf[index]) { | 791 | } else while (ieee80211_rx_reorder_ready( |
| 792 | &tid_agg_rx->reorder_buf[index])) { | ||
| 779 | ieee80211_release_reorder_frame(sdata, tid_agg_rx, index, | 793 | ieee80211_release_reorder_frame(sdata, tid_agg_rx, index, |
| 780 | frames); | 794 | frames); |
| 781 | index = tid_agg_rx->head_seq_num % tid_agg_rx->buf_size; | 795 | index = tid_agg_rx->head_seq_num % tid_agg_rx->buf_size; |
| @@ -786,7 +800,8 @@ static void ieee80211_sta_reorder_release(struct ieee80211_sub_if_data *sdata, | |||
| 786 | 800 | ||
| 787 | for (; j != (index - 1) % tid_agg_rx->buf_size; | 801 | for (; j != (index - 1) % tid_agg_rx->buf_size; |
| 788 | j = (j + 1) % tid_agg_rx->buf_size) { | 802 | j = (j + 1) % tid_agg_rx->buf_size) { |
| 789 | if (tid_agg_rx->reorder_buf[j]) | 803 | if (ieee80211_rx_reorder_ready( |
| 804 | &tid_agg_rx->reorder_buf[j])) | ||
| 790 | break; | 805 | break; |
| 791 | } | 806 | } |
| 792 | 807 | ||
| @@ -811,6 +826,7 @@ static bool ieee80211_sta_manage_reorder_buf(struct ieee80211_sub_if_data *sdata | |||
| 811 | struct sk_buff_head *frames) | 826 | struct sk_buff_head *frames) |
| 812 | { | 827 | { |
| 813 | struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; | 828 | struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; |
| 829 | struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(skb); | ||
| 814 | u16 sc = le16_to_cpu(hdr->seq_ctrl); | 830 | u16 sc = le16_to_cpu(hdr->seq_ctrl); |
| 815 | u16 mpdu_seq_num = (sc & IEEE80211_SCTL_SEQ) >> 4; | 831 | u16 mpdu_seq_num = (sc & IEEE80211_SCTL_SEQ) >> 4; |
| 816 | u16 head_seq_num, buf_size; | 832 | u16 head_seq_num, buf_size; |
| @@ -845,7 +861,7 @@ static bool ieee80211_sta_manage_reorder_buf(struct ieee80211_sub_if_data *sdata | |||
| 845 | index = mpdu_seq_num % tid_agg_rx->buf_size; | 861 | index = mpdu_seq_num % tid_agg_rx->buf_size; |
| 846 | 862 | ||
| 847 | /* check if we already stored this frame */ | 863 | /* check if we already stored this frame */ |
| 848 | if (tid_agg_rx->reorder_buf[index]) { | 864 | if (ieee80211_rx_reorder_ready(&tid_agg_rx->reorder_buf[index])) { |
| 849 | dev_kfree_skb(skb); | 865 | dev_kfree_skb(skb); |
| 850 | goto out; | 866 | goto out; |
| 851 | } | 867 | } |
| @@ -858,17 +874,20 @@ static bool ieee80211_sta_manage_reorder_buf(struct ieee80211_sub_if_data *sdata | |||
| 858 | */ | 874 | */ |
| 859 | if (mpdu_seq_num == tid_agg_rx->head_seq_num && | 875 | if (mpdu_seq_num == tid_agg_rx->head_seq_num && |
| 860 | tid_agg_rx->stored_mpdu_num == 0) { | 876 | tid_agg_rx->stored_mpdu_num == 0) { |
| 861 | tid_agg_rx->head_seq_num = | 877 | if (!(status->flag & RX_FLAG_AMSDU_MORE)) |
| 862 | ieee80211_sn_inc(tid_agg_rx->head_seq_num); | 878 | tid_agg_rx->head_seq_num = |
| 879 | ieee80211_sn_inc(tid_agg_rx->head_seq_num); | ||
| 863 | ret = false; | 880 | ret = false; |
| 864 | goto out; | 881 | goto out; |
| 865 | } | 882 | } |
| 866 | 883 | ||
| 867 | /* put the frame in the reordering buffer */ | 884 | /* put the frame in the reordering buffer */ |
| 868 | tid_agg_rx->reorder_buf[index] = skb; | 885 | __skb_queue_tail(&tid_agg_rx->reorder_buf[index], skb); |
| 869 | tid_agg_rx->reorder_time[index] = jiffies; | 886 | if (!(status->flag & RX_FLAG_AMSDU_MORE)) { |
| 870 | tid_agg_rx->stored_mpdu_num++; | 887 | tid_agg_rx->reorder_time[index] = jiffies; |
| 871 | ieee80211_sta_reorder_release(sdata, tid_agg_rx, frames); | 888 | tid_agg_rx->stored_mpdu_num++; |
| 889 | ieee80211_sta_reorder_release(sdata, tid_agg_rx, frames); | ||
| 890 | } | ||
| 872 | 891 | ||
| 873 | out: | 892 | out: |
| 874 | spin_unlock(&tid_agg_rx->reorder_lock); | 893 | spin_unlock(&tid_agg_rx->reorder_lock); |
| @@ -1107,6 +1126,8 @@ static void sta_ps_end(struct sta_info *sta) | |||
| 1107 | return; | 1126 | return; |
| 1108 | } | 1127 | } |
| 1109 | 1128 | ||
| 1129 | set_sta_flag(sta, WLAN_STA_PS_DELIVER); | ||
| 1130 | clear_sta_flag(sta, WLAN_STA_PS_STA); | ||
| 1110 | ieee80211_sta_ps_deliver_wakeup(sta); | 1131 | ieee80211_sta_ps_deliver_wakeup(sta); |
| 1111 | } | 1132 | } |
| 1112 | 1133 | ||
| @@ -3127,6 +3148,14 @@ static bool prepare_for_handlers(struct ieee80211_rx_data *rx, | |||
| 3127 | if (!ieee80211_is_beacon(hdr->frame_control)) | 3148 | if (!ieee80211_is_beacon(hdr->frame_control)) |
| 3128 | return false; | 3149 | return false; |
| 3129 | status->rx_flags &= ~IEEE80211_RX_RA_MATCH; | 3150 | status->rx_flags &= ~IEEE80211_RX_RA_MATCH; |
| 3151 | } else if (!ieee80211_has_tods(hdr->frame_control)) { | ||
| 3152 | /* ignore data frames to TDLS-peers */ | ||
| 3153 | if (ieee80211_is_data(hdr->frame_control)) | ||
| 3154 | return false; | ||
| 3155 | /* ignore action frames to TDLS-peers */ | ||
| 3156 | if (ieee80211_is_action(hdr->frame_control) && | ||
| 3157 | !ether_addr_equal(bssid, hdr->addr1)) | ||
| 3158 | return false; | ||
| 3130 | } | 3159 | } |
| 3131 | break; | 3160 | break; |
| 3132 | case NL80211_IFTYPE_WDS: | 3161 | case NL80211_IFTYPE_WDS: |
diff --git a/net/mac80211/scan.c b/net/mac80211/scan.c index f40661eb75b5..a0a938145dcc 100644 --- a/net/mac80211/scan.c +++ b/net/mac80211/scan.c | |||
| @@ -235,38 +235,51 @@ static bool ieee80211_prep_hw_scan(struct ieee80211_local *local) | |||
| 235 | { | 235 | { |
| 236 | struct cfg80211_scan_request *req = local->scan_req; | 236 | struct cfg80211_scan_request *req = local->scan_req; |
| 237 | struct cfg80211_chan_def chandef; | 237 | struct cfg80211_chan_def chandef; |
| 238 | enum ieee80211_band band; | 238 | u8 bands_used = 0; |
| 239 | int i, ielen, n_chans; | 239 | int i, ielen, n_chans; |
| 240 | 240 | ||
| 241 | if (test_bit(SCAN_HW_CANCELLED, &local->scanning)) | 241 | if (test_bit(SCAN_HW_CANCELLED, &local->scanning)) |
| 242 | return false; | 242 | return false; |
| 243 | 243 | ||
| 244 | do { | 244 | if (local->hw.flags & IEEE80211_SINGLE_HW_SCAN_ON_ALL_BANDS) { |
| 245 | if (local->hw_scan_band == IEEE80211_NUM_BANDS) | ||
| 246 | return false; | ||
| 247 | |||
| 248 | band = local->hw_scan_band; | ||
| 249 | n_chans = 0; | ||
| 250 | for (i = 0; i < req->n_channels; i++) { | 245 | for (i = 0; i < req->n_channels; i++) { |
| 251 | if (req->channels[i]->band == band) { | 246 | local->hw_scan_req->req.channels[i] = req->channels[i]; |
| 252 | local->hw_scan_req->channels[n_chans] = | 247 | bands_used |= BIT(req->channels[i]->band); |
| 248 | } | ||
| 249 | |||
| 250 | n_chans = req->n_channels; | ||
| 251 | } else { | ||
| 252 | do { | ||
| 253 | if (local->hw_scan_band == IEEE80211_NUM_BANDS) | ||
| 254 | return false; | ||
| 255 | |||
| 256 | n_chans = 0; | ||
| 257 | |||
| 258 | for (i = 0; i < req->n_channels; i++) { | ||
| 259 | if (req->channels[i]->band != | ||
| 260 | local->hw_scan_band) | ||
| 261 | continue; | ||
| 262 | local->hw_scan_req->req.channels[n_chans] = | ||
| 253 | req->channels[i]; | 263 | req->channels[i]; |
| 254 | n_chans++; | 264 | n_chans++; |
| 265 | bands_used |= BIT(req->channels[i]->band); | ||
| 255 | } | 266 | } |
| 256 | } | ||
| 257 | 267 | ||
| 258 | local->hw_scan_band++; | 268 | local->hw_scan_band++; |
| 259 | } while (!n_chans); | 269 | } while (!n_chans); |
| 270 | } | ||
| 260 | 271 | ||
| 261 | local->hw_scan_req->n_channels = n_chans; | 272 | local->hw_scan_req->req.n_channels = n_chans; |
| 262 | ieee80211_prepare_scan_chandef(&chandef, req->scan_width); | 273 | ieee80211_prepare_scan_chandef(&chandef, req->scan_width); |
| 263 | 274 | ||
| 264 | ielen = ieee80211_build_preq_ies(local, (u8 *)local->hw_scan_req->ie, | 275 | ielen = ieee80211_build_preq_ies(local, |
| 276 | (u8 *)local->hw_scan_req->req.ie, | ||
| 265 | local->hw_scan_ies_bufsize, | 277 | local->hw_scan_ies_bufsize, |
| 266 | req->ie, req->ie_len, band, | 278 | &local->hw_scan_req->ies, |
| 267 | req->rates[band], &chandef); | 279 | req->ie, req->ie_len, |
| 268 | local->hw_scan_req->ie_len = ielen; | 280 | bands_used, req->rates, &chandef); |
| 269 | local->hw_scan_req->no_cck = req->no_cck; | 281 | local->hw_scan_req->req.ie_len = ielen; |
| 282 | local->hw_scan_req->req.no_cck = req->no_cck; | ||
| 270 | 283 | ||
| 271 | return true; | 284 | return true; |
| 272 | } | 285 | } |
| @@ -291,7 +304,9 @@ static void __ieee80211_scan_completed(struct ieee80211_hw *hw, bool aborted) | |||
| 291 | if (WARN_ON(!local->scan_req)) | 304 | if (WARN_ON(!local->scan_req)) |
| 292 | return; | 305 | return; |
| 293 | 306 | ||
| 294 | if (hw_scan && !aborted && ieee80211_prep_hw_scan(local)) { | 307 | if (hw_scan && !aborted && |
| 308 | !(local->hw.flags & IEEE80211_SINGLE_HW_SCAN_ON_ALL_BANDS) && | ||
| 309 | ieee80211_prep_hw_scan(local)) { | ||
| 295 | int rc; | 310 | int rc; |
| 296 | 311 | ||
| 297 | rc = drv_hw_scan(local, | 312 | rc = drv_hw_scan(local, |
| @@ -473,6 +488,21 @@ static int __ieee80211_start_scan(struct ieee80211_sub_if_data *sdata, | |||
| 473 | u8 *ies; | 488 | u8 *ies; |
| 474 | 489 | ||
| 475 | local->hw_scan_ies_bufsize = local->scan_ies_len + req->ie_len; | 490 | local->hw_scan_ies_bufsize = local->scan_ies_len + req->ie_len; |
| 491 | |||
| 492 | if (local->hw.flags & IEEE80211_SINGLE_HW_SCAN_ON_ALL_BANDS) { | ||
| 493 | int i, n_bands = 0; | ||
| 494 | u8 bands_counted = 0; | ||
| 495 | |||
| 496 | for (i = 0; i < req->n_channels; i++) { | ||
| 497 | if (bands_counted & BIT(req->channels[i]->band)) | ||
| 498 | continue; | ||
| 499 | bands_counted |= BIT(req->channels[i]->band); | ||
| 500 | n_bands++; | ||
| 501 | } | ||
| 502 | |||
| 503 | local->hw_scan_ies_bufsize *= n_bands; | ||
| 504 | } | ||
| 505 | |||
| 476 | local->hw_scan_req = kmalloc( | 506 | local->hw_scan_req = kmalloc( |
| 477 | sizeof(*local->hw_scan_req) + | 507 | sizeof(*local->hw_scan_req) + |
| 478 | req->n_channels * sizeof(req->channels[0]) + | 508 | req->n_channels * sizeof(req->channels[0]) + |
| @@ -480,13 +510,13 @@ static int __ieee80211_start_scan(struct ieee80211_sub_if_data *sdata, | |||
| 480 | if (!local->hw_scan_req) | 510 | if (!local->hw_scan_req) |
| 481 | return -ENOMEM; | 511 | return -ENOMEM; |
| 482 | 512 | ||
| 483 | local->hw_scan_req->ssids = req->ssids; | 513 | local->hw_scan_req->req.ssids = req->ssids; |
| 484 | local->hw_scan_req->n_ssids = req->n_ssids; | 514 | local->hw_scan_req->req.n_ssids = req->n_ssids; |
| 485 | ies = (u8 *)local->hw_scan_req + | 515 | ies = (u8 *)local->hw_scan_req + |
| 486 | sizeof(*local->hw_scan_req) + | 516 | sizeof(*local->hw_scan_req) + |
| 487 | req->n_channels * sizeof(req->channels[0]); | 517 | req->n_channels * sizeof(req->channels[0]); |
| 488 | local->hw_scan_req->ie = ies; | 518 | local->hw_scan_req->req.ie = ies; |
| 489 | local->hw_scan_req->flags = req->flags; | 519 | local->hw_scan_req->req.flags = req->flags; |
| 490 | 520 | ||
| 491 | local->hw_scan_band = 0; | 521 | local->hw_scan_band = 0; |
| 492 | 522 | ||
| @@ -973,9 +1003,13 @@ int __ieee80211_request_sched_scan_start(struct ieee80211_sub_if_data *sdata, | |||
| 973 | struct cfg80211_sched_scan_request *req) | 1003 | struct cfg80211_sched_scan_request *req) |
| 974 | { | 1004 | { |
| 975 | struct ieee80211_local *local = sdata->local; | 1005 | struct ieee80211_local *local = sdata->local; |
| 976 | struct ieee80211_sched_scan_ies sched_scan_ies = {}; | 1006 | struct ieee80211_scan_ies sched_scan_ies = {}; |
| 977 | struct cfg80211_chan_def chandef; | 1007 | struct cfg80211_chan_def chandef; |
| 978 | int ret, i, iebufsz; | 1008 | int ret, i, iebufsz, num_bands = 0; |
| 1009 | u32 rate_masks[IEEE80211_NUM_BANDS] = {}; | ||
| 1010 | u8 bands_used = 0; | ||
| 1011 | u8 *ie; | ||
| 1012 | size_t len; | ||
| 979 | 1013 | ||
| 980 | iebufsz = local->scan_ies_len + req->ie_len; | 1014 | iebufsz = local->scan_ies_len + req->ie_len; |
| 981 | 1015 | ||
| @@ -985,33 +1019,35 @@ int __ieee80211_request_sched_scan_start(struct ieee80211_sub_if_data *sdata, | |||
| 985 | return -ENOTSUPP; | 1019 | return -ENOTSUPP; |
| 986 | 1020 | ||
| 987 | for (i = 0; i < IEEE80211_NUM_BANDS; i++) { | 1021 | for (i = 0; i < IEEE80211_NUM_BANDS; i++) { |
| 988 | if (!local->hw.wiphy->bands[i]) | 1022 | if (local->hw.wiphy->bands[i]) { |
| 989 | continue; | 1023 | bands_used |= BIT(i); |
| 990 | 1024 | rate_masks[i] = (u32) -1; | |
| 991 | sched_scan_ies.ie[i] = kzalloc(iebufsz, GFP_KERNEL); | 1025 | num_bands++; |
| 992 | if (!sched_scan_ies.ie[i]) { | ||
| 993 | ret = -ENOMEM; | ||
| 994 | goto out_free; | ||
| 995 | } | 1026 | } |
| 1027 | } | ||
| 996 | 1028 | ||
| 997 | ieee80211_prepare_scan_chandef(&chandef, req->scan_width); | 1029 | ie = kzalloc(num_bands * iebufsz, GFP_KERNEL); |
| 998 | 1030 | if (!ie) { | |
| 999 | sched_scan_ies.len[i] = | 1031 | ret = -ENOMEM; |
| 1000 | ieee80211_build_preq_ies(local, sched_scan_ies.ie[i], | 1032 | goto out; |
| 1001 | iebufsz, req->ie, req->ie_len, | ||
| 1002 | i, (u32) -1, &chandef); | ||
| 1003 | } | 1033 | } |
| 1004 | 1034 | ||
| 1035 | ieee80211_prepare_scan_chandef(&chandef, req->scan_width); | ||
| 1036 | |||
| 1037 | len = ieee80211_build_preq_ies(local, ie, num_bands * iebufsz, | ||
| 1038 | &sched_scan_ies, req->ie, | ||
| 1039 | req->ie_len, bands_used, | ||
| 1040 | rate_masks, &chandef); | ||
| 1041 | |||
| 1005 | ret = drv_sched_scan_start(local, sdata, req, &sched_scan_ies); | 1042 | ret = drv_sched_scan_start(local, sdata, req, &sched_scan_ies); |
| 1006 | if (ret == 0) { | 1043 | if (ret == 0) { |
| 1007 | rcu_assign_pointer(local->sched_scan_sdata, sdata); | 1044 | rcu_assign_pointer(local->sched_scan_sdata, sdata); |
| 1008 | local->sched_scan_req = req; | 1045 | local->sched_scan_req = req; |
| 1009 | } | 1046 | } |
| 1010 | 1047 | ||
| 1011 | out_free: | 1048 | kfree(ie); |
| 1012 | while (i > 0) | ||
| 1013 | kfree(sched_scan_ies.ie[--i]); | ||
| 1014 | 1049 | ||
| 1050 | out: | ||
| 1015 | if (ret) { | 1051 | if (ret) { |
| 1016 | /* Clean in case of failure after HW restart or upon resume. */ | 1052 | /* Clean in case of failure after HW restart or upon resume. */ |
| 1017 | RCU_INIT_POINTER(local->sched_scan_sdata, NULL); | 1053 | RCU_INIT_POINTER(local->sched_scan_sdata, NULL); |
diff --git a/net/mac80211/sta_info.c b/net/mac80211/sta_info.c index a9b46d8ea22f..c6ee2139fbc5 100644 --- a/net/mac80211/sta_info.c +++ b/net/mac80211/sta_info.c | |||
| @@ -100,7 +100,8 @@ static void __cleanup_single_sta(struct sta_info *sta) | |||
| 100 | struct ps_data *ps; | 100 | struct ps_data *ps; |
| 101 | 101 | ||
| 102 | if (test_sta_flag(sta, WLAN_STA_PS_STA) || | 102 | if (test_sta_flag(sta, WLAN_STA_PS_STA) || |
| 103 | test_sta_flag(sta, WLAN_STA_PS_DRIVER)) { | 103 | test_sta_flag(sta, WLAN_STA_PS_DRIVER) || |
| 104 | test_sta_flag(sta, WLAN_STA_PS_DELIVER)) { | ||
| 104 | if (sta->sdata->vif.type == NL80211_IFTYPE_AP || | 105 | if (sta->sdata->vif.type == NL80211_IFTYPE_AP || |
| 105 | sta->sdata->vif.type == NL80211_IFTYPE_AP_VLAN) | 106 | sta->sdata->vif.type == NL80211_IFTYPE_AP_VLAN) |
| 106 | ps = &sdata->bss->ps; | 107 | ps = &sdata->bss->ps; |
| @@ -111,6 +112,7 @@ static void __cleanup_single_sta(struct sta_info *sta) | |||
| 111 | 112 | ||
| 112 | clear_sta_flag(sta, WLAN_STA_PS_STA); | 113 | clear_sta_flag(sta, WLAN_STA_PS_STA); |
| 113 | clear_sta_flag(sta, WLAN_STA_PS_DRIVER); | 114 | clear_sta_flag(sta, WLAN_STA_PS_DRIVER); |
| 115 | clear_sta_flag(sta, WLAN_STA_PS_DELIVER); | ||
| 114 | 116 | ||
| 115 | atomic_dec(&ps->num_sta_ps); | 117 | atomic_dec(&ps->num_sta_ps); |
| 116 | sta_info_recalc_tim(sta); | 118 | sta_info_recalc_tim(sta); |
| @@ -125,7 +127,7 @@ static void __cleanup_single_sta(struct sta_info *sta) | |||
| 125 | if (ieee80211_vif_is_mesh(&sdata->vif)) | 127 | if (ieee80211_vif_is_mesh(&sdata->vif)) |
| 126 | mesh_sta_cleanup(sta); | 128 | mesh_sta_cleanup(sta); |
| 127 | 129 | ||
| 128 | cancel_work_sync(&sta->drv_unblock_wk); | 130 | cancel_work_sync(&sta->drv_deliver_wk); |
| 129 | 131 | ||
| 130 | /* | 132 | /* |
| 131 | * Destroy aggregation state here. It would be nice to wait for the | 133 | * Destroy aggregation state here. It would be nice to wait for the |
| @@ -253,33 +255,23 @@ static void sta_info_hash_add(struct ieee80211_local *local, | |||
| 253 | rcu_assign_pointer(local->sta_hash[STA_HASH(sta->sta.addr)], sta); | 255 | rcu_assign_pointer(local->sta_hash[STA_HASH(sta->sta.addr)], sta); |
| 254 | } | 256 | } |
| 255 | 257 | ||
| 256 | static void sta_unblock(struct work_struct *wk) | 258 | static void sta_deliver_ps_frames(struct work_struct *wk) |
| 257 | { | 259 | { |
| 258 | struct sta_info *sta; | 260 | struct sta_info *sta; |
| 259 | 261 | ||
| 260 | sta = container_of(wk, struct sta_info, drv_unblock_wk); | 262 | sta = container_of(wk, struct sta_info, drv_deliver_wk); |
| 261 | 263 | ||
| 262 | if (sta->dead) | 264 | if (sta->dead) |
| 263 | return; | 265 | return; |
| 264 | 266 | ||
| 265 | if (!test_sta_flag(sta, WLAN_STA_PS_STA)) { | 267 | local_bh_disable(); |
| 266 | local_bh_disable(); | 268 | if (!test_sta_flag(sta, WLAN_STA_PS_STA)) |
| 267 | ieee80211_sta_ps_deliver_wakeup(sta); | 269 | ieee80211_sta_ps_deliver_wakeup(sta); |
| 268 | local_bh_enable(); | 270 | else if (test_and_clear_sta_flag(sta, WLAN_STA_PSPOLL)) |
| 269 | } else if (test_and_clear_sta_flag(sta, WLAN_STA_PSPOLL)) { | ||
| 270 | clear_sta_flag(sta, WLAN_STA_PS_DRIVER); | ||
| 271 | |||
| 272 | local_bh_disable(); | ||
| 273 | ieee80211_sta_ps_deliver_poll_response(sta); | 271 | ieee80211_sta_ps_deliver_poll_response(sta); |
| 274 | local_bh_enable(); | 272 | else if (test_and_clear_sta_flag(sta, WLAN_STA_UAPSD)) |
| 275 | } else if (test_and_clear_sta_flag(sta, WLAN_STA_UAPSD)) { | ||
| 276 | clear_sta_flag(sta, WLAN_STA_PS_DRIVER); | ||
| 277 | |||
| 278 | local_bh_disable(); | ||
| 279 | ieee80211_sta_ps_deliver_uapsd(sta); | 273 | ieee80211_sta_ps_deliver_uapsd(sta); |
| 280 | local_bh_enable(); | 274 | local_bh_enable(); |
| 281 | } else | ||
| 282 | clear_sta_flag(sta, WLAN_STA_PS_DRIVER); | ||
| 283 | } | 275 | } |
| 284 | 276 | ||
| 285 | static int sta_prepare_rate_control(struct ieee80211_local *local, | 277 | static int sta_prepare_rate_control(struct ieee80211_local *local, |
| @@ -341,7 +333,7 @@ struct sta_info *sta_info_alloc(struct ieee80211_sub_if_data *sdata, | |||
| 341 | 333 | ||
| 342 | spin_lock_init(&sta->lock); | 334 | spin_lock_init(&sta->lock); |
| 343 | spin_lock_init(&sta->ps_lock); | 335 | spin_lock_init(&sta->ps_lock); |
| 344 | INIT_WORK(&sta->drv_unblock_wk, sta_unblock); | 336 | INIT_WORK(&sta->drv_deliver_wk, sta_deliver_ps_frames); |
| 345 | INIT_WORK(&sta->ampdu_mlme.work, ieee80211_ba_session_work); | 337 | INIT_WORK(&sta->ampdu_mlme.work, ieee80211_ba_session_work); |
| 346 | mutex_init(&sta->ampdu_mlme.mtx); | 338 | mutex_init(&sta->ampdu_mlme.mtx); |
| 347 | #ifdef CONFIG_MAC80211_MESH | 339 | #ifdef CONFIG_MAC80211_MESH |
| @@ -358,7 +350,7 @@ struct sta_info *sta_info_alloc(struct ieee80211_sub_if_data *sdata, | |||
| 358 | 350 | ||
| 359 | sta->sta_state = IEEE80211_STA_NONE; | 351 | sta->sta_state = IEEE80211_STA_NONE; |
| 360 | 352 | ||
| 361 | do_posix_clock_monotonic_gettime(&uptime); | 353 | ktime_get_ts(&uptime); |
| 362 | sta->last_connected = uptime.tv_sec; | 354 | sta->last_connected = uptime.tv_sec; |
| 363 | ewma_init(&sta->avg_signal, 1024, 8); | 355 | ewma_init(&sta->avg_signal, 1024, 8); |
| 364 | for (i = 0; i < ARRAY_SIZE(sta->chain_signal_avg); i++) | 356 | for (i = 0; i < ARRAY_SIZE(sta->chain_signal_avg); i++) |
| @@ -1141,8 +1133,15 @@ void ieee80211_sta_ps_deliver_wakeup(struct sta_info *sta) | |||
| 1141 | } | 1133 | } |
| 1142 | 1134 | ||
| 1143 | ieee80211_add_pending_skbs(local, &pending); | 1135 | ieee80211_add_pending_skbs(local, &pending); |
| 1144 | clear_sta_flag(sta, WLAN_STA_PS_DRIVER); | 1136 | |
| 1145 | clear_sta_flag(sta, WLAN_STA_PS_STA); | 1137 | /* now we're no longer in the deliver code */ |
| 1138 | clear_sta_flag(sta, WLAN_STA_PS_DELIVER); | ||
| 1139 | |||
| 1140 | /* The station might have polled and then woken up before we responded, | ||
| 1141 | * so clear these flags now to avoid them sticking around. | ||
| 1142 | */ | ||
| 1143 | clear_sta_flag(sta, WLAN_STA_PSPOLL); | ||
| 1144 | clear_sta_flag(sta, WLAN_STA_UAPSD); | ||
| 1146 | spin_unlock(&sta->ps_lock); | 1145 | spin_unlock(&sta->ps_lock); |
| 1147 | 1146 | ||
| 1148 | atomic_dec(&ps->num_sta_ps); | 1147 | atomic_dec(&ps->num_sta_ps); |
| @@ -1543,10 +1542,26 @@ void ieee80211_sta_block_awake(struct ieee80211_hw *hw, | |||
| 1543 | 1542 | ||
| 1544 | trace_api_sta_block_awake(sta->local, pubsta, block); | 1543 | trace_api_sta_block_awake(sta->local, pubsta, block); |
| 1545 | 1544 | ||
| 1546 | if (block) | 1545 | if (block) { |
| 1547 | set_sta_flag(sta, WLAN_STA_PS_DRIVER); | 1546 | set_sta_flag(sta, WLAN_STA_PS_DRIVER); |
| 1548 | else if (test_sta_flag(sta, WLAN_STA_PS_DRIVER)) | 1547 | return; |
| 1549 | ieee80211_queue_work(hw, &sta->drv_unblock_wk); | 1548 | } |
| 1549 | |||
| 1550 | if (!test_sta_flag(sta, WLAN_STA_PS_DRIVER)) | ||
| 1551 | return; | ||
| 1552 | |||
| 1553 | if (!test_sta_flag(sta, WLAN_STA_PS_STA)) { | ||
| 1554 | set_sta_flag(sta, WLAN_STA_PS_DELIVER); | ||
| 1555 | clear_sta_flag(sta, WLAN_STA_PS_DRIVER); | ||
| 1556 | ieee80211_queue_work(hw, &sta->drv_deliver_wk); | ||
| 1557 | } else if (test_sta_flag(sta, WLAN_STA_PSPOLL) || | ||
| 1558 | test_sta_flag(sta, WLAN_STA_UAPSD)) { | ||
| 1559 | /* must be asleep in this case */ | ||
| 1560 | clear_sta_flag(sta, WLAN_STA_PS_DRIVER); | ||
| 1561 | ieee80211_queue_work(hw, &sta->drv_deliver_wk); | ||
| 1562 | } else { | ||
| 1563 | clear_sta_flag(sta, WLAN_STA_PS_DRIVER); | ||
| 1564 | } | ||
| 1550 | } | 1565 | } |
| 1551 | EXPORT_SYMBOL(ieee80211_sta_block_awake); | 1566 | EXPORT_SYMBOL(ieee80211_sta_block_awake); |
| 1552 | 1567 | ||
| @@ -1704,3 +1719,140 @@ u8 sta_info_tx_streams(struct sta_info *sta) | |||
| 1704 | return ((ht_cap->mcs.tx_params & IEEE80211_HT_MCS_TX_MAX_STREAMS_MASK) | 1719 | return ((ht_cap->mcs.tx_params & IEEE80211_HT_MCS_TX_MAX_STREAMS_MASK) |
| 1705 | >> IEEE80211_HT_MCS_TX_MAX_STREAMS_SHIFT) + 1; | 1720 | >> IEEE80211_HT_MCS_TX_MAX_STREAMS_SHIFT) + 1; |
| 1706 | } | 1721 | } |
| 1722 | |||
| 1723 | void sta_set_sinfo(struct sta_info *sta, struct station_info *sinfo) | ||
| 1724 | { | ||
| 1725 | struct ieee80211_sub_if_data *sdata = sta->sdata; | ||
| 1726 | struct ieee80211_local *local = sdata->local; | ||
| 1727 | struct rate_control_ref *ref = NULL; | ||
| 1728 | struct timespec uptime; | ||
| 1729 | u64 packets = 0; | ||
| 1730 | u32 thr = 0; | ||
| 1731 | int i, ac; | ||
| 1732 | |||
| 1733 | if (test_sta_flag(sta, WLAN_STA_RATE_CONTROL)) | ||
| 1734 | ref = local->rate_ctrl; | ||
| 1735 | |||
| 1736 | sinfo->generation = sdata->local->sta_generation; | ||
| 1737 | |||
| 1738 | sinfo->filled = STATION_INFO_INACTIVE_TIME | | ||
| 1739 | STATION_INFO_RX_BYTES64 | | ||
| 1740 | STATION_INFO_TX_BYTES64 | | ||
| 1741 | STATION_INFO_RX_PACKETS | | ||
| 1742 | STATION_INFO_TX_PACKETS | | ||
| 1743 | STATION_INFO_TX_RETRIES | | ||
| 1744 | STATION_INFO_TX_FAILED | | ||
| 1745 | STATION_INFO_TX_BITRATE | | ||
| 1746 | STATION_INFO_RX_BITRATE | | ||
| 1747 | STATION_INFO_RX_DROP_MISC | | ||
| 1748 | STATION_INFO_BSS_PARAM | | ||
| 1749 | STATION_INFO_CONNECTED_TIME | | ||
| 1750 | STATION_INFO_STA_FLAGS | | ||
| 1751 | STATION_INFO_BEACON_LOSS_COUNT; | ||
| 1752 | |||
| 1753 | ktime_get_ts(&uptime); | ||
| 1754 | sinfo->connected_time = uptime.tv_sec - sta->last_connected; | ||
| 1755 | |||
| 1756 | sinfo->inactive_time = jiffies_to_msecs(jiffies - sta->last_rx); | ||
| 1757 | sinfo->tx_bytes = 0; | ||
| 1758 | for (ac = 0; ac < IEEE80211_NUM_ACS; ac++) { | ||
| 1759 | sinfo->tx_bytes += sta->tx_bytes[ac]; | ||
| 1760 | packets += sta->tx_packets[ac]; | ||
| 1761 | } | ||
| 1762 | sinfo->tx_packets = packets; | ||
| 1763 | sinfo->rx_bytes = sta->rx_bytes; | ||
| 1764 | sinfo->rx_packets = sta->rx_packets; | ||
| 1765 | sinfo->tx_retries = sta->tx_retry_count; | ||
| 1766 | sinfo->tx_failed = sta->tx_retry_failed; | ||
| 1767 | sinfo->rx_dropped_misc = sta->rx_dropped; | ||
| 1768 | sinfo->beacon_loss_count = sta->beacon_loss_count; | ||
| 1769 | |||
| 1770 | if ((sta->local->hw.flags & IEEE80211_HW_SIGNAL_DBM) || | ||
| 1771 | (sta->local->hw.flags & IEEE80211_HW_SIGNAL_UNSPEC)) { | ||
| 1772 | sinfo->filled |= STATION_INFO_SIGNAL | STATION_INFO_SIGNAL_AVG; | ||
| 1773 | if (!local->ops->get_rssi || | ||
| 1774 | drv_get_rssi(local, sdata, &sta->sta, &sinfo->signal)) | ||
| 1775 | sinfo->signal = (s8)sta->last_signal; | ||
| 1776 | sinfo->signal_avg = (s8) -ewma_read(&sta->avg_signal); | ||
| 1777 | } | ||
| 1778 | if (sta->chains) { | ||
| 1779 | sinfo->filled |= STATION_INFO_CHAIN_SIGNAL | | ||
| 1780 | STATION_INFO_CHAIN_SIGNAL_AVG; | ||
| 1781 | |||
| 1782 | sinfo->chains = sta->chains; | ||
| 1783 | for (i = 0; i < ARRAY_SIZE(sinfo->chain_signal); i++) { | ||
| 1784 | sinfo->chain_signal[i] = sta->chain_signal_last[i]; | ||
| 1785 | sinfo->chain_signal_avg[i] = | ||
| 1786 | (s8) -ewma_read(&sta->chain_signal_avg[i]); | ||
| 1787 | } | ||
| 1788 | } | ||
| 1789 | |||
| 1790 | sta_set_rate_info_tx(sta, &sta->last_tx_rate, &sinfo->txrate); | ||
| 1791 | sta_set_rate_info_rx(sta, &sinfo->rxrate); | ||
| 1792 | |||
| 1793 | if (ieee80211_vif_is_mesh(&sdata->vif)) { | ||
| 1794 | #ifdef CONFIG_MAC80211_MESH | ||
| 1795 | sinfo->filled |= STATION_INFO_LLID | | ||
| 1796 | STATION_INFO_PLID | | ||
| 1797 | STATION_INFO_PLINK_STATE | | ||
| 1798 | STATION_INFO_LOCAL_PM | | ||
| 1799 | STATION_INFO_PEER_PM | | ||
| 1800 | STATION_INFO_NONPEER_PM; | ||
| 1801 | |||
| 1802 | sinfo->llid = sta->llid; | ||
| 1803 | sinfo->plid = sta->plid; | ||
| 1804 | sinfo->plink_state = sta->plink_state; | ||
| 1805 | if (test_sta_flag(sta, WLAN_STA_TOFFSET_KNOWN)) { | ||
| 1806 | sinfo->filled |= STATION_INFO_T_OFFSET; | ||
| 1807 | sinfo->t_offset = sta->t_offset; | ||
| 1808 | } | ||
| 1809 | sinfo->local_pm = sta->local_pm; | ||
| 1810 | sinfo->peer_pm = sta->peer_pm; | ||
| 1811 | sinfo->nonpeer_pm = sta->nonpeer_pm; | ||
| 1812 | #endif | ||
| 1813 | } | ||
| 1814 | |||
| 1815 | sinfo->bss_param.flags = 0; | ||
| 1816 | if (sdata->vif.bss_conf.use_cts_prot) | ||
| 1817 | sinfo->bss_param.flags |= BSS_PARAM_FLAGS_CTS_PROT; | ||
| 1818 | if (sdata->vif.bss_conf.use_short_preamble) | ||
| 1819 | sinfo->bss_param.flags |= BSS_PARAM_FLAGS_SHORT_PREAMBLE; | ||
| 1820 | if (sdata->vif.bss_conf.use_short_slot) | ||
| 1821 | sinfo->bss_param.flags |= BSS_PARAM_FLAGS_SHORT_SLOT_TIME; | ||
| 1822 | sinfo->bss_param.dtim_period = sdata->local->hw.conf.ps_dtim_period; | ||
| 1823 | sinfo->bss_param.beacon_interval = sdata->vif.bss_conf.beacon_int; | ||
| 1824 | |||
| 1825 | sinfo->sta_flags.set = 0; | ||
| 1826 | sinfo->sta_flags.mask = BIT(NL80211_STA_FLAG_AUTHORIZED) | | ||
| 1827 | BIT(NL80211_STA_FLAG_SHORT_PREAMBLE) | | ||
| 1828 | BIT(NL80211_STA_FLAG_WME) | | ||
| 1829 | BIT(NL80211_STA_FLAG_MFP) | | ||
| 1830 | BIT(NL80211_STA_FLAG_AUTHENTICATED) | | ||
| 1831 | BIT(NL80211_STA_FLAG_ASSOCIATED) | | ||
| 1832 | BIT(NL80211_STA_FLAG_TDLS_PEER); | ||
| 1833 | if (test_sta_flag(sta, WLAN_STA_AUTHORIZED)) | ||
| 1834 | sinfo->sta_flags.set |= BIT(NL80211_STA_FLAG_AUTHORIZED); | ||
| 1835 | if (test_sta_flag(sta, WLAN_STA_SHORT_PREAMBLE)) | ||
| 1836 | sinfo->sta_flags.set |= BIT(NL80211_STA_FLAG_SHORT_PREAMBLE); | ||
| 1837 | if (test_sta_flag(sta, WLAN_STA_WME)) | ||
| 1838 | sinfo->sta_flags.set |= BIT(NL80211_STA_FLAG_WME); | ||
| 1839 | if (test_sta_flag(sta, WLAN_STA_MFP)) | ||
| 1840 | sinfo->sta_flags.set |= BIT(NL80211_STA_FLAG_MFP); | ||
| 1841 | if (test_sta_flag(sta, WLAN_STA_AUTH)) | ||
| 1842 | sinfo->sta_flags.set |= BIT(NL80211_STA_FLAG_AUTHENTICATED); | ||
| 1843 | if (test_sta_flag(sta, WLAN_STA_ASSOC)) | ||
| 1844 | sinfo->sta_flags.set |= BIT(NL80211_STA_FLAG_ASSOCIATED); | ||
| 1845 | if (test_sta_flag(sta, WLAN_STA_TDLS_PEER)) | ||
| 1846 | sinfo->sta_flags.set |= BIT(NL80211_STA_FLAG_TDLS_PEER); | ||
| 1847 | |||
| 1848 | /* check if the driver has a SW RC implementation */ | ||
| 1849 | if (ref && ref->ops->get_expected_throughput) | ||
| 1850 | thr = ref->ops->get_expected_throughput(sta->rate_ctrl_priv); | ||
| 1851 | else | ||
| 1852 | thr = drv_get_expected_throughput(local, &sta->sta); | ||
| 1853 | |||
| 1854 | if (thr != 0) { | ||
| 1855 | sinfo->filled |= STATION_INFO_EXPECTED_THROUGHPUT; | ||
| 1856 | sinfo->expected_throughput = thr; | ||
| 1857 | } | ||
| 1858 | } | ||
diff --git a/net/mac80211/sta_info.h b/net/mac80211/sta_info.h index 4acc5fc402fa..d411bcc8ef08 100644 --- a/net/mac80211/sta_info.h +++ b/net/mac80211/sta_info.h | |||
| @@ -47,6 +47,8 @@ | |||
| 47 | * @WLAN_STA_TDLS_PEER: Station is a TDLS peer. | 47 | * @WLAN_STA_TDLS_PEER: Station is a TDLS peer. |
| 48 | * @WLAN_STA_TDLS_PEER_AUTH: This TDLS peer is authorized to send direct | 48 | * @WLAN_STA_TDLS_PEER_AUTH: This TDLS peer is authorized to send direct |
| 49 | * packets. This means the link is enabled. | 49 | * packets. This means the link is enabled. |
| 50 | * @WLAN_STA_TDLS_INITIATOR: We are the initiator of the TDLS link with this | ||
| 51 | * station. | ||
| 50 | * @WLAN_STA_UAPSD: Station requested unscheduled SP while driver was | 52 | * @WLAN_STA_UAPSD: Station requested unscheduled SP while driver was |
| 51 | * keeping station in power-save mode, reply when the driver | 53 | * keeping station in power-save mode, reply when the driver |
| 52 | * unblocks the station. | 54 | * unblocks the station. |
| @@ -58,6 +60,8 @@ | |||
| 58 | * @WLAN_STA_TOFFSET_KNOWN: toffset calculated for this station is valid. | 60 | * @WLAN_STA_TOFFSET_KNOWN: toffset calculated for this station is valid. |
| 59 | * @WLAN_STA_MPSP_OWNER: local STA is owner of a mesh Peer Service Period. | 61 | * @WLAN_STA_MPSP_OWNER: local STA is owner of a mesh Peer Service Period. |
| 60 | * @WLAN_STA_MPSP_RECIPIENT: local STA is recipient of a MPSP. | 62 | * @WLAN_STA_MPSP_RECIPIENT: local STA is recipient of a MPSP. |
| 63 | * @WLAN_STA_PS_DELIVER: station woke up, but we're still blocking TX | ||
| 64 | * until pending frames are delivered | ||
| 61 | */ | 65 | */ |
| 62 | enum ieee80211_sta_info_flags { | 66 | enum ieee80211_sta_info_flags { |
| 63 | WLAN_STA_AUTH, | 67 | WLAN_STA_AUTH, |
| @@ -74,6 +78,7 @@ enum ieee80211_sta_info_flags { | |||
| 74 | WLAN_STA_PSPOLL, | 78 | WLAN_STA_PSPOLL, |
| 75 | WLAN_STA_TDLS_PEER, | 79 | WLAN_STA_TDLS_PEER, |
| 76 | WLAN_STA_TDLS_PEER_AUTH, | 80 | WLAN_STA_TDLS_PEER_AUTH, |
| 81 | WLAN_STA_TDLS_INITIATOR, | ||
| 77 | WLAN_STA_UAPSD, | 82 | WLAN_STA_UAPSD, |
| 78 | WLAN_STA_SP, | 83 | WLAN_STA_SP, |
| 79 | WLAN_STA_4ADDR_EVENT, | 84 | WLAN_STA_4ADDR_EVENT, |
| @@ -82,6 +87,7 @@ enum ieee80211_sta_info_flags { | |||
| 82 | WLAN_STA_TOFFSET_KNOWN, | 87 | WLAN_STA_TOFFSET_KNOWN, |
| 83 | WLAN_STA_MPSP_OWNER, | 88 | WLAN_STA_MPSP_OWNER, |
| 84 | WLAN_STA_MPSP_RECIPIENT, | 89 | WLAN_STA_MPSP_RECIPIENT, |
| 90 | WLAN_STA_PS_DELIVER, | ||
| 85 | }; | 91 | }; |
| 86 | 92 | ||
| 87 | #define ADDBA_RESP_INTERVAL HZ | 93 | #define ADDBA_RESP_INTERVAL HZ |
| @@ -149,7 +155,8 @@ struct tid_ampdu_tx { | |||
| 149 | /** | 155 | /** |
| 150 | * struct tid_ampdu_rx - TID aggregation information (Rx). | 156 | * struct tid_ampdu_rx - TID aggregation information (Rx). |
| 151 | * | 157 | * |
| 152 | * @reorder_buf: buffer to reorder incoming aggregated MPDUs | 158 | * @reorder_buf: buffer to reorder incoming aggregated MPDUs. An MPDU may be an |
| 159 | * A-MSDU with individually reported subframes. | ||
| 153 | * @reorder_time: jiffies when skb was added | 160 | * @reorder_time: jiffies when skb was added |
| 154 | * @session_timer: check if peer keeps Tx-ing on the TID (by timeout value) | 161 | * @session_timer: check if peer keeps Tx-ing on the TID (by timeout value) |
| 155 | * @reorder_timer: releases expired frames from the reorder buffer. | 162 | * @reorder_timer: releases expired frames from the reorder buffer. |
| @@ -174,7 +181,7 @@ struct tid_ampdu_tx { | |||
| 174 | struct tid_ampdu_rx { | 181 | struct tid_ampdu_rx { |
| 175 | struct rcu_head rcu_head; | 182 | struct rcu_head rcu_head; |
| 176 | spinlock_t reorder_lock; | 183 | spinlock_t reorder_lock; |
| 177 | struct sk_buff **reorder_buf; | 184 | struct sk_buff_head *reorder_buf; |
| 178 | unsigned long *reorder_time; | 185 | unsigned long *reorder_time; |
| 179 | struct timer_list session_timer; | 186 | struct timer_list session_timer; |
| 180 | struct timer_list reorder_timer; | 187 | struct timer_list reorder_timer; |
| @@ -265,7 +272,7 @@ struct ieee80211_tx_latency_stat { | |||
| 265 | * @last_rx_rate_vht_nss: rx status nss of last data packet | 272 | * @last_rx_rate_vht_nss: rx status nss of last data packet |
| 266 | * @lock: used for locking all fields that require locking, see comments | 273 | * @lock: used for locking all fields that require locking, see comments |
| 267 | * in the header file. | 274 | * in the header file. |
| 268 | * @drv_unblock_wk: used for driver PS unblocking | 275 | * @drv_deliver_wk: used for delivering frames after driver PS unblocking |
| 269 | * @listen_interval: listen interval of this station, when we're acting as AP | 276 | * @listen_interval: listen interval of this station, when we're acting as AP |
| 270 | * @_flags: STA flags, see &enum ieee80211_sta_info_flags, do not use directly | 277 | * @_flags: STA flags, see &enum ieee80211_sta_info_flags, do not use directly |
| 271 | * @ps_lock: used for powersave (when mac80211 is the AP) related locking | 278 | * @ps_lock: used for powersave (when mac80211 is the AP) related locking |
| @@ -278,7 +285,6 @@ struct ieee80211_tx_latency_stat { | |||
| 278 | * @driver_buffered_tids: bitmap of TIDs the driver has data buffered on | 285 | * @driver_buffered_tids: bitmap of TIDs the driver has data buffered on |
| 279 | * @rx_packets: Number of MSDUs received from this STA | 286 | * @rx_packets: Number of MSDUs received from this STA |
| 280 | * @rx_bytes: Number of bytes received from this STA | 287 | * @rx_bytes: Number of bytes received from this STA |
| 281 | * @wep_weak_iv_count: number of weak WEP IVs received from this station | ||
| 282 | * @last_rx: time (in jiffies) when last frame was received from this STA | 288 | * @last_rx: time (in jiffies) when last frame was received from this STA |
| 283 | * @last_connected: time (in seconds) when a station got connected | 289 | * @last_connected: time (in seconds) when a station got connected |
| 284 | * @num_duplicates: number of duplicate frames received from this STA | 290 | * @num_duplicates: number of duplicate frames received from this STA |
| @@ -303,7 +309,6 @@ struct ieee80211_tx_latency_stat { | |||
| 303 | * @plid: Peer link ID | 309 | * @plid: Peer link ID |
| 304 | * @reason: Cancel reason on PLINK_HOLDING state | 310 | * @reason: Cancel reason on PLINK_HOLDING state |
| 305 | * @plink_retries: Retries in establishment | 311 | * @plink_retries: Retries in establishment |
| 306 | * @ignore_plink_timer: ignore the peer-link timer (used internally) | ||
| 307 | * @plink_state: peer link state | 312 | * @plink_state: peer link state |
| 308 | * @plink_timeout: timeout of peer link | 313 | * @plink_timeout: timeout of peer link |
| 309 | * @plink_timer: peer link watch timer | 314 | * @plink_timer: peer link watch timer |
| @@ -345,7 +350,7 @@ struct sta_info { | |||
| 345 | void *rate_ctrl_priv; | 350 | void *rate_ctrl_priv; |
| 346 | spinlock_t lock; | 351 | spinlock_t lock; |
| 347 | 352 | ||
| 348 | struct work_struct drv_unblock_wk; | 353 | struct work_struct drv_deliver_wk; |
| 349 | 354 | ||
| 350 | u16 listen_interval; | 355 | u16 listen_interval; |
| 351 | 356 | ||
| @@ -367,7 +372,6 @@ struct sta_info { | |||
| 367 | /* Updated from RX path only, no locking requirements */ | 372 | /* Updated from RX path only, no locking requirements */ |
| 368 | unsigned long rx_packets; | 373 | unsigned long rx_packets; |
| 369 | u64 rx_bytes; | 374 | u64 rx_bytes; |
| 370 | unsigned long wep_weak_iv_count; | ||
| 371 | unsigned long last_rx; | 375 | unsigned long last_rx; |
| 372 | long last_connected; | 376 | long last_connected; |
| 373 | unsigned long num_duplicates; | 377 | unsigned long num_duplicates; |
| @@ -418,7 +422,6 @@ struct sta_info { | |||
| 418 | u16 plid; | 422 | u16 plid; |
| 419 | u16 reason; | 423 | u16 reason; |
| 420 | u8 plink_retries; | 424 | u8 plink_retries; |
| 421 | bool ignore_plink_timer; | ||
| 422 | enum nl80211_plink_state plink_state; | 425 | enum nl80211_plink_state plink_state; |
| 423 | u32 plink_timeout; | 426 | u32 plink_timeout; |
| 424 | struct timer_list plink_timer; | 427 | struct timer_list plink_timer; |
| @@ -628,6 +631,8 @@ void sta_set_rate_info_tx(struct sta_info *sta, | |||
| 628 | struct rate_info *rinfo); | 631 | struct rate_info *rinfo); |
| 629 | void sta_set_rate_info_rx(struct sta_info *sta, | 632 | void sta_set_rate_info_rx(struct sta_info *sta, |
| 630 | struct rate_info *rinfo); | 633 | struct rate_info *rinfo); |
| 634 | void sta_set_sinfo(struct sta_info *sta, struct station_info *sinfo); | ||
| 635 | |||
| 631 | void ieee80211_sta_expire(struct ieee80211_sub_if_data *sdata, | 636 | void ieee80211_sta_expire(struct ieee80211_sub_if_data *sdata, |
| 632 | unsigned long exp_time); | 637 | unsigned long exp_time); |
| 633 | u8 sta_info_tx_streams(struct sta_info *sta); | 638 | u8 sta_info_tx_streams(struct sta_info *sta); |
diff --git a/net/mac80211/status.c b/net/mac80211/status.c index ba29ebc86141..aa06dcad336e 100644 --- a/net/mac80211/status.c +++ b/net/mac80211/status.c | |||
| @@ -473,8 +473,6 @@ static void ieee80211_tx_latency_end_msrmnt(struct ieee80211_local *local, | |||
| 473 | struct sta_info *sta, | 473 | struct sta_info *sta, |
| 474 | struct ieee80211_hdr *hdr) | 474 | struct ieee80211_hdr *hdr) |
| 475 | { | 475 | { |
| 476 | ktime_t skb_dprt; | ||
| 477 | struct timespec dprt_time; | ||
| 478 | u32 msrmnt; | 476 | u32 msrmnt; |
| 479 | u16 tid; | 477 | u16 tid; |
| 480 | u8 *qc; | 478 | u8 *qc; |
| @@ -506,9 +504,8 @@ static void ieee80211_tx_latency_end_msrmnt(struct ieee80211_local *local, | |||
| 506 | 504 | ||
| 507 | tx_lat = &sta->tx_lat[tid]; | 505 | tx_lat = &sta->tx_lat[tid]; |
| 508 | 506 | ||
| 509 | ktime_get_ts(&dprt_time); /* time stamp completion time */ | 507 | /* Calculate the latency */ |
| 510 | skb_dprt = ktime_set(dprt_time.tv_sec, dprt_time.tv_nsec); | 508 | msrmnt = ktime_to_ms(ktime_sub(ktime_get(), skb_arv)); |
| 511 | msrmnt = ktime_to_ms(ktime_sub(skb_dprt, skb_arv)); | ||
| 512 | 509 | ||
| 513 | if (tx_lat->max < msrmnt) /* update stats */ | 510 | if (tx_lat->max < msrmnt) /* update stats */ |
| 514 | tx_lat->max = msrmnt; | 511 | tx_lat->max = msrmnt; |
diff --git a/net/mac80211/tdls.c b/net/mac80211/tdls.c index 652813b2d3df..1b21050be174 100644 --- a/net/mac80211/tdls.c +++ b/net/mac80211/tdls.c | |||
| @@ -8,7 +8,31 @@ | |||
| 8 | */ | 8 | */ |
| 9 | 9 | ||
| 10 | #include <linux/ieee80211.h> | 10 | #include <linux/ieee80211.h> |
| 11 | #include <linux/log2.h> | ||
| 12 | #include <net/cfg80211.h> | ||
| 11 | #include "ieee80211_i.h" | 13 | #include "ieee80211_i.h" |
| 14 | #include "driver-ops.h" | ||
| 15 | |||
| 16 | /* give usermode some time for retries in setting up the TDLS session */ | ||
| 17 | #define TDLS_PEER_SETUP_TIMEOUT (15 * HZ) | ||
| 18 | |||
| 19 | void ieee80211_tdls_peer_del_work(struct work_struct *wk) | ||
| 20 | { | ||
| 21 | struct ieee80211_sub_if_data *sdata; | ||
| 22 | struct ieee80211_local *local; | ||
| 23 | |||
| 24 | sdata = container_of(wk, struct ieee80211_sub_if_data, | ||
| 25 | u.mgd.tdls_peer_del_work.work); | ||
| 26 | local = sdata->local; | ||
| 27 | |||
| 28 | mutex_lock(&local->mtx); | ||
| 29 | if (!is_zero_ether_addr(sdata->u.mgd.tdls_peer)) { | ||
| 30 | tdls_dbg(sdata, "TDLS del peer %pM\n", sdata->u.mgd.tdls_peer); | ||
| 31 | sta_info_destroy_addr(sdata, sdata->u.mgd.tdls_peer); | ||
| 32 | eth_zero_addr(sdata->u.mgd.tdls_peer); | ||
| 33 | } | ||
| 34 | mutex_unlock(&local->mtx); | ||
| 35 | } | ||
| 12 | 36 | ||
| 13 | static void ieee80211_tdls_add_ext_capab(struct sk_buff *skb) | 37 | static void ieee80211_tdls_add_ext_capab(struct sk_buff *skb) |
| 14 | { | 38 | { |
| @@ -23,11 +47,16 @@ static void ieee80211_tdls_add_ext_capab(struct sk_buff *skb) | |||
| 23 | *pos++ = WLAN_EXT_CAPA5_TDLS_ENABLED; | 47 | *pos++ = WLAN_EXT_CAPA5_TDLS_ENABLED; |
| 24 | } | 48 | } |
| 25 | 49 | ||
| 26 | static u16 ieee80211_get_tdls_sta_capab(struct ieee80211_sub_if_data *sdata) | 50 | static u16 ieee80211_get_tdls_sta_capab(struct ieee80211_sub_if_data *sdata, |
| 51 | u16 status_code) | ||
| 27 | { | 52 | { |
| 28 | struct ieee80211_local *local = sdata->local; | 53 | struct ieee80211_local *local = sdata->local; |
| 29 | u16 capab; | 54 | u16 capab; |
| 30 | 55 | ||
| 56 | /* The capability will be 0 when sending a failure code */ | ||
| 57 | if (status_code != 0) | ||
| 58 | return 0; | ||
| 59 | |||
| 31 | capab = 0; | 60 | capab = 0; |
| 32 | if (ieee80211_get_sdata_band(sdata) != IEEE80211_BAND_2GHZ) | 61 | if (ieee80211_get_sdata_band(sdata) != IEEE80211_BAND_2GHZ) |
| 33 | return capab; | 62 | return capab; |
| @@ -40,19 +69,332 @@ static u16 ieee80211_get_tdls_sta_capab(struct ieee80211_sub_if_data *sdata) | |||
| 40 | return capab; | 69 | return capab; |
| 41 | } | 70 | } |
| 42 | 71 | ||
| 43 | static void ieee80211_tdls_add_link_ie(struct sk_buff *skb, const u8 *src_addr, | 72 | static void ieee80211_tdls_add_link_ie(struct ieee80211_sub_if_data *sdata, |
| 44 | const u8 *peer, const u8 *bssid) | 73 | struct sk_buff *skb, const u8 *peer, |
| 74 | bool initiator) | ||
| 45 | { | 75 | { |
| 46 | struct ieee80211_tdls_lnkie *lnkid; | 76 | struct ieee80211_tdls_lnkie *lnkid; |
| 77 | const u8 *init_addr, *rsp_addr; | ||
| 78 | |||
| 79 | if (initiator) { | ||
| 80 | init_addr = sdata->vif.addr; | ||
| 81 | rsp_addr = peer; | ||
| 82 | } else { | ||
| 83 | init_addr = peer; | ||
| 84 | rsp_addr = sdata->vif.addr; | ||
| 85 | } | ||
| 47 | 86 | ||
| 48 | lnkid = (void *)skb_put(skb, sizeof(struct ieee80211_tdls_lnkie)); | 87 | lnkid = (void *)skb_put(skb, sizeof(struct ieee80211_tdls_lnkie)); |
| 49 | 88 | ||
| 50 | lnkid->ie_type = WLAN_EID_LINK_ID; | 89 | lnkid->ie_type = WLAN_EID_LINK_ID; |
| 51 | lnkid->ie_len = sizeof(struct ieee80211_tdls_lnkie) - 2; | 90 | lnkid->ie_len = sizeof(struct ieee80211_tdls_lnkie) - 2; |
| 52 | 91 | ||
| 53 | memcpy(lnkid->bssid, bssid, ETH_ALEN); | 92 | memcpy(lnkid->bssid, sdata->u.mgd.bssid, ETH_ALEN); |
| 54 | memcpy(lnkid->init_sta, src_addr, ETH_ALEN); | 93 | memcpy(lnkid->init_sta, init_addr, ETH_ALEN); |
| 55 | memcpy(lnkid->resp_sta, peer, ETH_ALEN); | 94 | memcpy(lnkid->resp_sta, rsp_addr, ETH_ALEN); |
| 95 | } | ||
| 96 | |||
| 97 | /* translate numbering in the WMM parameter IE to the mac80211 notation */ | ||
| 98 | static enum ieee80211_ac_numbers ieee80211_ac_from_wmm(int ac) | ||
| 99 | { | ||
| 100 | switch (ac) { | ||
| 101 | default: | ||
| 102 | WARN_ON_ONCE(1); | ||
| 103 | case 0: | ||
| 104 | return IEEE80211_AC_BE; | ||
| 105 | case 1: | ||
| 106 | return IEEE80211_AC_BK; | ||
| 107 | case 2: | ||
| 108 | return IEEE80211_AC_VI; | ||
| 109 | case 3: | ||
| 110 | return IEEE80211_AC_VO; | ||
| 111 | } | ||
| 112 | } | ||
| 113 | |||
| 114 | static u8 ieee80211_wmm_aci_aifsn(int aifsn, bool acm, int aci) | ||
| 115 | { | ||
| 116 | u8 ret; | ||
| 117 | |||
| 118 | ret = aifsn & 0x0f; | ||
| 119 | if (acm) | ||
| 120 | ret |= 0x10; | ||
| 121 | ret |= (aci << 5) & 0x60; | ||
| 122 | return ret; | ||
| 123 | } | ||
| 124 | |||
| 125 | static u8 ieee80211_wmm_ecw(u16 cw_min, u16 cw_max) | ||
| 126 | { | ||
| 127 | return ((ilog2(cw_min + 1) << 0x0) & 0x0f) | | ||
| 128 | ((ilog2(cw_max + 1) << 0x4) & 0xf0); | ||
| 129 | } | ||
| 130 | |||
| 131 | static void ieee80211_tdls_add_wmm_param_ie(struct ieee80211_sub_if_data *sdata, | ||
| 132 | struct sk_buff *skb) | ||
| 133 | { | ||
| 134 | struct ieee80211_wmm_param_ie *wmm; | ||
| 135 | struct ieee80211_tx_queue_params *txq; | ||
| 136 | int i; | ||
| 137 | |||
| 138 | wmm = (void *)skb_put(skb, sizeof(*wmm)); | ||
| 139 | memset(wmm, 0, sizeof(*wmm)); | ||
| 140 | |||
| 141 | wmm->element_id = WLAN_EID_VENDOR_SPECIFIC; | ||
| 142 | wmm->len = sizeof(*wmm) - 2; | ||
| 143 | |||
| 144 | wmm->oui[0] = 0x00; /* Microsoft OUI 00:50:F2 */ | ||
| 145 | wmm->oui[1] = 0x50; | ||
| 146 | wmm->oui[2] = 0xf2; | ||
| 147 | wmm->oui_type = 2; /* WME */ | ||
| 148 | wmm->oui_subtype = 1; /* WME param */ | ||
| 149 | wmm->version = 1; /* WME ver */ | ||
| 150 | wmm->qos_info = 0; /* U-APSD not in use */ | ||
| 151 | |||
| 152 | /* | ||
| 153 | * Use the EDCA parameters defined for the BSS, or default if the AP | ||
| 154 | * doesn't support it, as mandated by 802.11-2012 section 10.22.4 | ||
| 155 | */ | ||
| 156 | for (i = 0; i < IEEE80211_NUM_ACS; i++) { | ||
| 157 | txq = &sdata->tx_conf[ieee80211_ac_from_wmm(i)]; | ||
| 158 | wmm->ac[i].aci_aifsn = ieee80211_wmm_aci_aifsn(txq->aifs, | ||
| 159 | txq->acm, i); | ||
| 160 | wmm->ac[i].cw = ieee80211_wmm_ecw(txq->cw_min, txq->cw_max); | ||
| 161 | wmm->ac[i].txop_limit = cpu_to_le16(txq->txop); | ||
| 162 | } | ||
| 163 | } | ||
| 164 | |||
| 165 | static void | ||
| 166 | ieee80211_tdls_add_setup_start_ies(struct ieee80211_sub_if_data *sdata, | ||
| 167 | struct sk_buff *skb, const u8 *peer, | ||
| 168 | u8 action_code, bool initiator, | ||
| 169 | const u8 *extra_ies, size_t extra_ies_len) | ||
| 170 | { | ||
| 171 | enum ieee80211_band band = ieee80211_get_sdata_band(sdata); | ||
| 172 | struct ieee80211_local *local = sdata->local; | ||
| 173 | struct ieee80211_supported_band *sband; | ||
| 174 | struct ieee80211_sta_ht_cap ht_cap; | ||
| 175 | struct sta_info *sta = NULL; | ||
| 176 | size_t offset = 0, noffset; | ||
| 177 | u8 *pos; | ||
| 178 | |||
| 179 | rcu_read_lock(); | ||
| 180 | |||
| 181 | /* we should have the peer STA if we're already responding */ | ||
| 182 | if (action_code == WLAN_TDLS_SETUP_RESPONSE) { | ||
| 183 | sta = sta_info_get(sdata, peer); | ||
| 184 | if (WARN_ON_ONCE(!sta)) { | ||
| 185 | rcu_read_unlock(); | ||
| 186 | return; | ||
| 187 | } | ||
| 188 | } | ||
| 189 | |||
| 190 | ieee80211_add_srates_ie(sdata, skb, false, band); | ||
| 191 | ieee80211_add_ext_srates_ie(sdata, skb, false, band); | ||
| 192 | |||
| 193 | /* add any custom IEs that go before Extended Capabilities */ | ||
| 194 | if (extra_ies_len) { | ||
| 195 | static const u8 before_ext_cap[] = { | ||
| 196 | WLAN_EID_SUPP_RATES, | ||
| 197 | WLAN_EID_COUNTRY, | ||
| 198 | WLAN_EID_EXT_SUPP_RATES, | ||
| 199 | WLAN_EID_SUPPORTED_CHANNELS, | ||
| 200 | WLAN_EID_RSN, | ||
| 201 | }; | ||
| 202 | noffset = ieee80211_ie_split(extra_ies, extra_ies_len, | ||
| 203 | before_ext_cap, | ||
| 204 | ARRAY_SIZE(before_ext_cap), | ||
| 205 | offset); | ||
| 206 | pos = skb_put(skb, noffset - offset); | ||
| 207 | memcpy(pos, extra_ies + offset, noffset - offset); | ||
| 208 | offset = noffset; | ||
| 209 | } | ||
| 210 | |||
| 211 | ieee80211_tdls_add_ext_capab(skb); | ||
| 212 | |||
| 213 | /* add the QoS element if we support it */ | ||
| 214 | if (local->hw.queues >= IEEE80211_NUM_ACS && | ||
| 215 | action_code != WLAN_PUB_ACTION_TDLS_DISCOVER_RES) | ||
| 216 | ieee80211_add_wmm_info_ie(skb_put(skb, 9), 0); /* no U-APSD */ | ||
| 217 | |||
| 218 | /* add any custom IEs that go before HT capabilities */ | ||
| 219 | if (extra_ies_len) { | ||
| 220 | static const u8 before_ht_cap[] = { | ||
| 221 | WLAN_EID_SUPP_RATES, | ||
| 222 | WLAN_EID_COUNTRY, | ||
| 223 | WLAN_EID_EXT_SUPP_RATES, | ||
| 224 | WLAN_EID_SUPPORTED_CHANNELS, | ||
| 225 | WLAN_EID_RSN, | ||
| 226 | WLAN_EID_EXT_CAPABILITY, | ||
| 227 | WLAN_EID_QOS_CAPA, | ||
| 228 | WLAN_EID_FAST_BSS_TRANSITION, | ||
| 229 | WLAN_EID_TIMEOUT_INTERVAL, | ||
| 230 | WLAN_EID_SUPPORTED_REGULATORY_CLASSES, | ||
| 231 | }; | ||
| 232 | noffset = ieee80211_ie_split(extra_ies, extra_ies_len, | ||
| 233 | before_ht_cap, | ||
| 234 | ARRAY_SIZE(before_ht_cap), | ||
| 235 | offset); | ||
| 236 | pos = skb_put(skb, noffset - offset); | ||
| 237 | memcpy(pos, extra_ies + offset, noffset - offset); | ||
| 238 | offset = noffset; | ||
| 239 | } | ||
| 240 | |||
| 241 | /* | ||
| 242 | * with TDLS we can switch channels, and HT-caps are not necessarily | ||
| 243 | * the same on all bands. The specification limits the setup to a | ||
| 244 | * single HT-cap, so use the current band for now. | ||
| 245 | */ | ||
| 246 | sband = local->hw.wiphy->bands[band]; | ||
| 247 | memcpy(&ht_cap, &sband->ht_cap, sizeof(ht_cap)); | ||
| 248 | if ((action_code == WLAN_TDLS_SETUP_REQUEST || | ||
| 249 | action_code == WLAN_TDLS_SETUP_RESPONSE) && | ||
| 250 | ht_cap.ht_supported && (!sta || sta->sta.ht_cap.ht_supported)) { | ||
| 251 | if (action_code == WLAN_TDLS_SETUP_REQUEST) { | ||
| 252 | ieee80211_apply_htcap_overrides(sdata, &ht_cap); | ||
| 253 | |||
| 254 | /* disable SMPS in TDLS initiator */ | ||
| 255 | ht_cap.cap |= (WLAN_HT_CAP_SM_PS_DISABLED | ||
| 256 | << IEEE80211_HT_CAP_SM_PS_SHIFT); | ||
| 257 | } else { | ||
| 258 | /* disable SMPS in TDLS responder */ | ||
| 259 | sta->sta.ht_cap.cap |= | ||
| 260 | (WLAN_HT_CAP_SM_PS_DISABLED | ||
| 261 | << IEEE80211_HT_CAP_SM_PS_SHIFT); | ||
| 262 | |||
| 263 | /* the peer caps are already intersected with our own */ | ||
| 264 | memcpy(&ht_cap, &sta->sta.ht_cap, sizeof(ht_cap)); | ||
| 265 | } | ||
| 266 | |||
| 267 | pos = skb_put(skb, sizeof(struct ieee80211_ht_cap) + 2); | ||
| 268 | ieee80211_ie_build_ht_cap(pos, &ht_cap, ht_cap.cap); | ||
| 269 | } | ||
| 270 | |||
| 271 | rcu_read_unlock(); | ||
| 272 | |||
| 273 | /* add any remaining IEs */ | ||
| 274 | if (extra_ies_len) { | ||
| 275 | noffset = extra_ies_len; | ||
| 276 | pos = skb_put(skb, noffset - offset); | ||
| 277 | memcpy(pos, extra_ies + offset, noffset - offset); | ||
| 278 | } | ||
| 279 | |||
| 280 | ieee80211_tdls_add_link_ie(sdata, skb, peer, initiator); | ||
| 281 | } | ||
| 282 | |||
| 283 | static void | ||
| 284 | ieee80211_tdls_add_setup_cfm_ies(struct ieee80211_sub_if_data *sdata, | ||
| 285 | struct sk_buff *skb, const u8 *peer, | ||
| 286 | bool initiator, const u8 *extra_ies, | ||
| 287 | size_t extra_ies_len) | ||
| 288 | { | ||
| 289 | struct ieee80211_local *local = sdata->local; | ||
| 290 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; | ||
| 291 | size_t offset = 0, noffset; | ||
| 292 | struct sta_info *sta, *ap_sta; | ||
| 293 | u8 *pos; | ||
| 294 | |||
| 295 | rcu_read_lock(); | ||
| 296 | |||
| 297 | sta = sta_info_get(sdata, peer); | ||
| 298 | ap_sta = sta_info_get(sdata, ifmgd->bssid); | ||
| 299 | if (WARN_ON_ONCE(!sta || !ap_sta)) { | ||
| 300 | rcu_read_unlock(); | ||
| 301 | return; | ||
| 302 | } | ||
| 303 | |||
| 304 | /* add any custom IEs that go before the QoS IE */ | ||
| 305 | if (extra_ies_len) { | ||
| 306 | static const u8 before_qos[] = { | ||
| 307 | WLAN_EID_RSN, | ||
| 308 | }; | ||
| 309 | noffset = ieee80211_ie_split(extra_ies, extra_ies_len, | ||
| 310 | before_qos, | ||
| 311 | ARRAY_SIZE(before_qos), | ||
| 312 | offset); | ||
| 313 | pos = skb_put(skb, noffset - offset); | ||
| 314 | memcpy(pos, extra_ies + offset, noffset - offset); | ||
| 315 | offset = noffset; | ||
| 316 | } | ||
| 317 | |||
| 318 | /* add the QoS param IE if both the peer and we support it */ | ||
| 319 | if (local->hw.queues >= IEEE80211_NUM_ACS && | ||
| 320 | test_sta_flag(sta, WLAN_STA_WME)) | ||
| 321 | ieee80211_tdls_add_wmm_param_ie(sdata, skb); | ||
| 322 | |||
| 323 | /* add any custom IEs that go before HT operation */ | ||
| 324 | if (extra_ies_len) { | ||
| 325 | static const u8 before_ht_op[] = { | ||
| 326 | WLAN_EID_RSN, | ||
| 327 | WLAN_EID_QOS_CAPA, | ||
| 328 | WLAN_EID_FAST_BSS_TRANSITION, | ||
| 329 | WLAN_EID_TIMEOUT_INTERVAL, | ||
| 330 | }; | ||
| 331 | noffset = ieee80211_ie_split(extra_ies, extra_ies_len, | ||
| 332 | before_ht_op, | ||
| 333 | ARRAY_SIZE(before_ht_op), | ||
| 334 | offset); | ||
| 335 | pos = skb_put(skb, noffset - offset); | ||
| 336 | memcpy(pos, extra_ies + offset, noffset - offset); | ||
| 337 | offset = noffset; | ||
| 338 | } | ||
| 339 | |||
| 340 | /* if HT support is only added in TDLS, we need an HT-operation IE */ | ||
| 341 | if (!ap_sta->sta.ht_cap.ht_supported && sta->sta.ht_cap.ht_supported) { | ||
| 342 | struct ieee80211_chanctx_conf *chanctx_conf = | ||
| 343 | rcu_dereference(sdata->vif.chanctx_conf); | ||
| 344 | if (!WARN_ON(!chanctx_conf)) { | ||
| 345 | pos = skb_put(skb, 2 + | ||
| 346 | sizeof(struct ieee80211_ht_operation)); | ||
| 347 | /* send an empty HT operation IE */ | ||
| 348 | ieee80211_ie_build_ht_oper(pos, &sta->sta.ht_cap, | ||
| 349 | &chanctx_conf->def, 0); | ||
| 350 | } | ||
| 351 | } | ||
| 352 | |||
| 353 | rcu_read_unlock(); | ||
| 354 | |||
| 355 | /* add any remaining IEs */ | ||
| 356 | if (extra_ies_len) { | ||
| 357 | noffset = extra_ies_len; | ||
| 358 | pos = skb_put(skb, noffset - offset); | ||
| 359 | memcpy(pos, extra_ies + offset, noffset - offset); | ||
| 360 | } | ||
| 361 | |||
| 362 | ieee80211_tdls_add_link_ie(sdata, skb, peer, initiator); | ||
| 363 | } | ||
| 364 | |||
| 365 | static void ieee80211_tdls_add_ies(struct ieee80211_sub_if_data *sdata, | ||
| 366 | struct sk_buff *skb, const u8 *peer, | ||
| 367 | u8 action_code, u16 status_code, | ||
| 368 | bool initiator, const u8 *extra_ies, | ||
| 369 | size_t extra_ies_len) | ||
| 370 | { | ||
| 371 | switch (action_code) { | ||
| 372 | case WLAN_TDLS_SETUP_REQUEST: | ||
| 373 | case WLAN_TDLS_SETUP_RESPONSE: | ||
| 374 | case WLAN_PUB_ACTION_TDLS_DISCOVER_RES: | ||
| 375 | if (status_code == 0) | ||
| 376 | ieee80211_tdls_add_setup_start_ies(sdata, skb, peer, | ||
| 377 | action_code, | ||
| 378 | initiator, | ||
| 379 | extra_ies, | ||
| 380 | extra_ies_len); | ||
| 381 | break; | ||
| 382 | case WLAN_TDLS_SETUP_CONFIRM: | ||
| 383 | if (status_code == 0) | ||
| 384 | ieee80211_tdls_add_setup_cfm_ies(sdata, skb, peer, | ||
| 385 | initiator, extra_ies, | ||
| 386 | extra_ies_len); | ||
| 387 | break; | ||
| 388 | case WLAN_TDLS_TEARDOWN: | ||
| 389 | case WLAN_TDLS_DISCOVERY_REQUEST: | ||
| 390 | if (extra_ies_len) | ||
| 391 | memcpy(skb_put(skb, extra_ies_len), extra_ies, | ||
| 392 | extra_ies_len); | ||
| 393 | if (status_code == 0 || action_code == WLAN_TDLS_TEARDOWN) | ||
| 394 | ieee80211_tdls_add_link_ie(sdata, skb, peer, initiator); | ||
| 395 | break; | ||
| 396 | } | ||
| 397 | |||
| 56 | } | 398 | } |
| 57 | 399 | ||
| 58 | static int | 400 | static int |
| @@ -61,7 +403,6 @@ ieee80211_prep_tdls_encap_data(struct wiphy *wiphy, struct net_device *dev, | |||
| 61 | u16 status_code, struct sk_buff *skb) | 403 | u16 status_code, struct sk_buff *skb) |
| 62 | { | 404 | { |
| 63 | struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); | 405 | struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); |
| 64 | enum ieee80211_band band = ieee80211_get_sdata_band(sdata); | ||
| 65 | struct ieee80211_tdls_data *tf; | 406 | struct ieee80211_tdls_data *tf; |
| 66 | 407 | ||
| 67 | tf = (void *)skb_put(skb, offsetof(struct ieee80211_tdls_data, u)); | 408 | tf = (void *)skb_put(skb, offsetof(struct ieee80211_tdls_data, u)); |
| @@ -79,11 +420,8 @@ ieee80211_prep_tdls_encap_data(struct wiphy *wiphy, struct net_device *dev, | |||
| 79 | skb_put(skb, sizeof(tf->u.setup_req)); | 420 | skb_put(skb, sizeof(tf->u.setup_req)); |
| 80 | tf->u.setup_req.dialog_token = dialog_token; | 421 | tf->u.setup_req.dialog_token = dialog_token; |
| 81 | tf->u.setup_req.capability = | 422 | tf->u.setup_req.capability = |
| 82 | cpu_to_le16(ieee80211_get_tdls_sta_capab(sdata)); | 423 | cpu_to_le16(ieee80211_get_tdls_sta_capab(sdata, |
| 83 | 424 | status_code)); | |
| 84 | ieee80211_add_srates_ie(sdata, skb, false, band); | ||
| 85 | ieee80211_add_ext_srates_ie(sdata, skb, false, band); | ||
| 86 | ieee80211_tdls_add_ext_capab(skb); | ||
| 87 | break; | 425 | break; |
| 88 | case WLAN_TDLS_SETUP_RESPONSE: | 426 | case WLAN_TDLS_SETUP_RESPONSE: |
| 89 | tf->category = WLAN_CATEGORY_TDLS; | 427 | tf->category = WLAN_CATEGORY_TDLS; |
| @@ -93,11 +431,8 @@ ieee80211_prep_tdls_encap_data(struct wiphy *wiphy, struct net_device *dev, | |||
| 93 | tf->u.setup_resp.status_code = cpu_to_le16(status_code); | 431 | tf->u.setup_resp.status_code = cpu_to_le16(status_code); |
| 94 | tf->u.setup_resp.dialog_token = dialog_token; | 432 | tf->u.setup_resp.dialog_token = dialog_token; |
| 95 | tf->u.setup_resp.capability = | 433 | tf->u.setup_resp.capability = |
| 96 | cpu_to_le16(ieee80211_get_tdls_sta_capab(sdata)); | 434 | cpu_to_le16(ieee80211_get_tdls_sta_capab(sdata, |
| 97 | 435 | status_code)); | |
| 98 | ieee80211_add_srates_ie(sdata, skb, false, band); | ||
| 99 | ieee80211_add_ext_srates_ie(sdata, skb, false, band); | ||
| 100 | ieee80211_tdls_add_ext_capab(skb); | ||
| 101 | break; | 436 | break; |
| 102 | case WLAN_TDLS_SETUP_CONFIRM: | 437 | case WLAN_TDLS_SETUP_CONFIRM: |
| 103 | tf->category = WLAN_CATEGORY_TDLS; | 438 | tf->category = WLAN_CATEGORY_TDLS; |
| @@ -134,7 +469,6 @@ ieee80211_prep_tdls_direct(struct wiphy *wiphy, struct net_device *dev, | |||
| 134 | u16 status_code, struct sk_buff *skb) | 469 | u16 status_code, struct sk_buff *skb) |
| 135 | { | 470 | { |
| 136 | struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); | 471 | struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); |
| 137 | enum ieee80211_band band = ieee80211_get_sdata_band(sdata); | ||
| 138 | struct ieee80211_mgmt *mgmt; | 472 | struct ieee80211_mgmt *mgmt; |
| 139 | 473 | ||
| 140 | mgmt = (void *)skb_put(skb, 24); | 474 | mgmt = (void *)skb_put(skb, 24); |
| @@ -155,11 +489,8 @@ ieee80211_prep_tdls_direct(struct wiphy *wiphy, struct net_device *dev, | |||
| 155 | mgmt->u.action.u.tdls_discover_resp.dialog_token = | 489 | mgmt->u.action.u.tdls_discover_resp.dialog_token = |
| 156 | dialog_token; | 490 | dialog_token; |
| 157 | mgmt->u.action.u.tdls_discover_resp.capability = | 491 | mgmt->u.action.u.tdls_discover_resp.capability = |
| 158 | cpu_to_le16(ieee80211_get_tdls_sta_capab(sdata)); | 492 | cpu_to_le16(ieee80211_get_tdls_sta_capab(sdata, |
| 159 | 493 | status_code)); | |
| 160 | ieee80211_add_srates_ie(sdata, skb, false, band); | ||
| 161 | ieee80211_add_ext_srates_ie(sdata, skb, false, band); | ||
| 162 | ieee80211_tdls_add_ext_capab(skb); | ||
| 163 | break; | 494 | break; |
| 164 | default: | 495 | default: |
| 165 | return -EINVAL; | 496 | return -EINVAL; |
| @@ -168,33 +499,28 @@ ieee80211_prep_tdls_direct(struct wiphy *wiphy, struct net_device *dev, | |||
| 168 | return 0; | 499 | return 0; |
| 169 | } | 500 | } |
| 170 | 501 | ||
| 171 | int ieee80211_tdls_mgmt(struct wiphy *wiphy, struct net_device *dev, | 502 | static int |
| 172 | const u8 *peer, u8 action_code, u8 dialog_token, | 503 | ieee80211_tdls_prep_mgmt_packet(struct wiphy *wiphy, struct net_device *dev, |
| 173 | u16 status_code, u32 peer_capability, | 504 | const u8 *peer, u8 action_code, |
| 174 | const u8 *extra_ies, size_t extra_ies_len) | 505 | u8 dialog_token, u16 status_code, |
| 506 | u32 peer_capability, bool initiator, | ||
| 507 | const u8 *extra_ies, size_t extra_ies_len) | ||
| 175 | { | 508 | { |
| 176 | struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); | 509 | struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); |
| 177 | struct ieee80211_local *local = sdata->local; | 510 | struct ieee80211_local *local = sdata->local; |
| 178 | struct sk_buff *skb = NULL; | 511 | struct sk_buff *skb = NULL; |
| 179 | bool send_direct; | 512 | bool send_direct; |
| 513 | struct sta_info *sta; | ||
| 180 | int ret; | 514 | int ret; |
| 181 | 515 | ||
| 182 | if (!(wiphy->flags & WIPHY_FLAG_SUPPORTS_TDLS)) | ||
| 183 | return -ENOTSUPP; | ||
| 184 | |||
| 185 | /* make sure we are in managed mode, and associated */ | ||
| 186 | if (sdata->vif.type != NL80211_IFTYPE_STATION || | ||
| 187 | !sdata->u.mgd.associated) | ||
| 188 | return -EINVAL; | ||
| 189 | |||
| 190 | tdls_dbg(sdata, "TDLS mgmt action %d peer %pM\n", | ||
| 191 | action_code, peer); | ||
| 192 | |||
| 193 | skb = dev_alloc_skb(local->hw.extra_tx_headroom + | 516 | skb = dev_alloc_skb(local->hw.extra_tx_headroom + |
| 194 | max(sizeof(struct ieee80211_mgmt), | 517 | max(sizeof(struct ieee80211_mgmt), |
| 195 | sizeof(struct ieee80211_tdls_data)) + | 518 | sizeof(struct ieee80211_tdls_data)) + |
| 196 | 50 + /* supported rates */ | 519 | 50 + /* supported rates */ |
| 197 | 7 + /* ext capab */ | 520 | 7 + /* ext capab */ |
| 521 | 26 + /* max(WMM-info, WMM-param) */ | ||
| 522 | 2 + max(sizeof(struct ieee80211_ht_cap), | ||
| 523 | sizeof(struct ieee80211_ht_operation)) + | ||
| 198 | extra_ies_len + | 524 | extra_ies_len + |
| 199 | sizeof(struct ieee80211_tdls_lnkie)); | 525 | sizeof(struct ieee80211_tdls_lnkie)); |
| 200 | if (!skb) | 526 | if (!skb) |
| @@ -227,30 +553,48 @@ int ieee80211_tdls_mgmt(struct wiphy *wiphy, struct net_device *dev, | |||
| 227 | if (ret < 0) | 553 | if (ret < 0) |
| 228 | goto fail; | 554 | goto fail; |
| 229 | 555 | ||
| 230 | if (extra_ies_len) | 556 | rcu_read_lock(); |
| 231 | memcpy(skb_put(skb, extra_ies_len), extra_ies, extra_ies_len); | 557 | sta = sta_info_get(sdata, peer); |
| 232 | 558 | ||
| 233 | /* the TDLS link IE is always added last */ | 559 | /* infer the initiator if we can, to support old userspace */ |
| 234 | switch (action_code) { | 560 | switch (action_code) { |
| 235 | case WLAN_TDLS_SETUP_REQUEST: | 561 | case WLAN_TDLS_SETUP_REQUEST: |
| 562 | if (sta) | ||
| 563 | set_sta_flag(sta, WLAN_STA_TDLS_INITIATOR); | ||
| 564 | /* fall-through */ | ||
| 236 | case WLAN_TDLS_SETUP_CONFIRM: | 565 | case WLAN_TDLS_SETUP_CONFIRM: |
| 237 | case WLAN_TDLS_TEARDOWN: | ||
| 238 | case WLAN_TDLS_DISCOVERY_REQUEST: | 566 | case WLAN_TDLS_DISCOVERY_REQUEST: |
| 239 | /* we are the initiator */ | 567 | initiator = true; |
| 240 | ieee80211_tdls_add_link_ie(skb, sdata->vif.addr, peer, | ||
| 241 | sdata->u.mgd.bssid); | ||
| 242 | break; | 568 | break; |
| 243 | case WLAN_TDLS_SETUP_RESPONSE: | 569 | case WLAN_TDLS_SETUP_RESPONSE: |
| 570 | /* | ||
| 571 | * In some testing scenarios, we send a request and response. | ||
| 572 | * Make the last packet sent take effect for the initiator | ||
| 573 | * value. | ||
| 574 | */ | ||
| 575 | if (sta) | ||
| 576 | clear_sta_flag(sta, WLAN_STA_TDLS_INITIATOR); | ||
| 577 | /* fall-through */ | ||
| 244 | case WLAN_PUB_ACTION_TDLS_DISCOVER_RES: | 578 | case WLAN_PUB_ACTION_TDLS_DISCOVER_RES: |
| 245 | /* we are the responder */ | 579 | initiator = false; |
| 246 | ieee80211_tdls_add_link_ie(skb, peer, sdata->vif.addr, | 580 | break; |
| 247 | sdata->u.mgd.bssid); | 581 | case WLAN_TDLS_TEARDOWN: |
| 582 | /* any value is ok */ | ||
| 248 | break; | 583 | break; |
| 249 | default: | 584 | default: |
| 250 | ret = -ENOTSUPP; | 585 | ret = -ENOTSUPP; |
| 251 | goto fail; | 586 | break; |
| 252 | } | 587 | } |
| 253 | 588 | ||
| 589 | if (sta && test_sta_flag(sta, WLAN_STA_TDLS_INITIATOR)) | ||
| 590 | initiator = true; | ||
| 591 | |||
| 592 | rcu_read_unlock(); | ||
| 593 | if (ret < 0) | ||
| 594 | goto fail; | ||
| 595 | |||
| 596 | ieee80211_tdls_add_ies(sdata, skb, peer, action_code, status_code, | ||
| 597 | initiator, extra_ies, extra_ies_len); | ||
| 254 | if (send_direct) { | 598 | if (send_direct) { |
| 255 | ieee80211_tx_skb(sdata, skb); | 599 | ieee80211_tx_skb(sdata, skb); |
| 256 | return 0; | 600 | return 0; |
| @@ -284,11 +628,175 @@ fail: | |||
| 284 | return ret; | 628 | return ret; |
| 285 | } | 629 | } |
| 286 | 630 | ||
| 631 | static int | ||
| 632 | ieee80211_tdls_mgmt_setup(struct wiphy *wiphy, struct net_device *dev, | ||
| 633 | const u8 *peer, u8 action_code, u8 dialog_token, | ||
| 634 | u16 status_code, u32 peer_capability, bool initiator, | ||
| 635 | const u8 *extra_ies, size_t extra_ies_len) | ||
| 636 | { | ||
| 637 | struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); | ||
| 638 | struct ieee80211_local *local = sdata->local; | ||
| 639 | int ret; | ||
| 640 | |||
| 641 | mutex_lock(&local->mtx); | ||
| 642 | |||
| 643 | /* we don't support concurrent TDLS peer setups */ | ||
| 644 | if (!is_zero_ether_addr(sdata->u.mgd.tdls_peer) && | ||
| 645 | !ether_addr_equal(sdata->u.mgd.tdls_peer, peer)) { | ||
| 646 | ret = -EBUSY; | ||
| 647 | goto exit; | ||
| 648 | } | ||
| 649 | |||
| 650 | /* | ||
| 651 | * make sure we have a STA representing the peer so we drop or buffer | ||
| 652 | * non-TDLS-setup frames to the peer. We can't send other packets | ||
| 653 | * during setup through the AP path. | ||
| 654 | * Allow error packets to be sent - sometimes we don't even add a STA | ||
| 655 | * before failing the setup. | ||
| 656 | */ | ||
| 657 | if (status_code == 0) { | ||
| 658 | rcu_read_lock(); | ||
| 659 | if (!sta_info_get(sdata, peer)) { | ||
| 660 | rcu_read_unlock(); | ||
| 661 | ret = -ENOLINK; | ||
| 662 | goto exit; | ||
| 663 | } | ||
| 664 | rcu_read_unlock(); | ||
| 665 | } | ||
| 666 | |||
| 667 | ieee80211_flush_queues(local, sdata); | ||
| 668 | |||
| 669 | ret = ieee80211_tdls_prep_mgmt_packet(wiphy, dev, peer, action_code, | ||
| 670 | dialog_token, status_code, | ||
| 671 | peer_capability, initiator, | ||
| 672 | extra_ies, extra_ies_len); | ||
| 673 | if (ret < 0) | ||
| 674 | goto exit; | ||
| 675 | |||
| 676 | memcpy(sdata->u.mgd.tdls_peer, peer, ETH_ALEN); | ||
| 677 | ieee80211_queue_delayed_work(&sdata->local->hw, | ||
| 678 | &sdata->u.mgd.tdls_peer_del_work, | ||
| 679 | TDLS_PEER_SETUP_TIMEOUT); | ||
| 680 | |||
| 681 | exit: | ||
| 682 | mutex_unlock(&local->mtx); | ||
| 683 | return ret; | ||
| 684 | } | ||
| 685 | |||
| 686 | static int | ||
| 687 | ieee80211_tdls_mgmt_teardown(struct wiphy *wiphy, struct net_device *dev, | ||
| 688 | const u8 *peer, u8 action_code, u8 dialog_token, | ||
| 689 | u16 status_code, u32 peer_capability, | ||
| 690 | bool initiator, const u8 *extra_ies, | ||
| 691 | size_t extra_ies_len) | ||
| 692 | { | ||
| 693 | struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); | ||
| 694 | struct ieee80211_local *local = sdata->local; | ||
| 695 | struct sta_info *sta; | ||
| 696 | int ret; | ||
| 697 | |||
| 698 | /* | ||
| 699 | * No packets can be transmitted to the peer via the AP during setup - | ||
| 700 | * the STA is set as a TDLS peer, but is not authorized. | ||
| 701 | * During teardown, we prevent direct transmissions by stopping the | ||
| 702 | * queues and flushing all direct packets. | ||
| 703 | */ | ||
| 704 | ieee80211_stop_vif_queues(local, sdata, | ||
| 705 | IEEE80211_QUEUE_STOP_REASON_TDLS_TEARDOWN); | ||
| 706 | ieee80211_flush_queues(local, sdata); | ||
| 707 | |||
| 708 | ret = ieee80211_tdls_prep_mgmt_packet(wiphy, dev, peer, action_code, | ||
| 709 | dialog_token, status_code, | ||
| 710 | peer_capability, initiator, | ||
| 711 | extra_ies, extra_ies_len); | ||
| 712 | if (ret < 0) | ||
| 713 | sdata_err(sdata, "Failed sending TDLS teardown packet %d\n", | ||
| 714 | ret); | ||
| 715 | |||
| 716 | /* | ||
| 717 | * Remove the STA AUTH flag to force further traffic through the AP. If | ||
| 718 | * the STA was unreachable, it was already removed. | ||
| 719 | */ | ||
| 720 | rcu_read_lock(); | ||
| 721 | sta = sta_info_get(sdata, peer); | ||
| 722 | if (sta) | ||
| 723 | clear_sta_flag(sta, WLAN_STA_TDLS_PEER_AUTH); | ||
| 724 | rcu_read_unlock(); | ||
| 725 | |||
| 726 | ieee80211_wake_vif_queues(local, sdata, | ||
| 727 | IEEE80211_QUEUE_STOP_REASON_TDLS_TEARDOWN); | ||
| 728 | |||
| 729 | return 0; | ||
| 730 | } | ||
| 731 | |||
| 732 | int ieee80211_tdls_mgmt(struct wiphy *wiphy, struct net_device *dev, | ||
| 733 | const u8 *peer, u8 action_code, u8 dialog_token, | ||
| 734 | u16 status_code, u32 peer_capability, | ||
| 735 | bool initiator, const u8 *extra_ies, | ||
| 736 | size_t extra_ies_len) | ||
| 737 | { | ||
| 738 | struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); | ||
| 739 | int ret; | ||
| 740 | |||
| 741 | if (!(wiphy->flags & WIPHY_FLAG_SUPPORTS_TDLS)) | ||
| 742 | return -ENOTSUPP; | ||
| 743 | |||
| 744 | /* make sure we are in managed mode, and associated */ | ||
| 745 | if (sdata->vif.type != NL80211_IFTYPE_STATION || | ||
| 746 | !sdata->u.mgd.associated) | ||
| 747 | return -EINVAL; | ||
| 748 | |||
| 749 | switch (action_code) { | ||
| 750 | case WLAN_TDLS_SETUP_REQUEST: | ||
| 751 | case WLAN_TDLS_SETUP_RESPONSE: | ||
| 752 | ret = ieee80211_tdls_mgmt_setup(wiphy, dev, peer, action_code, | ||
| 753 | dialog_token, status_code, | ||
| 754 | peer_capability, initiator, | ||
| 755 | extra_ies, extra_ies_len); | ||
| 756 | break; | ||
| 757 | case WLAN_TDLS_TEARDOWN: | ||
| 758 | ret = ieee80211_tdls_mgmt_teardown(wiphy, dev, peer, | ||
| 759 | action_code, dialog_token, | ||
| 760 | status_code, | ||
| 761 | peer_capability, initiator, | ||
| 762 | extra_ies, extra_ies_len); | ||
| 763 | break; | ||
| 764 | case WLAN_TDLS_DISCOVERY_REQUEST: | ||
| 765 | /* | ||
| 766 | * Protect the discovery so we can hear the TDLS discovery | ||
| 767 | * response frame. It is transmitted directly and not buffered | ||
| 768 | * by the AP. | ||
| 769 | */ | ||
| 770 | drv_mgd_protect_tdls_discover(sdata->local, sdata); | ||
| 771 | /* fall-through */ | ||
| 772 | case WLAN_TDLS_SETUP_CONFIRM: | ||
| 773 | case WLAN_PUB_ACTION_TDLS_DISCOVER_RES: | ||
| 774 | /* no special handling */ | ||
| 775 | ret = ieee80211_tdls_prep_mgmt_packet(wiphy, dev, peer, | ||
| 776 | action_code, | ||
| 777 | dialog_token, | ||
| 778 | status_code, | ||
| 779 | peer_capability, | ||
| 780 | initiator, extra_ies, | ||
| 781 | extra_ies_len); | ||
| 782 | break; | ||
| 783 | default: | ||
| 784 | ret = -EOPNOTSUPP; | ||
| 785 | break; | ||
| 786 | } | ||
| 787 | |||
| 788 | tdls_dbg(sdata, "TDLS mgmt action %d peer %pM status %d\n", | ||
| 789 | action_code, peer, ret); | ||
| 790 | return ret; | ||
| 791 | } | ||
| 792 | |||
| 287 | int ieee80211_tdls_oper(struct wiphy *wiphy, struct net_device *dev, | 793 | int ieee80211_tdls_oper(struct wiphy *wiphy, struct net_device *dev, |
| 288 | const u8 *peer, enum nl80211_tdls_operation oper) | 794 | const u8 *peer, enum nl80211_tdls_operation oper) |
| 289 | { | 795 | { |
| 290 | struct sta_info *sta; | 796 | struct sta_info *sta; |
| 291 | struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); | 797 | struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); |
| 798 | struct ieee80211_local *local = sdata->local; | ||
| 799 | int ret; | ||
| 292 | 800 | ||
| 293 | if (!(wiphy->flags & WIPHY_FLAG_SUPPORTS_TDLS)) | 801 | if (!(wiphy->flags & WIPHY_FLAG_SUPPORTS_TDLS)) |
| 294 | return -ENOTSUPP; | 802 | return -ENOTSUPP; |
| @@ -296,6 +804,18 @@ int ieee80211_tdls_oper(struct wiphy *wiphy, struct net_device *dev, | |||
| 296 | if (sdata->vif.type != NL80211_IFTYPE_STATION) | 804 | if (sdata->vif.type != NL80211_IFTYPE_STATION) |
| 297 | return -EINVAL; | 805 | return -EINVAL; |
| 298 | 806 | ||
| 807 | switch (oper) { | ||
| 808 | case NL80211_TDLS_ENABLE_LINK: | ||
| 809 | case NL80211_TDLS_DISABLE_LINK: | ||
| 810 | break; | ||
| 811 | case NL80211_TDLS_TEARDOWN: | ||
| 812 | case NL80211_TDLS_SETUP: | ||
| 813 | case NL80211_TDLS_DISCOVERY_REQ: | ||
| 814 | /* We don't support in-driver setup/teardown/discovery */ | ||
| 815 | return -ENOTSUPP; | ||
| 816 | } | ||
| 817 | |||
| 818 | mutex_lock(&local->mtx); | ||
| 299 | tdls_dbg(sdata, "TDLS oper %d peer %pM\n", oper, peer); | 819 | tdls_dbg(sdata, "TDLS oper %d peer %pM\n", oper, peer); |
| 300 | 820 | ||
| 301 | switch (oper) { | 821 | switch (oper) { |
| @@ -304,22 +824,60 @@ int ieee80211_tdls_oper(struct wiphy *wiphy, struct net_device *dev, | |||
| 304 | sta = sta_info_get(sdata, peer); | 824 | sta = sta_info_get(sdata, peer); |
| 305 | if (!sta) { | 825 | if (!sta) { |
| 306 | rcu_read_unlock(); | 826 | rcu_read_unlock(); |
| 307 | return -ENOLINK; | 827 | ret = -ENOLINK; |
| 828 | break; | ||
| 308 | } | 829 | } |
| 309 | 830 | ||
| 310 | set_sta_flag(sta, WLAN_STA_TDLS_PEER_AUTH); | 831 | set_sta_flag(sta, WLAN_STA_TDLS_PEER_AUTH); |
| 311 | rcu_read_unlock(); | 832 | rcu_read_unlock(); |
| 833 | |||
| 834 | WARN_ON_ONCE(is_zero_ether_addr(sdata->u.mgd.tdls_peer) || | ||
| 835 | !ether_addr_equal(sdata->u.mgd.tdls_peer, peer)); | ||
| 836 | ret = 0; | ||
| 312 | break; | 837 | break; |
| 313 | case NL80211_TDLS_DISABLE_LINK: | 838 | case NL80211_TDLS_DISABLE_LINK: |
| 314 | return sta_info_destroy_addr(sdata, peer); | 839 | /* |
| 315 | case NL80211_TDLS_TEARDOWN: | 840 | * The teardown message in ieee80211_tdls_mgmt_teardown() was |
| 316 | case NL80211_TDLS_SETUP: | 841 | * created while the queues were stopped, so it might still be |
| 317 | case NL80211_TDLS_DISCOVERY_REQ: | 842 | * pending. Before flushing the queues we need to be sure the |
| 318 | /* We don't support in-driver setup/teardown/discovery */ | 843 | * message is handled by the tasklet handling pending messages, |
| 319 | return -ENOTSUPP; | 844 | * otherwise we might start destroying the station before |
| 845 | * sending the teardown packet. | ||
| 846 | * Note that this only forces the tasklet to flush pendings - | ||
| 847 | * not to stop the tasklet from rescheduling itself. | ||
| 848 | */ | ||
| 849 | tasklet_kill(&local->tx_pending_tasklet); | ||
| 850 | /* flush a potentially queued teardown packet */ | ||
| 851 | ieee80211_flush_queues(local, sdata); | ||
| 852 | |||
| 853 | ret = sta_info_destroy_addr(sdata, peer); | ||
| 854 | break; | ||
| 320 | default: | 855 | default: |
| 321 | return -ENOTSUPP; | 856 | ret = -ENOTSUPP; |
| 857 | break; | ||
| 322 | } | 858 | } |
| 323 | 859 | ||
| 324 | return 0; | 860 | if (ret == 0 && ether_addr_equal(sdata->u.mgd.tdls_peer, peer)) { |
| 861 | cancel_delayed_work(&sdata->u.mgd.tdls_peer_del_work); | ||
| 862 | eth_zero_addr(sdata->u.mgd.tdls_peer); | ||
| 863 | } | ||
| 864 | |||
| 865 | mutex_unlock(&local->mtx); | ||
| 866 | return ret; | ||
| 867 | } | ||
| 868 | |||
| 869 | void ieee80211_tdls_oper_request(struct ieee80211_vif *vif, const u8 *peer, | ||
| 870 | enum nl80211_tdls_operation oper, | ||
| 871 | u16 reason_code, gfp_t gfp) | ||
| 872 | { | ||
| 873 | struct ieee80211_sub_if_data *sdata = vif_to_sdata(vif); | ||
| 874 | |||
| 875 | if (vif->type != NL80211_IFTYPE_STATION || !vif->bss_conf.assoc) { | ||
| 876 | sdata_err(sdata, "Discarding TDLS oper %d - not STA or disconnected\n", | ||
| 877 | oper); | ||
| 878 | return; | ||
| 879 | } | ||
| 880 | |||
| 881 | cfg80211_tdls_oper_request(sdata->dev, peer, oper, reason_code, gfp); | ||
| 325 | } | 882 | } |
| 883 | EXPORT_SYMBOL(ieee80211_tdls_oper_request); | ||
diff --git a/net/mac80211/trace.h b/net/mac80211/trace.h index cfe1a0688b5c..02ac535d1274 100644 --- a/net/mac80211/trace.h +++ b/net/mac80211/trace.h | |||
| @@ -1330,6 +1330,13 @@ DEFINE_EVENT(local_sdata_evt, drv_mgd_prepare_tx, | |||
| 1330 | TP_ARGS(local, sdata) | 1330 | TP_ARGS(local, sdata) |
| 1331 | ); | 1331 | ); |
| 1332 | 1332 | ||
| 1333 | DEFINE_EVENT(local_sdata_evt, drv_mgd_protect_tdls_discover, | ||
| 1334 | TP_PROTO(struct ieee80211_local *local, | ||
| 1335 | struct ieee80211_sub_if_data *sdata), | ||
| 1336 | |||
| 1337 | TP_ARGS(local, sdata) | ||
| 1338 | ); | ||
| 1339 | |||
| 1333 | DECLARE_EVENT_CLASS(local_chanctx, | 1340 | DECLARE_EVENT_CLASS(local_chanctx, |
| 1334 | TP_PROTO(struct ieee80211_local *local, | 1341 | TP_PROTO(struct ieee80211_local *local, |
| 1335 | struct ieee80211_chanctx *ctx), | 1342 | struct ieee80211_chanctx *ctx), |
diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c index 1a252c606ad0..464106c023d8 100644 --- a/net/mac80211/tx.c +++ b/net/mac80211/tx.c | |||
| @@ -250,7 +250,8 @@ ieee80211_tx_h_dynamic_ps(struct ieee80211_tx_data *tx) | |||
| 250 | if (local->hw.conf.flags & IEEE80211_CONF_PS) { | 250 | if (local->hw.conf.flags & IEEE80211_CONF_PS) { |
| 251 | ieee80211_stop_queues_by_reason(&local->hw, | 251 | ieee80211_stop_queues_by_reason(&local->hw, |
| 252 | IEEE80211_MAX_QUEUE_MAP, | 252 | IEEE80211_MAX_QUEUE_MAP, |
| 253 | IEEE80211_QUEUE_STOP_REASON_PS); | 253 | IEEE80211_QUEUE_STOP_REASON_PS, |
| 254 | false); | ||
| 254 | ifmgd->flags &= ~IEEE80211_STA_NULLFUNC_ACKED; | 255 | ifmgd->flags &= ~IEEE80211_STA_NULLFUNC_ACKED; |
| 255 | ieee80211_queue_work(&local->hw, | 256 | ieee80211_queue_work(&local->hw, |
| 256 | &local->dynamic_ps_disable_work); | 257 | &local->dynamic_ps_disable_work); |
| @@ -473,7 +474,8 @@ ieee80211_tx_h_unicast_ps_buf(struct ieee80211_tx_data *tx) | |||
| 473 | return TX_CONTINUE; | 474 | return TX_CONTINUE; |
| 474 | 475 | ||
| 475 | if (unlikely((test_sta_flag(sta, WLAN_STA_PS_STA) || | 476 | if (unlikely((test_sta_flag(sta, WLAN_STA_PS_STA) || |
| 476 | test_sta_flag(sta, WLAN_STA_PS_DRIVER)) && | 477 | test_sta_flag(sta, WLAN_STA_PS_DRIVER) || |
| 478 | test_sta_flag(sta, WLAN_STA_PS_DELIVER)) && | ||
| 477 | !(info->flags & IEEE80211_TX_CTL_NO_PS_BUFFER))) { | 479 | !(info->flags & IEEE80211_TX_CTL_NO_PS_BUFFER))) { |
| 478 | int ac = skb_get_queue_mapping(tx->skb); | 480 | int ac = skb_get_queue_mapping(tx->skb); |
| 479 | 481 | ||
| @@ -496,7 +498,8 @@ ieee80211_tx_h_unicast_ps_buf(struct ieee80211_tx_data *tx) | |||
| 496 | * ahead and Tx the packet. | 498 | * ahead and Tx the packet. |
| 497 | */ | 499 | */ |
| 498 | if (!test_sta_flag(sta, WLAN_STA_PS_STA) && | 500 | if (!test_sta_flag(sta, WLAN_STA_PS_STA) && |
| 499 | !test_sta_flag(sta, WLAN_STA_PS_DRIVER)) { | 501 | !test_sta_flag(sta, WLAN_STA_PS_DRIVER) && |
| 502 | !test_sta_flag(sta, WLAN_STA_PS_DELIVER)) { | ||
| 500 | spin_unlock(&sta->ps_lock); | 503 | spin_unlock(&sta->ps_lock); |
| 501 | return TX_CONTINUE; | 504 | return TX_CONTINUE; |
| 502 | } | 505 | } |
| @@ -1618,12 +1621,12 @@ netdev_tx_t ieee80211_monitor_start_xmit(struct sk_buff *skb, | |||
| 1618 | { | 1621 | { |
| 1619 | struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); | 1622 | struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); |
| 1620 | struct ieee80211_chanctx_conf *chanctx_conf; | 1623 | struct ieee80211_chanctx_conf *chanctx_conf; |
| 1621 | struct ieee80211_channel *chan; | ||
| 1622 | struct ieee80211_radiotap_header *prthdr = | 1624 | struct ieee80211_radiotap_header *prthdr = |
| 1623 | (struct ieee80211_radiotap_header *)skb->data; | 1625 | (struct ieee80211_radiotap_header *)skb->data; |
| 1624 | struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); | 1626 | struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); |
| 1625 | struct ieee80211_hdr *hdr; | 1627 | struct ieee80211_hdr *hdr; |
| 1626 | struct ieee80211_sub_if_data *tmp_sdata, *sdata; | 1628 | struct ieee80211_sub_if_data *tmp_sdata, *sdata; |
| 1629 | struct cfg80211_chan_def *chandef; | ||
| 1627 | u16 len_rthdr; | 1630 | u16 len_rthdr; |
| 1628 | int hdrlen; | 1631 | int hdrlen; |
| 1629 | 1632 | ||
| @@ -1721,9 +1724,9 @@ netdev_tx_t ieee80211_monitor_start_xmit(struct sk_buff *skb, | |||
| 1721 | } | 1724 | } |
| 1722 | 1725 | ||
| 1723 | if (chanctx_conf) | 1726 | if (chanctx_conf) |
| 1724 | chan = chanctx_conf->def.chan; | 1727 | chandef = &chanctx_conf->def; |
| 1725 | else if (!local->use_chanctx) | 1728 | else if (!local->use_chanctx) |
| 1726 | chan = local->_oper_chandef.chan; | 1729 | chandef = &local->_oper_chandef; |
| 1727 | else | 1730 | else |
| 1728 | goto fail_rcu; | 1731 | goto fail_rcu; |
| 1729 | 1732 | ||
| @@ -1743,10 +1746,11 @@ netdev_tx_t ieee80211_monitor_start_xmit(struct sk_buff *skb, | |||
| 1743 | * radar detection by itself. We can do that later by adding a | 1746 | * radar detection by itself. We can do that later by adding a |
| 1744 | * monitor flag interfaces used for AP support. | 1747 | * monitor flag interfaces used for AP support. |
| 1745 | */ | 1748 | */ |
| 1746 | if ((chan->flags & (IEEE80211_CHAN_NO_IR | IEEE80211_CHAN_RADAR))) | 1749 | if (!cfg80211_reg_can_beacon(local->hw.wiphy, chandef, |
| 1750 | sdata->vif.type)) | ||
| 1747 | goto fail_rcu; | 1751 | goto fail_rcu; |
| 1748 | 1752 | ||
| 1749 | ieee80211_xmit(sdata, skb, chan->band); | 1753 | ieee80211_xmit(sdata, skb, chandef->chan->band); |
| 1750 | rcu_read_unlock(); | 1754 | rcu_read_unlock(); |
| 1751 | 1755 | ||
| 1752 | return NETDEV_TX_OK; | 1756 | return NETDEV_TX_OK; |
| @@ -1767,15 +1771,12 @@ fail: | |||
| 1767 | static void ieee80211_tx_latency_start_msrmnt(struct ieee80211_local *local, | 1771 | static void ieee80211_tx_latency_start_msrmnt(struct ieee80211_local *local, |
| 1768 | struct sk_buff *skb) | 1772 | struct sk_buff *skb) |
| 1769 | { | 1773 | { |
| 1770 | struct timespec skb_arv; | ||
| 1771 | struct ieee80211_tx_latency_bin_ranges *tx_latency; | 1774 | struct ieee80211_tx_latency_bin_ranges *tx_latency; |
| 1772 | 1775 | ||
| 1773 | tx_latency = rcu_dereference(local->tx_latency); | 1776 | tx_latency = rcu_dereference(local->tx_latency); |
| 1774 | if (!tx_latency) | 1777 | if (!tx_latency) |
| 1775 | return; | 1778 | return; |
| 1776 | 1779 | skb->tstamp = ktime_get(); | |
| 1777 | ktime_get_ts(&skb_arv); | ||
| 1778 | skb->tstamp = ktime_set(skb_arv.tv_sec, skb_arv.tv_nsec); | ||
| 1779 | } | 1780 | } |
| 1780 | 1781 | ||
| 1781 | /** | 1782 | /** |
| @@ -1810,7 +1811,7 @@ netdev_tx_t ieee80211_subif_start_xmit(struct sk_buff *skb, | |||
| 1810 | int nh_pos, h_pos; | 1811 | int nh_pos, h_pos; |
| 1811 | struct sta_info *sta = NULL; | 1812 | struct sta_info *sta = NULL; |
| 1812 | bool wme_sta = false, authorized = false, tdls_auth = false; | 1813 | bool wme_sta = false, authorized = false, tdls_auth = false; |
| 1813 | bool tdls_direct = false; | 1814 | bool tdls_peer = false, tdls_setup_frame = false; |
| 1814 | bool multicast; | 1815 | bool multicast; |
| 1815 | u32 info_flags = 0; | 1816 | u32 info_flags = 0; |
| 1816 | u16 info_id = 0; | 1817 | u16 info_id = 0; |
| @@ -1952,34 +1953,35 @@ netdev_tx_t ieee80211_subif_start_xmit(struct sk_buff *skb, | |||
| 1952 | #endif | 1953 | #endif |
| 1953 | case NL80211_IFTYPE_STATION: | 1954 | case NL80211_IFTYPE_STATION: |
| 1954 | if (sdata->wdev.wiphy->flags & WIPHY_FLAG_SUPPORTS_TDLS) { | 1955 | if (sdata->wdev.wiphy->flags & WIPHY_FLAG_SUPPORTS_TDLS) { |
| 1955 | bool tdls_peer = false; | ||
| 1956 | |||
| 1957 | sta = sta_info_get(sdata, skb->data); | 1956 | sta = sta_info_get(sdata, skb->data); |
| 1958 | if (sta) { | 1957 | if (sta) { |
| 1959 | authorized = test_sta_flag(sta, | 1958 | authorized = test_sta_flag(sta, |
| 1960 | WLAN_STA_AUTHORIZED); | 1959 | WLAN_STA_AUTHORIZED); |
| 1961 | wme_sta = test_sta_flag(sta, WLAN_STA_WME); | 1960 | wme_sta = test_sta_flag(sta, WLAN_STA_WME); |
| 1962 | tdls_peer = test_sta_flag(sta, | 1961 | tdls_peer = test_sta_flag(sta, |
| 1963 | WLAN_STA_TDLS_PEER); | 1962 | WLAN_STA_TDLS_PEER); |
| 1964 | tdls_auth = test_sta_flag(sta, | 1963 | tdls_auth = test_sta_flag(sta, |
| 1965 | WLAN_STA_TDLS_PEER_AUTH); | 1964 | WLAN_STA_TDLS_PEER_AUTH); |
| 1966 | } | 1965 | } |
| 1967 | 1966 | ||
| 1968 | /* | 1967 | if (tdls_peer) |
| 1969 | * If the TDLS link is enabled, send everything | 1968 | tdls_setup_frame = |
| 1970 | * directly. Otherwise, allow TDLS setup frames | 1969 | ethertype == ETH_P_TDLS && |
| 1971 | * to be transmitted indirectly. | 1970 | skb->len > 14 && |
| 1972 | */ | 1971 | skb->data[14] == WLAN_TDLS_SNAP_RFTYPE; |
| 1973 | tdls_direct = tdls_peer && (tdls_auth || | ||
| 1974 | !(ethertype == ETH_P_TDLS && skb->len > 14 && | ||
| 1975 | skb->data[14] == WLAN_TDLS_SNAP_RFTYPE)); | ||
| 1976 | } | 1972 | } |
| 1977 | 1973 | ||
| 1978 | if (tdls_direct) { | 1974 | /* |
| 1979 | /* link during setup - throw out frames to peer */ | 1975 | * TDLS link during setup - throw out frames to peer. We allow |
| 1980 | if (!tdls_auth) | 1976 | * TDLS-setup frames to unauthorized peers for the special case |
| 1981 | goto fail_rcu; | 1977 | * of a link teardown after a TDLS sta is removed due to being |
| 1978 | * unreachable. | ||
| 1979 | */ | ||
| 1980 | if (tdls_peer && !tdls_auth && !tdls_setup_frame) | ||
| 1981 | goto fail_rcu; | ||
| 1982 | 1982 | ||
| 1983 | /* send direct packets to authorized TDLS peers */ | ||
| 1984 | if (tdls_peer && tdls_auth) { | ||
| 1983 | /* DA SA BSSID */ | 1985 | /* DA SA BSSID */ |
| 1984 | memcpy(hdr.addr1, skb->data, ETH_ALEN); | 1986 | memcpy(hdr.addr1, skb->data, ETH_ALEN); |
| 1985 | memcpy(hdr.addr2, skb->data + ETH_ALEN, ETH_ALEN); | 1987 | memcpy(hdr.addr2, skb->data + ETH_ALEN, ETH_ALEN); |
| @@ -2423,7 +2425,7 @@ static void ieee80211_set_csa(struct ieee80211_sub_if_data *sdata, | |||
| 2423 | u8 *beacon_data; | 2425 | u8 *beacon_data; |
| 2424 | size_t beacon_data_len; | 2426 | size_t beacon_data_len; |
| 2425 | int i; | 2427 | int i; |
| 2426 | u8 count = sdata->csa_current_counter; | 2428 | u8 count = beacon->csa_current_counter; |
| 2427 | 2429 | ||
| 2428 | switch (sdata->vif.type) { | 2430 | switch (sdata->vif.type) { |
| 2429 | case NL80211_IFTYPE_AP: | 2431 | case NL80211_IFTYPE_AP: |
| @@ -2442,46 +2444,53 @@ static void ieee80211_set_csa(struct ieee80211_sub_if_data *sdata, | |||
| 2442 | return; | 2444 | return; |
| 2443 | } | 2445 | } |
| 2444 | 2446 | ||
| 2447 | rcu_read_lock(); | ||
| 2445 | for (i = 0; i < IEEE80211_MAX_CSA_COUNTERS_NUM; ++i) { | 2448 | for (i = 0; i < IEEE80211_MAX_CSA_COUNTERS_NUM; ++i) { |
| 2446 | u16 counter_offset_beacon = | 2449 | resp = rcu_dereference(sdata->u.ap.probe_resp); |
| 2447 | sdata->csa_counter_offset_beacon[i]; | ||
| 2448 | u16 counter_offset_presp = sdata->csa_counter_offset_presp[i]; | ||
| 2449 | 2450 | ||
| 2450 | if (counter_offset_beacon) { | 2451 | if (beacon->csa_counter_offsets[i]) { |
| 2451 | if (WARN_ON(counter_offset_beacon >= beacon_data_len)) | 2452 | if (WARN_ON_ONCE(beacon->csa_counter_offsets[i] >= |
| 2452 | return; | 2453 | beacon_data_len)) { |
| 2453 | |||
| 2454 | beacon_data[counter_offset_beacon] = count; | ||
| 2455 | } | ||
| 2456 | |||
| 2457 | if (sdata->vif.type == NL80211_IFTYPE_AP && | ||
| 2458 | counter_offset_presp) { | ||
| 2459 | rcu_read_lock(); | ||
| 2460 | resp = rcu_dereference(sdata->u.ap.probe_resp); | ||
| 2461 | |||
| 2462 | /* If nl80211 accepted the offset, this should | ||
| 2463 | * not happen. | ||
| 2464 | */ | ||
| 2465 | if (WARN_ON(!resp)) { | ||
| 2466 | rcu_read_unlock(); | 2454 | rcu_read_unlock(); |
| 2467 | return; | 2455 | return; |
| 2468 | } | 2456 | } |
| 2469 | resp->data[counter_offset_presp] = count; | 2457 | |
| 2470 | rcu_read_unlock(); | 2458 | beacon_data[beacon->csa_counter_offsets[i]] = count; |
| 2471 | } | 2459 | } |
| 2460 | |||
| 2461 | if (sdata->vif.type == NL80211_IFTYPE_AP && resp) | ||
| 2462 | resp->data[resp->csa_counter_offsets[i]] = count; | ||
| 2472 | } | 2463 | } |
| 2464 | rcu_read_unlock(); | ||
| 2473 | } | 2465 | } |
| 2474 | 2466 | ||
| 2475 | u8 ieee80211_csa_update_counter(struct ieee80211_vif *vif) | 2467 | u8 ieee80211_csa_update_counter(struct ieee80211_vif *vif) |
| 2476 | { | 2468 | { |
| 2477 | struct ieee80211_sub_if_data *sdata = vif_to_sdata(vif); | 2469 | struct ieee80211_sub_if_data *sdata = vif_to_sdata(vif); |
| 2470 | struct beacon_data *beacon = NULL; | ||
| 2471 | u8 count = 0; | ||
| 2472 | |||
| 2473 | rcu_read_lock(); | ||
| 2478 | 2474 | ||
| 2479 | sdata->csa_current_counter--; | 2475 | if (sdata->vif.type == NL80211_IFTYPE_AP) |
| 2476 | beacon = rcu_dereference(sdata->u.ap.beacon); | ||
| 2477 | else if (sdata->vif.type == NL80211_IFTYPE_ADHOC) | ||
| 2478 | beacon = rcu_dereference(sdata->u.ibss.presp); | ||
| 2479 | else if (ieee80211_vif_is_mesh(&sdata->vif)) | ||
| 2480 | beacon = rcu_dereference(sdata->u.mesh.beacon); | ||
| 2481 | |||
| 2482 | if (!beacon) | ||
| 2483 | goto unlock; | ||
| 2484 | |||
| 2485 | beacon->csa_current_counter--; | ||
| 2480 | 2486 | ||
| 2481 | /* the counter should never reach 0 */ | 2487 | /* the counter should never reach 0 */ |
| 2482 | WARN_ON(!sdata->csa_current_counter); | 2488 | WARN_ON_ONCE(!beacon->csa_current_counter); |
| 2489 | count = beacon->csa_current_counter; | ||
| 2483 | 2490 | ||
| 2484 | return sdata->csa_current_counter; | 2491 | unlock: |
| 2492 | rcu_read_unlock(); | ||
| 2493 | return count; | ||
| 2485 | } | 2494 | } |
| 2486 | EXPORT_SYMBOL(ieee80211_csa_update_counter); | 2495 | EXPORT_SYMBOL(ieee80211_csa_update_counter); |
| 2487 | 2496 | ||
| @@ -2491,7 +2500,6 @@ bool ieee80211_csa_is_complete(struct ieee80211_vif *vif) | |||
| 2491 | struct beacon_data *beacon = NULL; | 2500 | struct beacon_data *beacon = NULL; |
| 2492 | u8 *beacon_data; | 2501 | u8 *beacon_data; |
| 2493 | size_t beacon_data_len; | 2502 | size_t beacon_data_len; |
| 2494 | int counter_beacon = sdata->csa_counter_offset_beacon[0]; | ||
| 2495 | int ret = false; | 2503 | int ret = false; |
| 2496 | 2504 | ||
| 2497 | if (!ieee80211_sdata_running(sdata)) | 2505 | if (!ieee80211_sdata_running(sdata)) |
| @@ -2529,10 +2537,13 @@ bool ieee80211_csa_is_complete(struct ieee80211_vif *vif) | |||
| 2529 | goto out; | 2537 | goto out; |
| 2530 | } | 2538 | } |
| 2531 | 2539 | ||
| 2532 | if (WARN_ON(counter_beacon > beacon_data_len)) | 2540 | if (!beacon->csa_counter_offsets[0]) |
| 2533 | goto out; | 2541 | goto out; |
| 2534 | 2542 | ||
| 2535 | if (beacon_data[counter_beacon] == 1) | 2543 | if (WARN_ON_ONCE(beacon->csa_counter_offsets[0] > beacon_data_len)) |
| 2544 | goto out; | ||
| 2545 | |||
| 2546 | if (beacon_data[beacon->csa_counter_offsets[0]] == 1) | ||
| 2536 | ret = true; | 2547 | ret = true; |
| 2537 | out: | 2548 | out: |
| 2538 | rcu_read_unlock(); | 2549 | rcu_read_unlock(); |
| @@ -2548,6 +2559,7 @@ __ieee80211_beacon_get(struct ieee80211_hw *hw, | |||
| 2548 | bool is_template) | 2559 | bool is_template) |
| 2549 | { | 2560 | { |
| 2550 | struct ieee80211_local *local = hw_to_local(hw); | 2561 | struct ieee80211_local *local = hw_to_local(hw); |
| 2562 | struct beacon_data *beacon = NULL; | ||
| 2551 | struct sk_buff *skb = NULL; | 2563 | struct sk_buff *skb = NULL; |
| 2552 | struct ieee80211_tx_info *info; | 2564 | struct ieee80211_tx_info *info; |
| 2553 | struct ieee80211_sub_if_data *sdata = NULL; | 2565 | struct ieee80211_sub_if_data *sdata = NULL; |
| @@ -2569,10 +2581,10 @@ __ieee80211_beacon_get(struct ieee80211_hw *hw, | |||
| 2569 | 2581 | ||
| 2570 | if (sdata->vif.type == NL80211_IFTYPE_AP) { | 2582 | if (sdata->vif.type == NL80211_IFTYPE_AP) { |
| 2571 | struct ieee80211_if_ap *ap = &sdata->u.ap; | 2583 | struct ieee80211_if_ap *ap = &sdata->u.ap; |
| 2572 | struct beacon_data *beacon = rcu_dereference(ap->beacon); | ||
| 2573 | 2584 | ||
| 2585 | beacon = rcu_dereference(ap->beacon); | ||
| 2574 | if (beacon) { | 2586 | if (beacon) { |
| 2575 | if (sdata->vif.csa_active) { | 2587 | if (beacon->csa_counter_offsets[0]) { |
| 2576 | if (!is_template) | 2588 | if (!is_template) |
| 2577 | ieee80211_csa_update_counter(vif); | 2589 | ieee80211_csa_update_counter(vif); |
| 2578 | 2590 | ||
| @@ -2613,37 +2625,37 @@ __ieee80211_beacon_get(struct ieee80211_hw *hw, | |||
| 2613 | } else if (sdata->vif.type == NL80211_IFTYPE_ADHOC) { | 2625 | } else if (sdata->vif.type == NL80211_IFTYPE_ADHOC) { |
| 2614 | struct ieee80211_if_ibss *ifibss = &sdata->u.ibss; | 2626 | struct ieee80211_if_ibss *ifibss = &sdata->u.ibss; |
| 2615 | struct ieee80211_hdr *hdr; | 2627 | struct ieee80211_hdr *hdr; |
| 2616 | struct beacon_data *presp = rcu_dereference(ifibss->presp); | ||
| 2617 | 2628 | ||
| 2618 | if (!presp) | 2629 | beacon = rcu_dereference(ifibss->presp); |
| 2630 | if (!beacon) | ||
| 2619 | goto out; | 2631 | goto out; |
| 2620 | 2632 | ||
| 2621 | if (sdata->vif.csa_active) { | 2633 | if (beacon->csa_counter_offsets[0]) { |
| 2622 | if (!is_template) | 2634 | if (!is_template) |
| 2623 | ieee80211_csa_update_counter(vif); | 2635 | ieee80211_csa_update_counter(vif); |
| 2624 | 2636 | ||
| 2625 | ieee80211_set_csa(sdata, presp); | 2637 | ieee80211_set_csa(sdata, beacon); |
| 2626 | } | 2638 | } |
| 2627 | 2639 | ||
| 2628 | skb = dev_alloc_skb(local->tx_headroom + presp->head_len + | 2640 | skb = dev_alloc_skb(local->tx_headroom + beacon->head_len + |
| 2629 | local->hw.extra_beacon_tailroom); | 2641 | local->hw.extra_beacon_tailroom); |
| 2630 | if (!skb) | 2642 | if (!skb) |
| 2631 | goto out; | 2643 | goto out; |
| 2632 | skb_reserve(skb, local->tx_headroom); | 2644 | skb_reserve(skb, local->tx_headroom); |
| 2633 | memcpy(skb_put(skb, presp->head_len), presp->head, | 2645 | memcpy(skb_put(skb, beacon->head_len), beacon->head, |
| 2634 | presp->head_len); | 2646 | beacon->head_len); |
| 2635 | 2647 | ||
| 2636 | hdr = (struct ieee80211_hdr *) skb->data; | 2648 | hdr = (struct ieee80211_hdr *) skb->data; |
| 2637 | hdr->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT | | 2649 | hdr->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT | |
| 2638 | IEEE80211_STYPE_BEACON); | 2650 | IEEE80211_STYPE_BEACON); |
| 2639 | } else if (ieee80211_vif_is_mesh(&sdata->vif)) { | 2651 | } else if (ieee80211_vif_is_mesh(&sdata->vif)) { |
| 2640 | struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh; | 2652 | struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh; |
| 2641 | struct beacon_data *bcn = rcu_dereference(ifmsh->beacon); | ||
| 2642 | 2653 | ||
| 2643 | if (!bcn) | 2654 | beacon = rcu_dereference(ifmsh->beacon); |
| 2655 | if (!beacon) | ||
| 2644 | goto out; | 2656 | goto out; |
| 2645 | 2657 | ||
| 2646 | if (sdata->vif.csa_active) { | 2658 | if (beacon->csa_counter_offsets[0]) { |
| 2647 | if (!is_template) | 2659 | if (!is_template) |
| 2648 | /* TODO: For mesh csa_counter is in TU, so | 2660 | /* TODO: For mesh csa_counter is in TU, so |
| 2649 | * decrementing it by one isn't correct, but | 2661 | * decrementing it by one isn't correct, but |
| @@ -2652,40 +2664,42 @@ __ieee80211_beacon_get(struct ieee80211_hw *hw, | |||
| 2652 | */ | 2664 | */ |
| 2653 | ieee80211_csa_update_counter(vif); | 2665 | ieee80211_csa_update_counter(vif); |
| 2654 | 2666 | ||
| 2655 | ieee80211_set_csa(sdata, bcn); | 2667 | ieee80211_set_csa(sdata, beacon); |
| 2656 | } | 2668 | } |
| 2657 | 2669 | ||
| 2658 | if (ifmsh->sync_ops) | 2670 | if (ifmsh->sync_ops) |
| 2659 | ifmsh->sync_ops->adjust_tbtt(sdata, bcn); | 2671 | ifmsh->sync_ops->adjust_tbtt(sdata, beacon); |
| 2660 | 2672 | ||
| 2661 | skb = dev_alloc_skb(local->tx_headroom + | 2673 | skb = dev_alloc_skb(local->tx_headroom + |
| 2662 | bcn->head_len + | 2674 | beacon->head_len + |
| 2663 | 256 + /* TIM IE */ | 2675 | 256 + /* TIM IE */ |
| 2664 | bcn->tail_len + | 2676 | beacon->tail_len + |
| 2665 | local->hw.extra_beacon_tailroom); | 2677 | local->hw.extra_beacon_tailroom); |
| 2666 | if (!skb) | 2678 | if (!skb) |
| 2667 | goto out; | 2679 | goto out; |
| 2668 | skb_reserve(skb, local->tx_headroom); | 2680 | skb_reserve(skb, local->tx_headroom); |
| 2669 | memcpy(skb_put(skb, bcn->head_len), bcn->head, bcn->head_len); | 2681 | memcpy(skb_put(skb, beacon->head_len), beacon->head, |
| 2682 | beacon->head_len); | ||
| 2670 | ieee80211_beacon_add_tim(sdata, &ifmsh->ps, skb, is_template); | 2683 | ieee80211_beacon_add_tim(sdata, &ifmsh->ps, skb, is_template); |
| 2671 | 2684 | ||
| 2672 | if (offs) { | 2685 | if (offs) { |
| 2673 | offs->tim_offset = bcn->head_len; | 2686 | offs->tim_offset = beacon->head_len; |
| 2674 | offs->tim_length = skb->len - bcn->head_len; | 2687 | offs->tim_length = skb->len - beacon->head_len; |
| 2675 | } | 2688 | } |
| 2676 | 2689 | ||
| 2677 | memcpy(skb_put(skb, bcn->tail_len), bcn->tail, bcn->tail_len); | 2690 | memcpy(skb_put(skb, beacon->tail_len), beacon->tail, |
| 2691 | beacon->tail_len); | ||
| 2678 | } else { | 2692 | } else { |
| 2679 | WARN_ON(1); | 2693 | WARN_ON(1); |
| 2680 | goto out; | 2694 | goto out; |
| 2681 | } | 2695 | } |
| 2682 | 2696 | ||
| 2683 | /* CSA offsets */ | 2697 | /* CSA offsets */ |
| 2684 | if (offs) { | 2698 | if (offs && beacon) { |
| 2685 | int i; | 2699 | int i; |
| 2686 | 2700 | ||
| 2687 | for (i = 0; i < IEEE80211_MAX_CSA_COUNTERS_NUM; i++) { | 2701 | for (i = 0; i < IEEE80211_MAX_CSA_COUNTERS_NUM; i++) { |
| 2688 | u16 csa_off = sdata->csa_counter_offset_beacon[i]; | 2702 | u16 csa_off = beacon->csa_counter_offsets[i]; |
| 2689 | 2703 | ||
| 2690 | if (!csa_off) | 2704 | if (!csa_off) |
| 2691 | continue; | 2705 | continue; |
diff --git a/net/mac80211/util.c b/net/mac80211/util.c index a6cda52ed920..725af7a468d2 100644 --- a/net/mac80211/util.c +++ b/net/mac80211/util.c | |||
| @@ -317,7 +317,8 @@ void ieee80211_propagate_queue_wake(struct ieee80211_local *local, int queue) | |||
| 317 | } | 317 | } |
| 318 | 318 | ||
| 319 | static void __ieee80211_wake_queue(struct ieee80211_hw *hw, int queue, | 319 | static void __ieee80211_wake_queue(struct ieee80211_hw *hw, int queue, |
| 320 | enum queue_stop_reason reason) | 320 | enum queue_stop_reason reason, |
| 321 | bool refcounted) | ||
| 321 | { | 322 | { |
| 322 | struct ieee80211_local *local = hw_to_local(hw); | 323 | struct ieee80211_local *local = hw_to_local(hw); |
| 323 | 324 | ||
| @@ -329,7 +330,13 @@ static void __ieee80211_wake_queue(struct ieee80211_hw *hw, int queue, | |||
| 329 | if (!test_bit(reason, &local->queue_stop_reasons[queue])) | 330 | if (!test_bit(reason, &local->queue_stop_reasons[queue])) |
| 330 | return; | 331 | return; |
| 331 | 332 | ||
| 332 | __clear_bit(reason, &local->queue_stop_reasons[queue]); | 333 | if (!refcounted) |
| 334 | local->q_stop_reasons[queue][reason] = 0; | ||
| 335 | else | ||
| 336 | local->q_stop_reasons[queue][reason]--; | ||
| 337 | |||
| 338 | if (local->q_stop_reasons[queue][reason] == 0) | ||
| 339 | __clear_bit(reason, &local->queue_stop_reasons[queue]); | ||
| 333 | 340 | ||
| 334 | if (local->queue_stop_reasons[queue] != 0) | 341 | if (local->queue_stop_reasons[queue] != 0) |
| 335 | /* someone still has this queue stopped */ | 342 | /* someone still has this queue stopped */ |
| @@ -344,25 +351,28 @@ static void __ieee80211_wake_queue(struct ieee80211_hw *hw, int queue, | |||
| 344 | } | 351 | } |
| 345 | 352 | ||
| 346 | void ieee80211_wake_queue_by_reason(struct ieee80211_hw *hw, int queue, | 353 | void ieee80211_wake_queue_by_reason(struct ieee80211_hw *hw, int queue, |
| 347 | enum queue_stop_reason reason) | 354 | enum queue_stop_reason reason, |
| 355 | bool refcounted) | ||
| 348 | { | 356 | { |
| 349 | struct ieee80211_local *local = hw_to_local(hw); | 357 | struct ieee80211_local *local = hw_to_local(hw); |
| 350 | unsigned long flags; | 358 | unsigned long flags; |
| 351 | 359 | ||
| 352 | spin_lock_irqsave(&local->queue_stop_reason_lock, flags); | 360 | spin_lock_irqsave(&local->queue_stop_reason_lock, flags); |
| 353 | __ieee80211_wake_queue(hw, queue, reason); | 361 | __ieee80211_wake_queue(hw, queue, reason, refcounted); |
| 354 | spin_unlock_irqrestore(&local->queue_stop_reason_lock, flags); | 362 | spin_unlock_irqrestore(&local->queue_stop_reason_lock, flags); |
| 355 | } | 363 | } |
| 356 | 364 | ||
| 357 | void ieee80211_wake_queue(struct ieee80211_hw *hw, int queue) | 365 | void ieee80211_wake_queue(struct ieee80211_hw *hw, int queue) |
| 358 | { | 366 | { |
| 359 | ieee80211_wake_queue_by_reason(hw, queue, | 367 | ieee80211_wake_queue_by_reason(hw, queue, |
| 360 | IEEE80211_QUEUE_STOP_REASON_DRIVER); | 368 | IEEE80211_QUEUE_STOP_REASON_DRIVER, |
| 369 | false); | ||
| 361 | } | 370 | } |
| 362 | EXPORT_SYMBOL(ieee80211_wake_queue); | 371 | EXPORT_SYMBOL(ieee80211_wake_queue); |
| 363 | 372 | ||
| 364 | static void __ieee80211_stop_queue(struct ieee80211_hw *hw, int queue, | 373 | static void __ieee80211_stop_queue(struct ieee80211_hw *hw, int queue, |
| 365 | enum queue_stop_reason reason) | 374 | enum queue_stop_reason reason, |
| 375 | bool refcounted) | ||
| 366 | { | 376 | { |
| 367 | struct ieee80211_local *local = hw_to_local(hw); | 377 | struct ieee80211_local *local = hw_to_local(hw); |
| 368 | struct ieee80211_sub_if_data *sdata; | 378 | struct ieee80211_sub_if_data *sdata; |
| @@ -373,10 +383,13 @@ static void __ieee80211_stop_queue(struct ieee80211_hw *hw, int queue, | |||
| 373 | if (WARN_ON(queue >= hw->queues)) | 383 | if (WARN_ON(queue >= hw->queues)) |
| 374 | return; | 384 | return; |
| 375 | 385 | ||
| 376 | if (test_bit(reason, &local->queue_stop_reasons[queue])) | 386 | if (!refcounted) |
| 377 | return; | 387 | local->q_stop_reasons[queue][reason] = 1; |
| 388 | else | ||
| 389 | local->q_stop_reasons[queue][reason]++; | ||
| 378 | 390 | ||
| 379 | __set_bit(reason, &local->queue_stop_reasons[queue]); | 391 | if (__test_and_set_bit(reason, &local->queue_stop_reasons[queue])) |
| 392 | return; | ||
| 380 | 393 | ||
| 381 | if (local->hw.queues < IEEE80211_NUM_ACS) | 394 | if (local->hw.queues < IEEE80211_NUM_ACS) |
| 382 | n_acs = 1; | 395 | n_acs = 1; |
| @@ -398,20 +411,22 @@ static void __ieee80211_stop_queue(struct ieee80211_hw *hw, int queue, | |||
| 398 | } | 411 | } |
| 399 | 412 | ||
| 400 | void ieee80211_stop_queue_by_reason(struct ieee80211_hw *hw, int queue, | 413 | void ieee80211_stop_queue_by_reason(struct ieee80211_hw *hw, int queue, |
| 401 | enum queue_stop_reason reason) | 414 | enum queue_stop_reason reason, |
| 415 | bool refcounted) | ||
| 402 | { | 416 | { |
| 403 | struct ieee80211_local *local = hw_to_local(hw); | 417 | struct ieee80211_local *local = hw_to_local(hw); |
| 404 | unsigned long flags; | 418 | unsigned long flags; |
| 405 | 419 | ||
| 406 | spin_lock_irqsave(&local->queue_stop_reason_lock, flags); | 420 | spin_lock_irqsave(&local->queue_stop_reason_lock, flags); |
| 407 | __ieee80211_stop_queue(hw, queue, reason); | 421 | __ieee80211_stop_queue(hw, queue, reason, refcounted); |
| 408 | spin_unlock_irqrestore(&local->queue_stop_reason_lock, flags); | 422 | spin_unlock_irqrestore(&local->queue_stop_reason_lock, flags); |
| 409 | } | 423 | } |
| 410 | 424 | ||
| 411 | void ieee80211_stop_queue(struct ieee80211_hw *hw, int queue) | 425 | void ieee80211_stop_queue(struct ieee80211_hw *hw, int queue) |
| 412 | { | 426 | { |
| 413 | ieee80211_stop_queue_by_reason(hw, queue, | 427 | ieee80211_stop_queue_by_reason(hw, queue, |
| 414 | IEEE80211_QUEUE_STOP_REASON_DRIVER); | 428 | IEEE80211_QUEUE_STOP_REASON_DRIVER, |
| 429 | false); | ||
| 415 | } | 430 | } |
| 416 | EXPORT_SYMBOL(ieee80211_stop_queue); | 431 | EXPORT_SYMBOL(ieee80211_stop_queue); |
| 417 | 432 | ||
| @@ -429,9 +444,11 @@ void ieee80211_add_pending_skb(struct ieee80211_local *local, | |||
| 429 | } | 444 | } |
| 430 | 445 | ||
| 431 | spin_lock_irqsave(&local->queue_stop_reason_lock, flags); | 446 | spin_lock_irqsave(&local->queue_stop_reason_lock, flags); |
| 432 | __ieee80211_stop_queue(hw, queue, IEEE80211_QUEUE_STOP_REASON_SKB_ADD); | 447 | __ieee80211_stop_queue(hw, queue, IEEE80211_QUEUE_STOP_REASON_SKB_ADD, |
| 448 | false); | ||
| 433 | __skb_queue_tail(&local->pending[queue], skb); | 449 | __skb_queue_tail(&local->pending[queue], skb); |
| 434 | __ieee80211_wake_queue(hw, queue, IEEE80211_QUEUE_STOP_REASON_SKB_ADD); | 450 | __ieee80211_wake_queue(hw, queue, IEEE80211_QUEUE_STOP_REASON_SKB_ADD, |
| 451 | false); | ||
| 435 | spin_unlock_irqrestore(&local->queue_stop_reason_lock, flags); | 452 | spin_unlock_irqrestore(&local->queue_stop_reason_lock, flags); |
| 436 | } | 453 | } |
| 437 | 454 | ||
| @@ -455,20 +472,23 @@ void ieee80211_add_pending_skbs(struct ieee80211_local *local, | |||
| 455 | queue = info->hw_queue; | 472 | queue = info->hw_queue; |
| 456 | 473 | ||
| 457 | __ieee80211_stop_queue(hw, queue, | 474 | __ieee80211_stop_queue(hw, queue, |
| 458 | IEEE80211_QUEUE_STOP_REASON_SKB_ADD); | 475 | IEEE80211_QUEUE_STOP_REASON_SKB_ADD, |
| 476 | false); | ||
| 459 | 477 | ||
| 460 | __skb_queue_tail(&local->pending[queue], skb); | 478 | __skb_queue_tail(&local->pending[queue], skb); |
| 461 | } | 479 | } |
| 462 | 480 | ||
| 463 | for (i = 0; i < hw->queues; i++) | 481 | for (i = 0; i < hw->queues; i++) |
| 464 | __ieee80211_wake_queue(hw, i, | 482 | __ieee80211_wake_queue(hw, i, |
| 465 | IEEE80211_QUEUE_STOP_REASON_SKB_ADD); | 483 | IEEE80211_QUEUE_STOP_REASON_SKB_ADD, |
| 484 | false); | ||
| 466 | spin_unlock_irqrestore(&local->queue_stop_reason_lock, flags); | 485 | spin_unlock_irqrestore(&local->queue_stop_reason_lock, flags); |
| 467 | } | 486 | } |
| 468 | 487 | ||
| 469 | void ieee80211_stop_queues_by_reason(struct ieee80211_hw *hw, | 488 | void ieee80211_stop_queues_by_reason(struct ieee80211_hw *hw, |
| 470 | unsigned long queues, | 489 | unsigned long queues, |
| 471 | enum queue_stop_reason reason) | 490 | enum queue_stop_reason reason, |
| 491 | bool refcounted) | ||
| 472 | { | 492 | { |
| 473 | struct ieee80211_local *local = hw_to_local(hw); | 493 | struct ieee80211_local *local = hw_to_local(hw); |
| 474 | unsigned long flags; | 494 | unsigned long flags; |
| @@ -477,7 +497,7 @@ void ieee80211_stop_queues_by_reason(struct ieee80211_hw *hw, | |||
| 477 | spin_lock_irqsave(&local->queue_stop_reason_lock, flags); | 497 | spin_lock_irqsave(&local->queue_stop_reason_lock, flags); |
| 478 | 498 | ||
| 479 | for_each_set_bit(i, &queues, hw->queues) | 499 | for_each_set_bit(i, &queues, hw->queues) |
| 480 | __ieee80211_stop_queue(hw, i, reason); | 500 | __ieee80211_stop_queue(hw, i, reason, refcounted); |
| 481 | 501 | ||
| 482 | spin_unlock_irqrestore(&local->queue_stop_reason_lock, flags); | 502 | spin_unlock_irqrestore(&local->queue_stop_reason_lock, flags); |
| 483 | } | 503 | } |
| @@ -485,7 +505,8 @@ void ieee80211_stop_queues_by_reason(struct ieee80211_hw *hw, | |||
| 485 | void ieee80211_stop_queues(struct ieee80211_hw *hw) | 505 | void ieee80211_stop_queues(struct ieee80211_hw *hw) |
| 486 | { | 506 | { |
| 487 | ieee80211_stop_queues_by_reason(hw, IEEE80211_MAX_QUEUE_MAP, | 507 | ieee80211_stop_queues_by_reason(hw, IEEE80211_MAX_QUEUE_MAP, |
| 488 | IEEE80211_QUEUE_STOP_REASON_DRIVER); | 508 | IEEE80211_QUEUE_STOP_REASON_DRIVER, |
| 509 | false); | ||
| 489 | } | 510 | } |
| 490 | EXPORT_SYMBOL(ieee80211_stop_queues); | 511 | EXPORT_SYMBOL(ieee80211_stop_queues); |
| 491 | 512 | ||
| @@ -508,7 +529,8 @@ EXPORT_SYMBOL(ieee80211_queue_stopped); | |||
| 508 | 529 | ||
| 509 | void ieee80211_wake_queues_by_reason(struct ieee80211_hw *hw, | 530 | void ieee80211_wake_queues_by_reason(struct ieee80211_hw *hw, |
| 510 | unsigned long queues, | 531 | unsigned long queues, |
| 511 | enum queue_stop_reason reason) | 532 | enum queue_stop_reason reason, |
| 533 | bool refcounted) | ||
| 512 | { | 534 | { |
| 513 | struct ieee80211_local *local = hw_to_local(hw); | 535 | struct ieee80211_local *local = hw_to_local(hw); |
| 514 | unsigned long flags; | 536 | unsigned long flags; |
| @@ -517,7 +539,7 @@ void ieee80211_wake_queues_by_reason(struct ieee80211_hw *hw, | |||
| 517 | spin_lock_irqsave(&local->queue_stop_reason_lock, flags); | 539 | spin_lock_irqsave(&local->queue_stop_reason_lock, flags); |
| 518 | 540 | ||
| 519 | for_each_set_bit(i, &queues, hw->queues) | 541 | for_each_set_bit(i, &queues, hw->queues) |
| 520 | __ieee80211_wake_queue(hw, i, reason); | 542 | __ieee80211_wake_queue(hw, i, reason, refcounted); |
| 521 | 543 | ||
| 522 | spin_unlock_irqrestore(&local->queue_stop_reason_lock, flags); | 544 | spin_unlock_irqrestore(&local->queue_stop_reason_lock, flags); |
| 523 | } | 545 | } |
| @@ -525,17 +547,16 @@ void ieee80211_wake_queues_by_reason(struct ieee80211_hw *hw, | |||
| 525 | void ieee80211_wake_queues(struct ieee80211_hw *hw) | 547 | void ieee80211_wake_queues(struct ieee80211_hw *hw) |
| 526 | { | 548 | { |
| 527 | ieee80211_wake_queues_by_reason(hw, IEEE80211_MAX_QUEUE_MAP, | 549 | ieee80211_wake_queues_by_reason(hw, IEEE80211_MAX_QUEUE_MAP, |
| 528 | IEEE80211_QUEUE_STOP_REASON_DRIVER); | 550 | IEEE80211_QUEUE_STOP_REASON_DRIVER, |
| 551 | false); | ||
| 529 | } | 552 | } |
| 530 | EXPORT_SYMBOL(ieee80211_wake_queues); | 553 | EXPORT_SYMBOL(ieee80211_wake_queues); |
| 531 | 554 | ||
| 532 | void ieee80211_flush_queues(struct ieee80211_local *local, | 555 | static unsigned int |
| 533 | struct ieee80211_sub_if_data *sdata) | 556 | ieee80211_get_vif_queues(struct ieee80211_local *local, |
| 557 | struct ieee80211_sub_if_data *sdata) | ||
| 534 | { | 558 | { |
| 535 | u32 queues; | 559 | unsigned int queues; |
| 536 | |||
| 537 | if (!local->ops->flush) | ||
| 538 | return; | ||
| 539 | 560 | ||
| 540 | if (sdata && local->hw.flags & IEEE80211_HW_QUEUE_CONTROL) { | 561 | if (sdata && local->hw.flags & IEEE80211_HW_QUEUE_CONTROL) { |
| 541 | int ac; | 562 | int ac; |
| @@ -551,13 +572,46 @@ void ieee80211_flush_queues(struct ieee80211_local *local, | |||
| 551 | queues = BIT(local->hw.queues) - 1; | 572 | queues = BIT(local->hw.queues) - 1; |
| 552 | } | 573 | } |
| 553 | 574 | ||
| 554 | ieee80211_stop_queues_by_reason(&local->hw, IEEE80211_MAX_QUEUE_MAP, | 575 | return queues; |
| 555 | IEEE80211_QUEUE_STOP_REASON_FLUSH); | 576 | } |
| 577 | |||
| 578 | void ieee80211_flush_queues(struct ieee80211_local *local, | ||
| 579 | struct ieee80211_sub_if_data *sdata) | ||
| 580 | { | ||
| 581 | unsigned int queues; | ||
| 582 | |||
| 583 | if (!local->ops->flush) | ||
| 584 | return; | ||
| 585 | |||
| 586 | queues = ieee80211_get_vif_queues(local, sdata); | ||
| 587 | |||
| 588 | ieee80211_stop_queues_by_reason(&local->hw, queues, | ||
| 589 | IEEE80211_QUEUE_STOP_REASON_FLUSH, | ||
| 590 | false); | ||
| 556 | 591 | ||
| 557 | drv_flush(local, sdata, queues, false); | 592 | drv_flush(local, sdata, queues, false); |
| 558 | 593 | ||
| 559 | ieee80211_wake_queues_by_reason(&local->hw, IEEE80211_MAX_QUEUE_MAP, | 594 | ieee80211_wake_queues_by_reason(&local->hw, queues, |
| 560 | IEEE80211_QUEUE_STOP_REASON_FLUSH); | 595 | IEEE80211_QUEUE_STOP_REASON_FLUSH, |
| 596 | false); | ||
| 597 | } | ||
| 598 | |||
| 599 | void ieee80211_stop_vif_queues(struct ieee80211_local *local, | ||
| 600 | struct ieee80211_sub_if_data *sdata, | ||
| 601 | enum queue_stop_reason reason) | ||
| 602 | { | ||
| 603 | ieee80211_stop_queues_by_reason(&local->hw, | ||
| 604 | ieee80211_get_vif_queues(local, sdata), | ||
| 605 | reason, true); | ||
| 606 | } | ||
| 607 | |||
| 608 | void ieee80211_wake_vif_queues(struct ieee80211_local *local, | ||
| 609 | struct ieee80211_sub_if_data *sdata, | ||
| 610 | enum queue_stop_reason reason) | ||
| 611 | { | ||
| 612 | ieee80211_wake_queues_by_reason(&local->hw, | ||
| 613 | ieee80211_get_vif_queues(local, sdata), | ||
| 614 | reason, true); | ||
| 561 | } | 615 | } |
| 562 | 616 | ||
| 563 | static void __iterate_active_interfaces(struct ieee80211_local *local, | 617 | static void __iterate_active_interfaces(struct ieee80211_local *local, |
| @@ -1166,14 +1220,17 @@ void ieee80211_send_deauth_disassoc(struct ieee80211_sub_if_data *sdata, | |||
| 1166 | } | 1220 | } |
| 1167 | } | 1221 | } |
| 1168 | 1222 | ||
| 1169 | int ieee80211_build_preq_ies(struct ieee80211_local *local, u8 *buffer, | 1223 | static int ieee80211_build_preq_ies_band(struct ieee80211_local *local, |
| 1170 | size_t buffer_len, const u8 *ie, size_t ie_len, | 1224 | u8 *buffer, size_t buffer_len, |
| 1171 | enum ieee80211_band band, u32 rate_mask, | 1225 | const u8 *ie, size_t ie_len, |
| 1172 | struct cfg80211_chan_def *chandef) | 1226 | enum ieee80211_band band, |
| 1227 | u32 rate_mask, | ||
| 1228 | struct cfg80211_chan_def *chandef, | ||
| 1229 | size_t *offset) | ||
| 1173 | { | 1230 | { |
| 1174 | struct ieee80211_supported_band *sband; | 1231 | struct ieee80211_supported_band *sband; |
| 1175 | u8 *pos = buffer, *end = buffer + buffer_len; | 1232 | u8 *pos = buffer, *end = buffer + buffer_len; |
| 1176 | size_t offset = 0, noffset; | 1233 | size_t noffset; |
| 1177 | int supp_rates_len, i; | 1234 | int supp_rates_len, i; |
| 1178 | u8 rates[32]; | 1235 | u8 rates[32]; |
| 1179 | int num_rates; | 1236 | int num_rates; |
| @@ -1181,6 +1238,8 @@ int ieee80211_build_preq_ies(struct ieee80211_local *local, u8 *buffer, | |||
| 1181 | int shift; | 1238 | int shift; |
| 1182 | u32 rate_flags; | 1239 | u32 rate_flags; |
| 1183 | 1240 | ||
| 1241 | *offset = 0; | ||
| 1242 | |||
| 1184 | sband = local->hw.wiphy->bands[band]; | 1243 | sband = local->hw.wiphy->bands[band]; |
| 1185 | if (WARN_ON_ONCE(!sband)) | 1244 | if (WARN_ON_ONCE(!sband)) |
| 1186 | return 0; | 1245 | return 0; |
| @@ -1219,12 +1278,12 @@ int ieee80211_build_preq_ies(struct ieee80211_local *local, u8 *buffer, | |||
| 1219 | noffset = ieee80211_ie_split(ie, ie_len, | 1278 | noffset = ieee80211_ie_split(ie, ie_len, |
| 1220 | before_extrates, | 1279 | before_extrates, |
| 1221 | ARRAY_SIZE(before_extrates), | 1280 | ARRAY_SIZE(before_extrates), |
| 1222 | offset); | 1281 | *offset); |
| 1223 | if (end - pos < noffset - offset) | 1282 | if (end - pos < noffset - *offset) |
| 1224 | goto out_err; | 1283 | goto out_err; |
| 1225 | memcpy(pos, ie + offset, noffset - offset); | 1284 | memcpy(pos, ie + *offset, noffset - *offset); |
| 1226 | pos += noffset - offset; | 1285 | pos += noffset - *offset; |
| 1227 | offset = noffset; | 1286 | *offset = noffset; |
| 1228 | } | 1287 | } |
| 1229 | 1288 | ||
| 1230 | ext_rates_len = num_rates - supp_rates_len; | 1289 | ext_rates_len = num_rates - supp_rates_len; |
| @@ -1258,12 +1317,12 @@ int ieee80211_build_preq_ies(struct ieee80211_local *local, u8 *buffer, | |||
| 1258 | }; | 1317 | }; |
| 1259 | noffset = ieee80211_ie_split(ie, ie_len, | 1318 | noffset = ieee80211_ie_split(ie, ie_len, |
| 1260 | before_ht, ARRAY_SIZE(before_ht), | 1319 | before_ht, ARRAY_SIZE(before_ht), |
| 1261 | offset); | 1320 | *offset); |
| 1262 | if (end - pos < noffset - offset) | 1321 | if (end - pos < noffset - *offset) |
| 1263 | goto out_err; | 1322 | goto out_err; |
| 1264 | memcpy(pos, ie + offset, noffset - offset); | 1323 | memcpy(pos, ie + *offset, noffset - *offset); |
| 1265 | pos += noffset - offset; | 1324 | pos += noffset - *offset; |
| 1266 | offset = noffset; | 1325 | *offset = noffset; |
| 1267 | } | 1326 | } |
| 1268 | 1327 | ||
| 1269 | if (sband->ht_cap.ht_supported) { | 1328 | if (sband->ht_cap.ht_supported) { |
| @@ -1298,12 +1357,12 @@ int ieee80211_build_preq_ies(struct ieee80211_local *local, u8 *buffer, | |||
| 1298 | }; | 1357 | }; |
| 1299 | noffset = ieee80211_ie_split(ie, ie_len, | 1358 | noffset = ieee80211_ie_split(ie, ie_len, |
| 1300 | before_vht, ARRAY_SIZE(before_vht), | 1359 | before_vht, ARRAY_SIZE(before_vht), |
| 1301 | offset); | 1360 | *offset); |
| 1302 | if (end - pos < noffset - offset) | 1361 | if (end - pos < noffset - *offset) |
| 1303 | goto out_err; | 1362 | goto out_err; |
| 1304 | memcpy(pos, ie + offset, noffset - offset); | 1363 | memcpy(pos, ie + *offset, noffset - *offset); |
| 1305 | pos += noffset - offset; | 1364 | pos += noffset - *offset; |
| 1306 | offset = noffset; | 1365 | *offset = noffset; |
| 1307 | } | 1366 | } |
| 1308 | 1367 | ||
| 1309 | if (sband->vht_cap.vht_supported) { | 1368 | if (sband->vht_cap.vht_supported) { |
| @@ -1313,21 +1372,54 @@ int ieee80211_build_preq_ies(struct ieee80211_local *local, u8 *buffer, | |||
| 1313 | sband->vht_cap.cap); | 1372 | sband->vht_cap.cap); |
| 1314 | } | 1373 | } |
| 1315 | 1374 | ||
| 1316 | /* add any remaining custom IEs */ | ||
| 1317 | if (ie && ie_len) { | ||
| 1318 | noffset = ie_len; | ||
| 1319 | if (end - pos < noffset - offset) | ||
| 1320 | goto out_err; | ||
| 1321 | memcpy(pos, ie + offset, noffset - offset); | ||
| 1322 | pos += noffset - offset; | ||
| 1323 | } | ||
| 1324 | |||
| 1325 | return pos - buffer; | 1375 | return pos - buffer; |
| 1326 | out_err: | 1376 | out_err: |
| 1327 | WARN_ONCE(1, "not enough space for preq IEs\n"); | 1377 | WARN_ONCE(1, "not enough space for preq IEs\n"); |
| 1328 | return pos - buffer; | 1378 | return pos - buffer; |
| 1329 | } | 1379 | } |
| 1330 | 1380 | ||
| 1381 | int ieee80211_build_preq_ies(struct ieee80211_local *local, u8 *buffer, | ||
| 1382 | size_t buffer_len, | ||
| 1383 | struct ieee80211_scan_ies *ie_desc, | ||
| 1384 | const u8 *ie, size_t ie_len, | ||
| 1385 | u8 bands_used, u32 *rate_masks, | ||
| 1386 | struct cfg80211_chan_def *chandef) | ||
| 1387 | { | ||
| 1388 | size_t pos = 0, old_pos = 0, custom_ie_offset = 0; | ||
| 1389 | int i; | ||
| 1390 | |||
| 1391 | memset(ie_desc, 0, sizeof(*ie_desc)); | ||
| 1392 | |||
| 1393 | for (i = 0; i < IEEE80211_NUM_BANDS; i++) { | ||
| 1394 | if (bands_used & BIT(i)) { | ||
| 1395 | pos += ieee80211_build_preq_ies_band(local, | ||
| 1396 | buffer + pos, | ||
| 1397 | buffer_len - pos, | ||
| 1398 | ie, ie_len, i, | ||
| 1399 | rate_masks[i], | ||
| 1400 | chandef, | ||
| 1401 | &custom_ie_offset); | ||
| 1402 | ie_desc->ies[i] = buffer + old_pos; | ||
| 1403 | ie_desc->len[i] = pos - old_pos; | ||
| 1404 | old_pos = pos; | ||
| 1405 | } | ||
| 1406 | } | ||
| 1407 | |||
| 1408 | /* add any remaining custom IEs */ | ||
| 1409 | if (ie && ie_len) { | ||
| 1410 | if (WARN_ONCE(buffer_len - pos < ie_len - custom_ie_offset, | ||
| 1411 | "not enough space for preq custom IEs\n")) | ||
| 1412 | return pos; | ||
| 1413 | memcpy(buffer + pos, ie + custom_ie_offset, | ||
| 1414 | ie_len - custom_ie_offset); | ||
| 1415 | ie_desc->common_ies = buffer + pos; | ||
| 1416 | ie_desc->common_ie_len = ie_len - custom_ie_offset; | ||
| 1417 | pos += ie_len - custom_ie_offset; | ||
| 1418 | } | ||
| 1419 | |||
| 1420 | return pos; | ||
| 1421 | }; | ||
| 1422 | |||
| 1331 | struct sk_buff *ieee80211_build_probe_req(struct ieee80211_sub_if_data *sdata, | 1423 | struct sk_buff *ieee80211_build_probe_req(struct ieee80211_sub_if_data *sdata, |
| 1332 | u8 *dst, u32 ratemask, | 1424 | u8 *dst, u32 ratemask, |
| 1333 | struct ieee80211_channel *chan, | 1425 | struct ieee80211_channel *chan, |
| @@ -1340,6 +1432,8 @@ struct sk_buff *ieee80211_build_probe_req(struct ieee80211_sub_if_data *sdata, | |||
| 1340 | struct sk_buff *skb; | 1432 | struct sk_buff *skb; |
| 1341 | struct ieee80211_mgmt *mgmt; | 1433 | struct ieee80211_mgmt *mgmt; |
| 1342 | int ies_len; | 1434 | int ies_len; |
| 1435 | u32 rate_masks[IEEE80211_NUM_BANDS] = {}; | ||
| 1436 | struct ieee80211_scan_ies dummy_ie_desc; | ||
| 1343 | 1437 | ||
| 1344 | /* | 1438 | /* |
| 1345 | * Do not send DS Channel parameter for directed probe requests | 1439 | * Do not send DS Channel parameter for directed probe requests |
| @@ -1357,10 +1451,11 @@ struct sk_buff *ieee80211_build_probe_req(struct ieee80211_sub_if_data *sdata, | |||
| 1357 | if (!skb) | 1451 | if (!skb) |
| 1358 | return NULL; | 1452 | return NULL; |
| 1359 | 1453 | ||
| 1454 | rate_masks[chan->band] = ratemask; | ||
| 1360 | ies_len = ieee80211_build_preq_ies(local, skb_tail_pointer(skb), | 1455 | ies_len = ieee80211_build_preq_ies(local, skb_tail_pointer(skb), |
| 1361 | skb_tailroom(skb), | 1456 | skb_tailroom(skb), &dummy_ie_desc, |
| 1362 | ie, ie_len, chan->band, | 1457 | ie, ie_len, BIT(chan->band), |
| 1363 | ratemask, &chandef); | 1458 | rate_masks, &chandef); |
| 1364 | skb_put(skb, ies_len); | 1459 | skb_put(skb, ies_len); |
| 1365 | 1460 | ||
| 1366 | if (dst) { | 1461 | if (dst) { |
| @@ -1604,7 +1699,9 @@ int ieee80211_reconfig(struct ieee80211_local *local) | |||
| 1604 | if (local->use_chanctx) { | 1699 | if (local->use_chanctx) { |
| 1605 | mutex_lock(&local->chanctx_mtx); | 1700 | mutex_lock(&local->chanctx_mtx); |
| 1606 | list_for_each_entry(ctx, &local->chanctx_list, list) | 1701 | list_for_each_entry(ctx, &local->chanctx_list, list) |
| 1607 | WARN_ON(drv_add_chanctx(local, ctx)); | 1702 | if (ctx->replace_state != |
| 1703 | IEEE80211_CHANCTX_REPLACES_OTHER) | ||
| 1704 | WARN_ON(drv_add_chanctx(local, ctx)); | ||
| 1608 | mutex_unlock(&local->chanctx_mtx); | 1705 | mutex_unlock(&local->chanctx_mtx); |
| 1609 | 1706 | ||
| 1610 | list_for_each_entry(sdata, &local->interfaces, list) { | 1707 | list_for_each_entry(sdata, &local->interfaces, list) { |
| @@ -1798,7 +1895,8 @@ int ieee80211_reconfig(struct ieee80211_local *local) | |||
| 1798 | } | 1895 | } |
| 1799 | 1896 | ||
| 1800 | ieee80211_wake_queues_by_reason(hw, IEEE80211_MAX_QUEUE_MAP, | 1897 | ieee80211_wake_queues_by_reason(hw, IEEE80211_MAX_QUEUE_MAP, |
| 1801 | IEEE80211_QUEUE_STOP_REASON_SUSPEND); | 1898 | IEEE80211_QUEUE_STOP_REASON_SUSPEND, |
| 1899 | false); | ||
| 1802 | 1900 | ||
| 1803 | /* | 1901 | /* |
| 1804 | * Reconfigure sched scan if it was interrupted by FW restart or | 1902 | * Reconfigure sched scan if it was interrupted by FW restart or |
| @@ -2836,6 +2934,35 @@ void ieee80211_recalc_dtim(struct ieee80211_local *local, | |||
| 2836 | ps->dtim_count = dtim_count; | 2934 | ps->dtim_count = dtim_count; |
| 2837 | } | 2935 | } |
| 2838 | 2936 | ||
| 2937 | static u8 ieee80211_chanctx_radar_detect(struct ieee80211_local *local, | ||
| 2938 | struct ieee80211_chanctx *ctx) | ||
| 2939 | { | ||
| 2940 | struct ieee80211_sub_if_data *sdata; | ||
| 2941 | u8 radar_detect = 0; | ||
| 2942 | |||
| 2943 | lockdep_assert_held(&local->chanctx_mtx); | ||
| 2944 | |||
| 2945 | if (WARN_ON(ctx->replace_state == IEEE80211_CHANCTX_WILL_BE_REPLACED)) | ||
| 2946 | return 0; | ||
| 2947 | |||
| 2948 | list_for_each_entry(sdata, &ctx->reserved_vifs, reserved_chanctx_list) | ||
| 2949 | if (sdata->reserved_radar_required) | ||
| 2950 | radar_detect |= BIT(sdata->reserved_chandef.width); | ||
| 2951 | |||
| 2952 | /* | ||
| 2953 | * An in-place reservation context should not have any assigned vifs | ||
| 2954 | * until it replaces the other context. | ||
| 2955 | */ | ||
| 2956 | WARN_ON(ctx->replace_state == IEEE80211_CHANCTX_REPLACES_OTHER && | ||
| 2957 | !list_empty(&ctx->assigned_vifs)); | ||
| 2958 | |||
| 2959 | list_for_each_entry(sdata, &ctx->assigned_vifs, assigned_chanctx_list) | ||
| 2960 | if (sdata->radar_required) | ||
| 2961 | radar_detect |= BIT(sdata->vif.bss_conf.chandef.width); | ||
| 2962 | |||
| 2963 | return radar_detect; | ||
| 2964 | } | ||
| 2965 | |||
| 2839 | int ieee80211_check_combinations(struct ieee80211_sub_if_data *sdata, | 2966 | int ieee80211_check_combinations(struct ieee80211_sub_if_data *sdata, |
| 2840 | const struct cfg80211_chan_def *chandef, | 2967 | const struct cfg80211_chan_def *chandef, |
| 2841 | enum ieee80211_chanctx_mode chanmode, | 2968 | enum ieee80211_chanctx_mode chanmode, |
| @@ -2877,8 +3004,9 @@ int ieee80211_check_combinations(struct ieee80211_sub_if_data *sdata, | |||
| 2877 | num[iftype] = 1; | 3004 | num[iftype] = 1; |
| 2878 | 3005 | ||
| 2879 | list_for_each_entry(ctx, &local->chanctx_list, list) { | 3006 | list_for_each_entry(ctx, &local->chanctx_list, list) { |
| 2880 | if (ctx->conf.radar_enabled) | 3007 | if (ctx->replace_state == IEEE80211_CHANCTX_WILL_BE_REPLACED) |
| 2881 | radar_detect |= BIT(ctx->conf.def.width); | 3008 | continue; |
| 3009 | radar_detect |= ieee80211_chanctx_radar_detect(local, ctx); | ||
| 2882 | if (ctx->mode == IEEE80211_CHANCTX_EXCLUSIVE) { | 3010 | if (ctx->mode == IEEE80211_CHANCTX_EXCLUSIVE) { |
| 2883 | num_different_channels++; | 3011 | num_different_channels++; |
| 2884 | continue; | 3012 | continue; |
| @@ -2935,10 +3063,12 @@ int ieee80211_max_num_channels(struct ieee80211_local *local) | |||
| 2935 | lockdep_assert_held(&local->chanctx_mtx); | 3063 | lockdep_assert_held(&local->chanctx_mtx); |
| 2936 | 3064 | ||
| 2937 | list_for_each_entry(ctx, &local->chanctx_list, list) { | 3065 | list_for_each_entry(ctx, &local->chanctx_list, list) { |
| 3066 | if (ctx->replace_state == IEEE80211_CHANCTX_WILL_BE_REPLACED) | ||
| 3067 | continue; | ||
| 3068 | |||
| 2938 | num_different_channels++; | 3069 | num_different_channels++; |
| 2939 | 3070 | ||
| 2940 | if (ctx->conf.radar_enabled) | 3071 | radar_detect |= ieee80211_chanctx_radar_detect(local, ctx); |
| 2941 | radar_detect |= BIT(ctx->conf.def.width); | ||
| 2942 | } | 3072 | } |
| 2943 | 3073 | ||
| 2944 | list_for_each_entry_rcu(sdata, &local->interfaces, list) | 3074 | list_for_each_entry_rcu(sdata, &local->interfaces, list) |
| @@ -2953,3 +3083,18 @@ int ieee80211_max_num_channels(struct ieee80211_local *local) | |||
| 2953 | 3083 | ||
| 2954 | return max_num_different_channels; | 3084 | return max_num_different_channels; |
| 2955 | } | 3085 | } |
| 3086 | |||
| 3087 | u8 *ieee80211_add_wmm_info_ie(u8 *buf, u8 qosinfo) | ||
| 3088 | { | ||
| 3089 | *buf++ = WLAN_EID_VENDOR_SPECIFIC; | ||
| 3090 | *buf++ = 7; /* len */ | ||
| 3091 | *buf++ = 0x00; /* Microsoft OUI 00:50:F2 */ | ||
| 3092 | *buf++ = 0x50; | ||
| 3093 | *buf++ = 0xf2; | ||
| 3094 | *buf++ = 2; /* WME */ | ||
| 3095 | *buf++ = 0; /* WME info */ | ||
| 3096 | *buf++ = 1; /* WME ver */ | ||
| 3097 | *buf++ = qosinfo; /* U-APSD no in use */ | ||
| 3098 | |||
| 3099 | return buf; | ||
| 3100 | } | ||
diff --git a/net/mac80211/vht.c b/net/mac80211/vht.c index 9265adfdabfc..671ce0d27a80 100644 --- a/net/mac80211/vht.c +++ b/net/mac80211/vht.c | |||
| @@ -129,6 +129,10 @@ ieee80211_vht_cap_ie_to_sta_vht_cap(struct ieee80211_sub_if_data *sdata, | |||
| 129 | if (!vht_cap_ie || !sband->vht_cap.vht_supported) | 129 | if (!vht_cap_ie || !sband->vht_cap.vht_supported) |
| 130 | return; | 130 | return; |
| 131 | 131 | ||
| 132 | /* don't support VHT for TDLS peers for now */ | ||
| 133 | if (test_sta_flag(sta, WLAN_STA_TDLS_PEER)) | ||
| 134 | return; | ||
| 135 | |||
| 132 | /* | 136 | /* |
| 133 | * A VHT STA must support 40 MHz, but if we verify that here | 137 | * A VHT STA must support 40 MHz, but if we verify that here |
| 134 | * then we break a few things - some APs (e.g. Netgear R6300v2 | 138 | * then we break a few things - some APs (e.g. Netgear R6300v2 |
diff --git a/net/mac80211/wep.c b/net/mac80211/wep.c index 6ee2b5863572..9181fb6d6437 100644 --- a/net/mac80211/wep.c +++ b/net/mac80211/wep.c | |||
| @@ -271,22 +271,6 @@ static int ieee80211_wep_decrypt(struct ieee80211_local *local, | |||
| 271 | return ret; | 271 | return ret; |
| 272 | } | 272 | } |
| 273 | 273 | ||
| 274 | |||
| 275 | static bool ieee80211_wep_is_weak_iv(struct sk_buff *skb, | ||
| 276 | struct ieee80211_key *key) | ||
| 277 | { | ||
| 278 | struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; | ||
| 279 | unsigned int hdrlen; | ||
| 280 | u8 *ivpos; | ||
| 281 | u32 iv; | ||
| 282 | |||
| 283 | hdrlen = ieee80211_hdrlen(hdr->frame_control); | ||
| 284 | ivpos = skb->data + hdrlen; | ||
| 285 | iv = (ivpos[0] << 16) | (ivpos[1] << 8) | ivpos[2]; | ||
| 286 | |||
| 287 | return ieee80211_wep_weak_iv(iv, key->conf.keylen); | ||
| 288 | } | ||
| 289 | |||
| 290 | ieee80211_rx_result | 274 | ieee80211_rx_result |
| 291 | ieee80211_crypto_wep_decrypt(struct ieee80211_rx_data *rx) | 275 | ieee80211_crypto_wep_decrypt(struct ieee80211_rx_data *rx) |
| 292 | { | 276 | { |
| @@ -301,16 +285,12 @@ ieee80211_crypto_wep_decrypt(struct ieee80211_rx_data *rx) | |||
| 301 | if (!(status->flag & RX_FLAG_DECRYPTED)) { | 285 | if (!(status->flag & RX_FLAG_DECRYPTED)) { |
| 302 | if (skb_linearize(rx->skb)) | 286 | if (skb_linearize(rx->skb)) |
| 303 | return RX_DROP_UNUSABLE; | 287 | return RX_DROP_UNUSABLE; |
| 304 | if (rx->sta && ieee80211_wep_is_weak_iv(rx->skb, rx->key)) | ||
| 305 | rx->sta->wep_weak_iv_count++; | ||
| 306 | if (ieee80211_wep_decrypt(rx->local, rx->skb, rx->key)) | 288 | if (ieee80211_wep_decrypt(rx->local, rx->skb, rx->key)) |
| 307 | return RX_DROP_UNUSABLE; | 289 | return RX_DROP_UNUSABLE; |
| 308 | } else if (!(status->flag & RX_FLAG_IV_STRIPPED)) { | 290 | } else if (!(status->flag & RX_FLAG_IV_STRIPPED)) { |
| 309 | if (!pskb_may_pull(rx->skb, ieee80211_hdrlen(fc) + | 291 | if (!pskb_may_pull(rx->skb, ieee80211_hdrlen(fc) + |
| 310 | IEEE80211_WEP_IV_LEN)) | 292 | IEEE80211_WEP_IV_LEN)) |
| 311 | return RX_DROP_UNUSABLE; | 293 | return RX_DROP_UNUSABLE; |
| 312 | if (rx->sta && ieee80211_wep_is_weak_iv(rx->skb, rx->key)) | ||
| 313 | rx->sta->wep_weak_iv_count++; | ||
| 314 | ieee80211_wep_remove_iv(rx->local, rx->skb, rx->key); | 294 | ieee80211_wep_remove_iv(rx->local, rx->skb, rx->key); |
| 315 | /* remove ICV */ | 295 | /* remove ICV */ |
| 316 | if (pskb_trim(rx->skb, rx->skb->len - IEEE80211_WEP_ICV_LEN)) | 296 | if (pskb_trim(rx->skb, rx->skb->len - IEEE80211_WEP_ICV_LEN)) |
diff --git a/net/mac80211/wpa.c b/net/mac80211/wpa.c index 9b3dcc201145..f7d4ca4c46e0 100644 --- a/net/mac80211/wpa.c +++ b/net/mac80211/wpa.c | |||
| @@ -811,7 +811,7 @@ ieee80211_crypto_hw_encrypt(struct ieee80211_tx_data *tx) | |||
| 811 | ieee80211_rx_result | 811 | ieee80211_rx_result |
| 812 | ieee80211_crypto_hw_decrypt(struct ieee80211_rx_data *rx) | 812 | ieee80211_crypto_hw_decrypt(struct ieee80211_rx_data *rx) |
| 813 | { | 813 | { |
| 814 | if (rx->sta->cipher_scheme) | 814 | if (rx->sta && rx->sta->cipher_scheme) |
| 815 | return ieee80211_crypto_cs_decrypt(rx); | 815 | return ieee80211_crypto_cs_decrypt(rx); |
| 816 | 816 | ||
| 817 | return RX_DROP_UNUSABLE; | 817 | return RX_DROP_UNUSABLE; |
diff --git a/net/mac802154/ieee802154_dev.c b/net/mac802154/ieee802154_dev.c index 2cf66d885e68..b36b2b996578 100644 --- a/net/mac802154/ieee802154_dev.c +++ b/net/mac802154/ieee802154_dev.c | |||
| @@ -143,6 +143,7 @@ static void | |||
| 143 | mac802154_del_iface(struct wpan_phy *phy, struct net_device *dev) | 143 | mac802154_del_iface(struct wpan_phy *phy, struct net_device *dev) |
| 144 | { | 144 | { |
| 145 | struct mac802154_sub_if_data *sdata; | 145 | struct mac802154_sub_if_data *sdata; |
| 146 | |||
| 146 | ASSERT_RTNL(); | 147 | ASSERT_RTNL(); |
| 147 | 148 | ||
| 148 | sdata = netdev_priv(dev); | 149 | sdata = netdev_priv(dev); |
| @@ -166,11 +167,13 @@ mac802154_add_iface(struct wpan_phy *phy, const char *name, int type) | |||
| 166 | switch (type) { | 167 | switch (type) { |
| 167 | case IEEE802154_DEV_MONITOR: | 168 | case IEEE802154_DEV_MONITOR: |
| 168 | dev = alloc_netdev(sizeof(struct mac802154_sub_if_data), | 169 | dev = alloc_netdev(sizeof(struct mac802154_sub_if_data), |
| 169 | name, mac802154_monitor_setup); | 170 | name, NET_NAME_UNKNOWN, |
| 171 | mac802154_monitor_setup); | ||
| 170 | break; | 172 | break; |
| 171 | case IEEE802154_DEV_WPAN: | 173 | case IEEE802154_DEV_WPAN: |
| 172 | dev = alloc_netdev(sizeof(struct mac802154_sub_if_data), | 174 | dev = alloc_netdev(sizeof(struct mac802154_sub_if_data), |
| 173 | name, mac802154_wpan_setup); | 175 | name, NET_NAME_UNKNOWN, |
| 176 | mac802154_wpan_setup); | ||
| 174 | break; | 177 | break; |
| 175 | default: | 178 | default: |
| 176 | dev = NULL; | 179 | dev = NULL; |
| @@ -276,7 +279,8 @@ ieee802154_alloc_device(size_t priv_data_len, struct ieee802154_ops *ops) | |||
| 276 | } | 279 | } |
| 277 | 280 | ||
| 278 | priv = wpan_phy_priv(phy); | 281 | priv = wpan_phy_priv(phy); |
| 279 | priv->hw.phy = priv->phy = phy; | 282 | priv->phy = phy; |
| 283 | priv->hw.phy = priv->phy; | ||
| 280 | priv->hw.priv = (char *)priv + ALIGN(sizeof(*priv), NETDEV_ALIGN); | 284 | priv->hw.priv = (char *)priv + ALIGN(sizeof(*priv), NETDEV_ALIGN); |
| 281 | priv->ops = ops; | 285 | priv->ops = ops; |
| 282 | 286 | ||
| @@ -302,29 +306,61 @@ EXPORT_SYMBOL(ieee802154_free_device); | |||
| 302 | int ieee802154_register_device(struct ieee802154_dev *dev) | 306 | int ieee802154_register_device(struct ieee802154_dev *dev) |
| 303 | { | 307 | { |
| 304 | struct mac802154_priv *priv = mac802154_to_priv(dev); | 308 | struct mac802154_priv *priv = mac802154_to_priv(dev); |
| 305 | int rc = -ENOMEM; | 309 | int rc = -ENOSYS; |
| 310 | |||
| 311 | if (dev->flags & IEEE802154_HW_TXPOWER) { | ||
| 312 | if (!priv->ops->set_txpower) | ||
| 313 | goto out; | ||
| 314 | |||
| 315 | priv->phy->set_txpower = mac802154_set_txpower; | ||
| 316 | } | ||
| 317 | |||
| 318 | if (dev->flags & IEEE802154_HW_LBT) { | ||
| 319 | if (!priv->ops->set_lbt) | ||
| 320 | goto out; | ||
| 321 | |||
| 322 | priv->phy->set_lbt = mac802154_set_lbt; | ||
| 323 | } | ||
| 324 | |||
| 325 | if (dev->flags & IEEE802154_HW_CCA_MODE) { | ||
| 326 | if (!priv->ops->set_cca_mode) | ||
| 327 | goto out; | ||
| 328 | |||
| 329 | priv->phy->set_cca_mode = mac802154_set_cca_mode; | ||
| 330 | } | ||
| 331 | |||
| 332 | if (dev->flags & IEEE802154_HW_CCA_ED_LEVEL) { | ||
| 333 | if (!priv->ops->set_cca_ed_level) | ||
| 334 | goto out; | ||
| 335 | |||
| 336 | priv->phy->set_cca_ed_level = mac802154_set_cca_ed_level; | ||
| 337 | } | ||
| 338 | |||
| 339 | if (dev->flags & IEEE802154_HW_CSMA_PARAMS) { | ||
| 340 | if (!priv->ops->set_csma_params) | ||
| 341 | goto out; | ||
| 342 | |||
| 343 | priv->phy->set_csma_params = mac802154_set_csma_params; | ||
| 344 | } | ||
| 345 | |||
| 346 | if (dev->flags & IEEE802154_HW_FRAME_RETRIES) { | ||
| 347 | if (!priv->ops->set_frame_retries) | ||
| 348 | goto out; | ||
| 349 | |||
| 350 | priv->phy->set_frame_retries = mac802154_set_frame_retries; | ||
| 351 | } | ||
| 306 | 352 | ||
| 307 | priv->dev_workqueue = | 353 | priv->dev_workqueue = |
| 308 | create_singlethread_workqueue(wpan_phy_name(priv->phy)); | 354 | create_singlethread_workqueue(wpan_phy_name(priv->phy)); |
| 309 | if (!priv->dev_workqueue) | 355 | if (!priv->dev_workqueue) { |
| 356 | rc = -ENOMEM; | ||
| 310 | goto out; | 357 | goto out; |
| 358 | } | ||
| 311 | 359 | ||
| 312 | wpan_phy_set_dev(priv->phy, priv->hw.parent); | 360 | wpan_phy_set_dev(priv->phy, priv->hw.parent); |
| 313 | 361 | ||
| 314 | priv->phy->add_iface = mac802154_add_iface; | 362 | priv->phy->add_iface = mac802154_add_iface; |
| 315 | priv->phy->del_iface = mac802154_del_iface; | 363 | priv->phy->del_iface = mac802154_del_iface; |
| 316 | if (priv->ops->set_txpower) | ||
| 317 | priv->phy->set_txpower = mac802154_set_txpower; | ||
| 318 | if (priv->ops->set_lbt) | ||
| 319 | priv->phy->set_lbt = mac802154_set_lbt; | ||
| 320 | if (priv->ops->set_cca_mode) | ||
| 321 | priv->phy->set_cca_mode = mac802154_set_cca_mode; | ||
| 322 | if (priv->ops->set_cca_ed_level) | ||
| 323 | priv->phy->set_cca_ed_level = mac802154_set_cca_ed_level; | ||
| 324 | if (priv->ops->set_csma_params) | ||
| 325 | priv->phy->set_csma_params = mac802154_set_csma_params; | ||
| 326 | if (priv->ops->set_frame_retries) | ||
| 327 | priv->phy->set_frame_retries = mac802154_set_frame_retries; | ||
| 328 | 364 | ||
| 329 | rc = wpan_phy_register(priv->phy); | 365 | rc = wpan_phy_register(priv->phy); |
| 330 | if (rc < 0) | 366 | if (rc < 0) |
diff --git a/net/mac802154/llsec.c b/net/mac802154/llsec.c index 1456f73b02b9..457058142098 100644 --- a/net/mac802154/llsec.c +++ b/net/mac802154/llsec.c | |||
| @@ -538,6 +538,7 @@ static int llsec_recover_addr(struct mac802154_llsec *sec, | |||
| 538 | struct ieee802154_addr *addr) | 538 | struct ieee802154_addr *addr) |
| 539 | { | 539 | { |
| 540 | __le16 caddr = sec->params.coord_shortaddr; | 540 | __le16 caddr = sec->params.coord_shortaddr; |
| 541 | |||
| 541 | addr->pan_id = sec->params.pan_id; | 542 | addr->pan_id = sec->params.pan_id; |
| 542 | 543 | ||
| 543 | if (caddr == cpu_to_le16(IEEE802154_ADDR_BROADCAST)) { | 544 | if (caddr == cpu_to_le16(IEEE802154_ADDR_BROADCAST)) { |
diff --git a/net/mac802154/mib.c b/net/mac802154/mib.c index 15aa2f2b03a7..868a040fd422 100644 --- a/net/mac802154/mib.c +++ b/net/mac802154/mib.c | |||
| @@ -175,9 +175,9 @@ static void phy_chan_notify(struct work_struct *work) | |||
| 175 | 175 | ||
| 176 | mutex_lock(&priv->hw->phy->pib_lock); | 176 | mutex_lock(&priv->hw->phy->pib_lock); |
| 177 | res = hw->ops->set_channel(&hw->hw, priv->page, priv->chan); | 177 | res = hw->ops->set_channel(&hw->hw, priv->page, priv->chan); |
| 178 | if (res) | 178 | if (res) { |
| 179 | pr_debug("set_channel failed\n"); | 179 | pr_debug("set_channel failed\n"); |
| 180 | else { | 180 | } else { |
| 181 | priv->hw->phy->current_channel = priv->chan; | 181 | priv->hw->phy->current_channel = priv->chan; |
| 182 | priv->hw->phy->current_page = priv->page; | 182 | priv->hw->phy->current_page = priv->page; |
| 183 | } | 183 | } |
| @@ -210,8 +210,9 @@ void mac802154_dev_set_page_channel(struct net_device *dev, u8 page, u8 chan) | |||
| 210 | INIT_WORK(&work->work, phy_chan_notify); | 210 | INIT_WORK(&work->work, phy_chan_notify); |
| 211 | work->dev = dev; | 211 | work->dev = dev; |
| 212 | queue_work(priv->hw->dev_workqueue, &work->work); | 212 | queue_work(priv->hw->dev_workqueue, &work->work); |
| 213 | } else | 213 | } else { |
| 214 | mutex_unlock(&priv->hw->phy->pib_lock); | 214 | mutex_unlock(&priv->hw->phy->pib_lock); |
| 215 | } | ||
| 215 | } | 216 | } |
| 216 | 217 | ||
| 217 | 218 | ||
diff --git a/net/mac802154/tx.c b/net/mac802154/tx.c index 6d1647399d4f..8124353646ae 100644 --- a/net/mac802154/tx.c +++ b/net/mac802154/tx.c | |||
| @@ -98,6 +98,7 @@ netdev_tx_t mac802154_tx(struct mac802154_priv *priv, struct sk_buff *skb, | |||
| 98 | if (!(priv->hw.flags & IEEE802154_HW_OMIT_CKSUM)) { | 98 | if (!(priv->hw.flags & IEEE802154_HW_OMIT_CKSUM)) { |
| 99 | u16 crc = crc_ccitt(0, skb->data, skb->len); | 99 | u16 crc = crc_ccitt(0, skb->data, skb->len); |
| 100 | u8 *data = skb_put(skb, 2); | 100 | u8 *data = skb_put(skb, 2); |
| 101 | |||
| 101 | data[0] = crc & 0xff; | 102 | data[0] = crc & 0xff; |
| 102 | data[1] = crc >> 8; | 103 | data[1] = crc >> 8; |
| 103 | } | 104 | } |
diff --git a/net/netfilter/Kconfig b/net/netfilter/Kconfig index e9410d17619d..ad751fe2e82b 100644 --- a/net/netfilter/Kconfig +++ b/net/netfilter/Kconfig | |||
| @@ -46,6 +46,9 @@ config NF_CONNTRACK | |||
| 46 | 46 | ||
| 47 | To compile it as a module, choose M here. If unsure, say N. | 47 | To compile it as a module, choose M here. If unsure, say N. |
| 48 | 48 | ||
| 49 | config NF_LOG_COMMON | ||
| 50 | tristate | ||
| 51 | |||
| 49 | if NF_CONNTRACK | 52 | if NF_CONNTRACK |
| 50 | 53 | ||
| 51 | config NF_CONNTRACK_MARK | 54 | config NF_CONNTRACK_MARK |
| @@ -744,6 +747,7 @@ config NETFILTER_XT_TARGET_LED | |||
| 744 | 747 | ||
| 745 | config NETFILTER_XT_TARGET_LOG | 748 | config NETFILTER_XT_TARGET_LOG |
| 746 | tristate "LOG target support" | 749 | tristate "LOG target support" |
| 750 | depends on NF_LOG_IPV4 && NF_LOG_IPV6 | ||
| 747 | default m if NETFILTER_ADVANCED=n | 751 | default m if NETFILTER_ADVANCED=n |
| 748 | help | 752 | help |
| 749 | This option adds a `LOG' target, which allows you to create rules in | 753 | This option adds a `LOG' target, which allows you to create rules in |
diff --git a/net/netfilter/Makefile b/net/netfilter/Makefile index bffdad774da7..8308624a406a 100644 --- a/net/netfilter/Makefile +++ b/net/netfilter/Makefile | |||
| @@ -47,6 +47,9 @@ obj-$(CONFIG_NF_CONNTRACK_TFTP) += nf_conntrack_tftp.o | |||
| 47 | nf_nat-y := nf_nat_core.o nf_nat_proto_unknown.o nf_nat_proto_common.o \ | 47 | nf_nat-y := nf_nat_core.o nf_nat_proto_unknown.o nf_nat_proto_common.o \ |
| 48 | nf_nat_proto_udp.o nf_nat_proto_tcp.o nf_nat_helper.o | 48 | nf_nat_proto_udp.o nf_nat_proto_tcp.o nf_nat_helper.o |
| 49 | 49 | ||
| 50 | # generic transport layer logging | ||
| 51 | obj-$(CONFIG_NF_LOG_COMMON) += nf_log_common.o | ||
| 52 | |||
| 50 | obj-$(CONFIG_NF_NAT) += nf_nat.o | 53 | obj-$(CONFIG_NF_NAT) += nf_nat.o |
| 51 | 54 | ||
| 52 | # NAT protocols (nf_nat) | 55 | # NAT protocols (nf_nat) |
diff --git a/net/netfilter/core.c b/net/netfilter/core.c index 1fbab0cdd302..a93c97f106d4 100644 --- a/net/netfilter/core.c +++ b/net/netfilter/core.c | |||
| @@ -35,11 +35,7 @@ EXPORT_SYMBOL_GPL(nf_ipv6_ops); | |||
| 35 | 35 | ||
| 36 | int nf_register_afinfo(const struct nf_afinfo *afinfo) | 36 | int nf_register_afinfo(const struct nf_afinfo *afinfo) |
| 37 | { | 37 | { |
| 38 | int err; | 38 | mutex_lock(&afinfo_mutex); |
| 39 | |||
| 40 | err = mutex_lock_interruptible(&afinfo_mutex); | ||
| 41 | if (err < 0) | ||
| 42 | return err; | ||
| 43 | RCU_INIT_POINTER(nf_afinfo[afinfo->family], afinfo); | 39 | RCU_INIT_POINTER(nf_afinfo[afinfo->family], afinfo); |
| 44 | mutex_unlock(&afinfo_mutex); | 40 | mutex_unlock(&afinfo_mutex); |
| 45 | return 0; | 41 | return 0; |
| @@ -68,11 +64,8 @@ static DEFINE_MUTEX(nf_hook_mutex); | |||
| 68 | int nf_register_hook(struct nf_hook_ops *reg) | 64 | int nf_register_hook(struct nf_hook_ops *reg) |
| 69 | { | 65 | { |
| 70 | struct nf_hook_ops *elem; | 66 | struct nf_hook_ops *elem; |
| 71 | int err; | ||
| 72 | 67 | ||
| 73 | err = mutex_lock_interruptible(&nf_hook_mutex); | 68 | mutex_lock(&nf_hook_mutex); |
| 74 | if (err < 0) | ||
| 75 | return err; | ||
| 76 | list_for_each_entry(elem, &nf_hooks[reg->pf][reg->hooknum], list) { | 69 | list_for_each_entry(elem, &nf_hooks[reg->pf][reg->hooknum], list) { |
| 77 | if (reg->priority < elem->priority) | 70 | if (reg->priority < elem->priority) |
| 78 | break; | 71 | break; |
diff --git a/net/netfilter/ipvs/ip_vs_ctl.c b/net/netfilter/ipvs/ip_vs_ctl.c index 581a6584ed0c..fd3f444a4f96 100644 --- a/net/netfilter/ipvs/ip_vs_ctl.c +++ b/net/netfilter/ipvs/ip_vs_ctl.c | |||
| @@ -1807,92 +1807,6 @@ static struct ctl_table vs_vars[] = { | |||
| 1807 | .proc_handler = proc_dointvec, | 1807 | .proc_handler = proc_dointvec, |
| 1808 | }, | 1808 | }, |
| 1809 | #endif | 1809 | #endif |
| 1810 | #if 0 | ||
| 1811 | { | ||
| 1812 | .procname = "timeout_established", | ||
| 1813 | .data = &vs_timeout_table_dos.timeout[IP_VS_S_ESTABLISHED], | ||
| 1814 | .maxlen = sizeof(int), | ||
| 1815 | .mode = 0644, | ||
| 1816 | .proc_handler = proc_dointvec_jiffies, | ||
| 1817 | }, | ||
| 1818 | { | ||
| 1819 | .procname = "timeout_synsent", | ||
| 1820 | .data = &vs_timeout_table_dos.timeout[IP_VS_S_SYN_SENT], | ||
| 1821 | .maxlen = sizeof(int), | ||
| 1822 | .mode = 0644, | ||
| 1823 | .proc_handler = proc_dointvec_jiffies, | ||
| 1824 | }, | ||
| 1825 | { | ||
| 1826 | .procname = "timeout_synrecv", | ||
| 1827 | .data = &vs_timeout_table_dos.timeout[IP_VS_S_SYN_RECV], | ||
| 1828 | .maxlen = sizeof(int), | ||
| 1829 | .mode = 0644, | ||
| 1830 | .proc_handler = proc_dointvec_jiffies, | ||
| 1831 | }, | ||
| 1832 | { | ||
| 1833 | .procname = "timeout_finwait", | ||
| 1834 | .data = &vs_timeout_table_dos.timeout[IP_VS_S_FIN_WAIT], | ||
| 1835 | .maxlen = sizeof(int), | ||
| 1836 | .mode = 0644, | ||
| 1837 | .proc_handler = proc_dointvec_jiffies, | ||
| 1838 | }, | ||
| 1839 | { | ||
| 1840 | .procname = "timeout_timewait", | ||
| 1841 | .data = &vs_timeout_table_dos.timeout[IP_VS_S_TIME_WAIT], | ||
| 1842 | .maxlen = sizeof(int), | ||
| 1843 | .mode = 0644, | ||
| 1844 | .proc_handler = proc_dointvec_jiffies, | ||
| 1845 | }, | ||
| 1846 | { | ||
| 1847 | .procname = "timeout_close", | ||
| 1848 | .data = &vs_timeout_table_dos.timeout[IP_VS_S_CLOSE], | ||
| 1849 | .maxlen = sizeof(int), | ||
| 1850 | .mode = 0644, | ||
| 1851 | .proc_handler = proc_dointvec_jiffies, | ||
| 1852 | }, | ||
| 1853 | { | ||
| 1854 | .procname = "timeout_closewait", | ||
| 1855 | .data = &vs_timeout_table_dos.timeout[IP_VS_S_CLOSE_WAIT], | ||
| 1856 | .maxlen = sizeof(int), | ||
| 1857 | .mode = 0644, | ||
| 1858 | .proc_handler = proc_dointvec_jiffies, | ||
| 1859 | }, | ||
| 1860 | { | ||
| 1861 | .procname = "timeout_lastack", | ||
| 1862 | .data = &vs_timeout_table_dos.timeout[IP_VS_S_LAST_ACK], | ||
| 1863 | .maxlen = sizeof(int), | ||
| 1864 | .mode = 0644, | ||
| 1865 | .proc_handler = proc_dointvec_jiffies, | ||
| 1866 | }, | ||
| 1867 | { | ||
| 1868 | .procname = "timeout_listen", | ||
| 1869 | .data = &vs_timeout_table_dos.timeout[IP_VS_S_LISTEN], | ||
| 1870 | .maxlen = sizeof(int), | ||
| 1871 | .mode = 0644, | ||
| 1872 | .proc_handler = proc_dointvec_jiffies, | ||
| 1873 | }, | ||
| 1874 | { | ||
| 1875 | .procname = "timeout_synack", | ||
| 1876 | .data = &vs_timeout_table_dos.timeout[IP_VS_S_SYNACK], | ||
| 1877 | .maxlen = sizeof(int), | ||
| 1878 | .mode = 0644, | ||
| 1879 | .proc_handler = proc_dointvec_jiffies, | ||
| 1880 | }, | ||
| 1881 | { | ||
| 1882 | .procname = "timeout_udp", | ||
| 1883 | .data = &vs_timeout_table_dos.timeout[IP_VS_S_UDP], | ||
| 1884 | .maxlen = sizeof(int), | ||
| 1885 | .mode = 0644, | ||
| 1886 | .proc_handler = proc_dointvec_jiffies, | ||
| 1887 | }, | ||
| 1888 | { | ||
| 1889 | .procname = "timeout_icmp", | ||
| 1890 | .data = &vs_timeout_table_dos.timeout[IP_VS_S_ICMP], | ||
| 1891 | .maxlen = sizeof(int), | ||
| 1892 | .mode = 0644, | ||
| 1893 | .proc_handler = proc_dointvec_jiffies, | ||
| 1894 | }, | ||
| 1895 | #endif | ||
| 1896 | { } | 1810 | { } |
| 1897 | }; | 1811 | }; |
| 1898 | 1812 | ||
| @@ -2357,10 +2271,7 @@ do_ip_vs_set_ctl(struct sock *sk, int cmd, void __user *user, unsigned int len) | |||
| 2357 | cmd == IP_VS_SO_SET_STOPDAEMON) { | 2271 | cmd == IP_VS_SO_SET_STOPDAEMON) { |
| 2358 | struct ip_vs_daemon_user *dm = (struct ip_vs_daemon_user *)arg; | 2272 | struct ip_vs_daemon_user *dm = (struct ip_vs_daemon_user *)arg; |
| 2359 | 2273 | ||
| 2360 | if (mutex_lock_interruptible(&ipvs->sync_mutex)) { | 2274 | mutex_lock(&ipvs->sync_mutex); |
| 2361 | ret = -ERESTARTSYS; | ||
| 2362 | goto out_dec; | ||
| 2363 | } | ||
| 2364 | if (cmd == IP_VS_SO_SET_STARTDAEMON) | 2275 | if (cmd == IP_VS_SO_SET_STARTDAEMON) |
| 2365 | ret = start_sync_thread(net, dm->state, dm->mcast_ifn, | 2276 | ret = start_sync_thread(net, dm->state, dm->mcast_ifn, |
| 2366 | dm->syncid); | 2277 | dm->syncid); |
| @@ -2370,11 +2281,7 @@ do_ip_vs_set_ctl(struct sock *sk, int cmd, void __user *user, unsigned int len) | |||
| 2370 | goto out_dec; | 2281 | goto out_dec; |
| 2371 | } | 2282 | } |
| 2372 | 2283 | ||
| 2373 | if (mutex_lock_interruptible(&__ip_vs_mutex)) { | 2284 | mutex_lock(&__ip_vs_mutex); |
| 2374 | ret = -ERESTARTSYS; | ||
| 2375 | goto out_dec; | ||
| 2376 | } | ||
| 2377 | |||
| 2378 | if (cmd == IP_VS_SO_SET_FLUSH) { | 2285 | if (cmd == IP_VS_SO_SET_FLUSH) { |
| 2379 | /* Flush the virtual service */ | 2286 | /* Flush the virtual service */ |
| 2380 | ret = ip_vs_flush(net, false); | 2287 | ret = ip_vs_flush(net, false); |
| @@ -2659,9 +2566,7 @@ do_ip_vs_get_ctl(struct sock *sk, int cmd, void __user *user, int *len) | |||
| 2659 | struct ip_vs_daemon_user d[2]; | 2566 | struct ip_vs_daemon_user d[2]; |
| 2660 | 2567 | ||
| 2661 | memset(&d, 0, sizeof(d)); | 2568 | memset(&d, 0, sizeof(d)); |
| 2662 | if (mutex_lock_interruptible(&ipvs->sync_mutex)) | 2569 | mutex_lock(&ipvs->sync_mutex); |
| 2663 | return -ERESTARTSYS; | ||
| 2664 | |||
| 2665 | if (ipvs->sync_state & IP_VS_STATE_MASTER) { | 2570 | if (ipvs->sync_state & IP_VS_STATE_MASTER) { |
| 2666 | d[0].state = IP_VS_STATE_MASTER; | 2571 | d[0].state = IP_VS_STATE_MASTER; |
| 2667 | strlcpy(d[0].mcast_ifn, ipvs->master_mcast_ifn, | 2572 | strlcpy(d[0].mcast_ifn, ipvs->master_mcast_ifn, |
| @@ -2680,9 +2585,7 @@ do_ip_vs_get_ctl(struct sock *sk, int cmd, void __user *user, int *len) | |||
| 2680 | return ret; | 2585 | return ret; |
| 2681 | } | 2586 | } |
| 2682 | 2587 | ||
| 2683 | if (mutex_lock_interruptible(&__ip_vs_mutex)) | 2588 | mutex_lock(&__ip_vs_mutex); |
| 2684 | return -ERESTARTSYS; | ||
| 2685 | |||
| 2686 | switch (cmd) { | 2589 | switch (cmd) { |
| 2687 | case IP_VS_SO_GET_VERSION: | 2590 | case IP_VS_SO_GET_VERSION: |
| 2688 | { | 2591 | { |
diff --git a/net/netfilter/ipvs/ip_vs_sync.c b/net/netfilter/ipvs/ip_vs_sync.c index db801263ee9f..eadffb29dec0 100644 --- a/net/netfilter/ipvs/ip_vs_sync.c +++ b/net/netfilter/ipvs/ip_vs_sync.c | |||
| @@ -886,8 +886,7 @@ static void ip_vs_proc_conn(struct net *net, struct ip_vs_conn_param *param, | |||
| 886 | cp = ip_vs_conn_new(param, daddr, dport, flags, dest, fwmark); | 886 | cp = ip_vs_conn_new(param, daddr, dport, flags, dest, fwmark); |
| 887 | rcu_read_unlock(); | 887 | rcu_read_unlock(); |
| 888 | if (!cp) { | 888 | if (!cp) { |
| 889 | if (param->pe_data) | 889 | kfree(param->pe_data); |
| 890 | kfree(param->pe_data); | ||
| 891 | IP_VS_DBG(2, "BACKUP, add new conn. failed\n"); | 890 | IP_VS_DBG(2, "BACKUP, add new conn. failed\n"); |
| 892 | return; | 891 | return; |
| 893 | } | 892 | } |
diff --git a/net/netfilter/ipvs/ip_vs_xmit.c b/net/netfilter/ipvs/ip_vs_xmit.c index 73ba1cc7a88d..6f70bdd3a90a 100644 --- a/net/netfilter/ipvs/ip_vs_xmit.c +++ b/net/netfilter/ipvs/ip_vs_xmit.c | |||
| @@ -967,8 +967,8 @@ ip_vs_tunnel_xmit_v6(struct sk_buff *skb, struct ip_vs_conn *cp, | |||
| 967 | iph->nexthdr = IPPROTO_IPV6; | 967 | iph->nexthdr = IPPROTO_IPV6; |
| 968 | iph->payload_len = old_iph->payload_len; | 968 | iph->payload_len = old_iph->payload_len; |
| 969 | be16_add_cpu(&iph->payload_len, sizeof(*old_iph)); | 969 | be16_add_cpu(&iph->payload_len, sizeof(*old_iph)); |
| 970 | iph->priority = old_iph->priority; | ||
| 971 | memset(&iph->flow_lbl, 0, sizeof(iph->flow_lbl)); | 970 | memset(&iph->flow_lbl, 0, sizeof(iph->flow_lbl)); |
| 971 | ipv6_change_dsfield(iph, 0, ipv6_get_dsfield(old_iph)); | ||
| 972 | iph->daddr = cp->daddr.in6; | 972 | iph->daddr = cp->daddr.in6; |
| 973 | iph->saddr = saddr; | 973 | iph->saddr = saddr; |
| 974 | iph->hop_limit = old_iph->hop_limit; | 974 | iph->hop_limit = old_iph->hop_limit; |
diff --git a/net/netfilter/nf_conntrack_core.c b/net/netfilter/nf_conntrack_core.c index 1f4f954c4b47..de88c4ab5146 100644 --- a/net/netfilter/nf_conntrack_core.c +++ b/net/netfilter/nf_conntrack_core.c | |||
| @@ -352,40 +352,6 @@ static void nf_ct_delete_from_lists(struct nf_conn *ct) | |||
| 352 | local_bh_enable(); | 352 | local_bh_enable(); |
| 353 | } | 353 | } |
| 354 | 354 | ||
| 355 | static void death_by_event(unsigned long ul_conntrack) | ||
| 356 | { | ||
| 357 | struct nf_conn *ct = (void *)ul_conntrack; | ||
| 358 | struct net *net = nf_ct_net(ct); | ||
| 359 | struct nf_conntrack_ecache *ecache = nf_ct_ecache_find(ct); | ||
| 360 | |||
| 361 | BUG_ON(ecache == NULL); | ||
| 362 | |||
| 363 | if (nf_conntrack_event(IPCT_DESTROY, ct) < 0) { | ||
| 364 | /* bad luck, let's retry again */ | ||
| 365 | ecache->timeout.expires = jiffies + | ||
| 366 | (prandom_u32() % net->ct.sysctl_events_retry_timeout); | ||
| 367 | add_timer(&ecache->timeout); | ||
| 368 | return; | ||
| 369 | } | ||
| 370 | /* we've got the event delivered, now it's dying */ | ||
| 371 | set_bit(IPS_DYING_BIT, &ct->status); | ||
| 372 | nf_ct_put(ct); | ||
| 373 | } | ||
| 374 | |||
| 375 | static void nf_ct_dying_timeout(struct nf_conn *ct) | ||
| 376 | { | ||
| 377 | struct net *net = nf_ct_net(ct); | ||
| 378 | struct nf_conntrack_ecache *ecache = nf_ct_ecache_find(ct); | ||
| 379 | |||
| 380 | BUG_ON(ecache == NULL); | ||
| 381 | |||
| 382 | /* set a new timer to retry event delivery */ | ||
| 383 | setup_timer(&ecache->timeout, death_by_event, (unsigned long)ct); | ||
| 384 | ecache->timeout.expires = jiffies + | ||
| 385 | (prandom_u32() % net->ct.sysctl_events_retry_timeout); | ||
| 386 | add_timer(&ecache->timeout); | ||
| 387 | } | ||
| 388 | |||
| 389 | bool nf_ct_delete(struct nf_conn *ct, u32 portid, int report) | 355 | bool nf_ct_delete(struct nf_conn *ct, u32 portid, int report) |
| 390 | { | 356 | { |
| 391 | struct nf_conn_tstamp *tstamp; | 357 | struct nf_conn_tstamp *tstamp; |
| @@ -394,15 +360,20 @@ bool nf_ct_delete(struct nf_conn *ct, u32 portid, int report) | |||
| 394 | if (tstamp && tstamp->stop == 0) | 360 | if (tstamp && tstamp->stop == 0) |
| 395 | tstamp->stop = ktime_to_ns(ktime_get_real()); | 361 | tstamp->stop = ktime_to_ns(ktime_get_real()); |
| 396 | 362 | ||
| 397 | if (!nf_ct_is_dying(ct) && | 363 | if (nf_ct_is_dying(ct)) |
| 398 | unlikely(nf_conntrack_event_report(IPCT_DESTROY, ct, | 364 | goto delete; |
| 399 | portid, report) < 0)) { | 365 | |
| 366 | if (nf_conntrack_event_report(IPCT_DESTROY, ct, | ||
| 367 | portid, report) < 0) { | ||
| 400 | /* destroy event was not delivered */ | 368 | /* destroy event was not delivered */ |
| 401 | nf_ct_delete_from_lists(ct); | 369 | nf_ct_delete_from_lists(ct); |
| 402 | nf_ct_dying_timeout(ct); | 370 | nf_conntrack_ecache_delayed_work(nf_ct_net(ct)); |
| 403 | return false; | 371 | return false; |
| 404 | } | 372 | } |
| 373 | |||
| 374 | nf_conntrack_ecache_work(nf_ct_net(ct)); | ||
| 405 | set_bit(IPS_DYING_BIT, &ct->status); | 375 | set_bit(IPS_DYING_BIT, &ct->status); |
| 376 | delete: | ||
| 406 | nf_ct_delete_from_lists(ct); | 377 | nf_ct_delete_from_lists(ct); |
| 407 | nf_ct_put(ct); | 378 | nf_ct_put(ct); |
| 408 | return true; | 379 | return true; |
| @@ -1464,26 +1435,6 @@ void nf_conntrack_flush_report(struct net *net, u32 portid, int report) | |||
| 1464 | } | 1435 | } |
| 1465 | EXPORT_SYMBOL_GPL(nf_conntrack_flush_report); | 1436 | EXPORT_SYMBOL_GPL(nf_conntrack_flush_report); |
| 1466 | 1437 | ||
| 1467 | static void nf_ct_release_dying_list(struct net *net) | ||
| 1468 | { | ||
| 1469 | struct nf_conntrack_tuple_hash *h; | ||
| 1470 | struct nf_conn *ct; | ||
| 1471 | struct hlist_nulls_node *n; | ||
| 1472 | int cpu; | ||
| 1473 | |||
| 1474 | for_each_possible_cpu(cpu) { | ||
| 1475 | struct ct_pcpu *pcpu = per_cpu_ptr(net->ct.pcpu_lists, cpu); | ||
| 1476 | |||
| 1477 | spin_lock_bh(&pcpu->lock); | ||
| 1478 | hlist_nulls_for_each_entry(h, n, &pcpu->dying, hnnode) { | ||
| 1479 | ct = nf_ct_tuplehash_to_ctrack(h); | ||
| 1480 | /* never fails to remove them, no listeners at this point */ | ||
| 1481 | nf_ct_kill(ct); | ||
| 1482 | } | ||
| 1483 | spin_unlock_bh(&pcpu->lock); | ||
| 1484 | } | ||
| 1485 | } | ||
| 1486 | |||
| 1487 | static int untrack_refs(void) | 1438 | static int untrack_refs(void) |
| 1488 | { | 1439 | { |
| 1489 | int cnt = 0, cpu; | 1440 | int cnt = 0, cpu; |
| @@ -1548,7 +1499,6 @@ i_see_dead_people: | |||
| 1548 | busy = 0; | 1499 | busy = 0; |
| 1549 | list_for_each_entry(net, net_exit_list, exit_list) { | 1500 | list_for_each_entry(net, net_exit_list, exit_list) { |
| 1550 | nf_ct_iterate_cleanup(net, kill_all, NULL, 0, 0); | 1501 | nf_ct_iterate_cleanup(net, kill_all, NULL, 0, 0); |
| 1551 | nf_ct_release_dying_list(net); | ||
| 1552 | if (atomic_read(&net->ct.count) != 0) | 1502 | if (atomic_read(&net->ct.count) != 0) |
| 1553 | busy = 1; | 1503 | busy = 1; |
| 1554 | } | 1504 | } |
diff --git a/net/netfilter/nf_conntrack_ecache.c b/net/netfilter/nf_conntrack_ecache.c index 1df176146567..4e78c57b818f 100644 --- a/net/netfilter/nf_conntrack_ecache.c +++ b/net/netfilter/nf_conntrack_ecache.c | |||
| @@ -29,6 +29,90 @@ | |||
| 29 | 29 | ||
| 30 | static DEFINE_MUTEX(nf_ct_ecache_mutex); | 30 | static DEFINE_MUTEX(nf_ct_ecache_mutex); |
| 31 | 31 | ||
| 32 | #define ECACHE_RETRY_WAIT (HZ/10) | ||
| 33 | |||
| 34 | enum retry_state { | ||
| 35 | STATE_CONGESTED, | ||
| 36 | STATE_RESTART, | ||
| 37 | STATE_DONE, | ||
| 38 | }; | ||
| 39 | |||
| 40 | static enum retry_state ecache_work_evict_list(struct ct_pcpu *pcpu) | ||
| 41 | { | ||
| 42 | struct nf_conn *refs[16]; | ||
| 43 | struct nf_conntrack_tuple_hash *h; | ||
| 44 | struct hlist_nulls_node *n; | ||
| 45 | unsigned int evicted = 0; | ||
| 46 | enum retry_state ret = STATE_DONE; | ||
| 47 | |||
| 48 | spin_lock(&pcpu->lock); | ||
| 49 | |||
| 50 | hlist_nulls_for_each_entry(h, n, &pcpu->dying, hnnode) { | ||
| 51 | struct nf_conn *ct = nf_ct_tuplehash_to_ctrack(h); | ||
| 52 | |||
| 53 | if (nf_ct_is_dying(ct)) | ||
| 54 | continue; | ||
| 55 | |||
| 56 | if (nf_conntrack_event(IPCT_DESTROY, ct)) { | ||
| 57 | ret = STATE_CONGESTED; | ||
| 58 | break; | ||
| 59 | } | ||
| 60 | |||
| 61 | /* we've got the event delivered, now it's dying */ | ||
| 62 | set_bit(IPS_DYING_BIT, &ct->status); | ||
| 63 | refs[evicted] = ct; | ||
| 64 | |||
| 65 | if (++evicted >= ARRAY_SIZE(refs)) { | ||
| 66 | ret = STATE_RESTART; | ||
| 67 | break; | ||
| 68 | } | ||
| 69 | } | ||
| 70 | |||
| 71 | spin_unlock(&pcpu->lock); | ||
| 72 | |||
| 73 | /* can't _put while holding lock */ | ||
| 74 | while (evicted) | ||
| 75 | nf_ct_put(refs[--evicted]); | ||
| 76 | |||
| 77 | return ret; | ||
| 78 | } | ||
| 79 | |||
| 80 | static void ecache_work(struct work_struct *work) | ||
| 81 | { | ||
| 82 | struct netns_ct *ctnet = | ||
| 83 | container_of(work, struct netns_ct, ecache_dwork.work); | ||
| 84 | int cpu, delay = -1; | ||
| 85 | struct ct_pcpu *pcpu; | ||
| 86 | |||
| 87 | local_bh_disable(); | ||
| 88 | |||
| 89 | for_each_possible_cpu(cpu) { | ||
| 90 | enum retry_state ret; | ||
| 91 | |||
| 92 | pcpu = per_cpu_ptr(ctnet->pcpu_lists, cpu); | ||
| 93 | |||
| 94 | ret = ecache_work_evict_list(pcpu); | ||
| 95 | |||
| 96 | switch (ret) { | ||
| 97 | case STATE_CONGESTED: | ||
| 98 | delay = ECACHE_RETRY_WAIT; | ||
| 99 | goto out; | ||
| 100 | case STATE_RESTART: | ||
| 101 | delay = 0; | ||
| 102 | break; | ||
| 103 | case STATE_DONE: | ||
| 104 | break; | ||
| 105 | } | ||
| 106 | } | ||
| 107 | |||
| 108 | out: | ||
| 109 | local_bh_enable(); | ||
| 110 | |||
| 111 | ctnet->ecache_dwork_pending = delay > 0; | ||
| 112 | if (delay >= 0) | ||
| 113 | schedule_delayed_work(&ctnet->ecache_dwork, delay); | ||
| 114 | } | ||
| 115 | |||
| 32 | /* deliver cached events and clear cache entry - must be called with locally | 116 | /* deliver cached events and clear cache entry - must be called with locally |
| 33 | * disabled softirqs */ | 117 | * disabled softirqs */ |
| 34 | void nf_ct_deliver_cached_events(struct nf_conn *ct) | 118 | void nf_ct_deliver_cached_events(struct nf_conn *ct) |
| @@ -157,7 +241,6 @@ EXPORT_SYMBOL_GPL(nf_ct_expect_unregister_notifier); | |||
| 157 | 241 | ||
| 158 | #define NF_CT_EVENTS_DEFAULT 1 | 242 | #define NF_CT_EVENTS_DEFAULT 1 |
| 159 | static int nf_ct_events __read_mostly = NF_CT_EVENTS_DEFAULT; | 243 | static int nf_ct_events __read_mostly = NF_CT_EVENTS_DEFAULT; |
| 160 | static int nf_ct_events_retry_timeout __read_mostly = 15*HZ; | ||
| 161 | 244 | ||
| 162 | #ifdef CONFIG_SYSCTL | 245 | #ifdef CONFIG_SYSCTL |
| 163 | static struct ctl_table event_sysctl_table[] = { | 246 | static struct ctl_table event_sysctl_table[] = { |
| @@ -168,13 +251,6 @@ static struct ctl_table event_sysctl_table[] = { | |||
| 168 | .mode = 0644, | 251 | .mode = 0644, |
| 169 | .proc_handler = proc_dointvec, | 252 | .proc_handler = proc_dointvec, |
| 170 | }, | 253 | }, |
| 171 | { | ||
| 172 | .procname = "nf_conntrack_events_retry_timeout", | ||
| 173 | .data = &init_net.ct.sysctl_events_retry_timeout, | ||
| 174 | .maxlen = sizeof(unsigned int), | ||
| 175 | .mode = 0644, | ||
| 176 | .proc_handler = proc_dointvec_jiffies, | ||
| 177 | }, | ||
| 178 | {} | 254 | {} |
| 179 | }; | 255 | }; |
| 180 | #endif /* CONFIG_SYSCTL */ | 256 | #endif /* CONFIG_SYSCTL */ |
| @@ -196,7 +272,6 @@ static int nf_conntrack_event_init_sysctl(struct net *net) | |||
| 196 | goto out; | 272 | goto out; |
| 197 | 273 | ||
| 198 | table[0].data = &net->ct.sysctl_events; | 274 | table[0].data = &net->ct.sysctl_events; |
| 199 | table[1].data = &net->ct.sysctl_events_retry_timeout; | ||
| 200 | 275 | ||
| 201 | /* Don't export sysctls to unprivileged users */ | 276 | /* Don't export sysctls to unprivileged users */ |
| 202 | if (net->user_ns != &init_user_ns) | 277 | if (net->user_ns != &init_user_ns) |
| @@ -238,12 +313,13 @@ static void nf_conntrack_event_fini_sysctl(struct net *net) | |||
| 238 | int nf_conntrack_ecache_pernet_init(struct net *net) | 313 | int nf_conntrack_ecache_pernet_init(struct net *net) |
| 239 | { | 314 | { |
| 240 | net->ct.sysctl_events = nf_ct_events; | 315 | net->ct.sysctl_events = nf_ct_events; |
| 241 | net->ct.sysctl_events_retry_timeout = nf_ct_events_retry_timeout; | 316 | INIT_DELAYED_WORK(&net->ct.ecache_dwork, ecache_work); |
| 242 | return nf_conntrack_event_init_sysctl(net); | 317 | return nf_conntrack_event_init_sysctl(net); |
| 243 | } | 318 | } |
| 244 | 319 | ||
| 245 | void nf_conntrack_ecache_pernet_fini(struct net *net) | 320 | void nf_conntrack_ecache_pernet_fini(struct net *net) |
| 246 | { | 321 | { |
| 322 | cancel_delayed_work_sync(&net->ct.ecache_dwork); | ||
| 247 | nf_conntrack_event_fini_sysctl(net); | 323 | nf_conntrack_event_fini_sysctl(net); |
| 248 | } | 324 | } |
| 249 | 325 | ||
diff --git a/net/netfilter/nf_conntrack_netlink.c b/net/netfilter/nf_conntrack_netlink.c index 300ed1eec729..355a5c4ef763 100644 --- a/net/netfilter/nf_conntrack_netlink.c +++ b/net/netfilter/nf_conntrack_netlink.c | |||
| @@ -745,8 +745,7 @@ static int ctnetlink_done(struct netlink_callback *cb) | |||
| 745 | { | 745 | { |
| 746 | if (cb->args[1]) | 746 | if (cb->args[1]) |
| 747 | nf_ct_put((struct nf_conn *)cb->args[1]); | 747 | nf_ct_put((struct nf_conn *)cb->args[1]); |
| 748 | if (cb->data) | 748 | kfree(cb->data); |
| 749 | kfree(cb->data); | ||
| 750 | return 0; | 749 | return 0; |
| 751 | } | 750 | } |
| 752 | 751 | ||
diff --git a/net/netfilter/nf_log.c b/net/netfilter/nf_log.c index 85296d4eac0e..daad6022c689 100644 --- a/net/netfilter/nf_log.c +++ b/net/netfilter/nf_log.c | |||
| @@ -16,16 +16,22 @@ | |||
| 16 | #define NF_LOG_PREFIXLEN 128 | 16 | #define NF_LOG_PREFIXLEN 128 |
| 17 | #define NFLOGGER_NAME_LEN 64 | 17 | #define NFLOGGER_NAME_LEN 64 |
| 18 | 18 | ||
| 19 | static struct list_head nf_loggers_l[NFPROTO_NUMPROTO] __read_mostly; | 19 | static struct nf_logger __rcu *loggers[NFPROTO_NUMPROTO][NF_LOG_TYPE_MAX] __read_mostly; |
| 20 | static DEFINE_MUTEX(nf_log_mutex); | 20 | static DEFINE_MUTEX(nf_log_mutex); |
| 21 | 21 | ||
| 22 | static struct nf_logger *__find_logger(int pf, const char *str_logger) | 22 | static struct nf_logger *__find_logger(int pf, const char *str_logger) |
| 23 | { | 23 | { |
| 24 | struct nf_logger *t; | 24 | struct nf_logger *log; |
| 25 | int i; | ||
| 26 | |||
| 27 | for (i = 0; i < NF_LOG_TYPE_MAX; i++) { | ||
| 28 | if (loggers[pf][i] == NULL) | ||
| 29 | continue; | ||
| 25 | 30 | ||
| 26 | list_for_each_entry(t, &nf_loggers_l[pf], list[pf]) { | 31 | log = rcu_dereference_protected(loggers[pf][i], |
| 27 | if (!strnicmp(str_logger, t->name, strlen(t->name))) | 32 | lockdep_is_held(&nf_log_mutex)); |
| 28 | return t; | 33 | if (!strnicmp(str_logger, log->name, strlen(log->name))) |
| 34 | return log; | ||
| 29 | } | 35 | } |
| 30 | 36 | ||
| 31 | return NULL; | 37 | return NULL; |
| @@ -73,17 +79,14 @@ int nf_log_register(u_int8_t pf, struct nf_logger *logger) | |||
| 73 | if (pf >= ARRAY_SIZE(init_net.nf.nf_loggers)) | 79 | if (pf >= ARRAY_SIZE(init_net.nf.nf_loggers)) |
| 74 | return -EINVAL; | 80 | return -EINVAL; |
| 75 | 81 | ||
| 76 | for (i = 0; i < ARRAY_SIZE(logger->list); i++) | ||
| 77 | INIT_LIST_HEAD(&logger->list[i]); | ||
| 78 | |||
| 79 | mutex_lock(&nf_log_mutex); | 82 | mutex_lock(&nf_log_mutex); |
| 80 | 83 | ||
| 81 | if (pf == NFPROTO_UNSPEC) { | 84 | if (pf == NFPROTO_UNSPEC) { |
| 82 | for (i = NFPROTO_UNSPEC; i < NFPROTO_NUMPROTO; i++) | 85 | for (i = NFPROTO_UNSPEC; i < NFPROTO_NUMPROTO; i++) |
| 83 | list_add_tail(&(logger->list[i]), &(nf_loggers_l[i])); | 86 | rcu_assign_pointer(loggers[i][logger->type], logger); |
| 84 | } else { | 87 | } else { |
| 85 | /* register at end of list to honor first register win */ | 88 | /* register at end of list to honor first register win */ |
| 86 | list_add_tail(&logger->list[pf], &nf_loggers_l[pf]); | 89 | rcu_assign_pointer(loggers[pf][logger->type], logger); |
| 87 | } | 90 | } |
| 88 | 91 | ||
| 89 | mutex_unlock(&nf_log_mutex); | 92 | mutex_unlock(&nf_log_mutex); |
| @@ -98,7 +101,7 @@ void nf_log_unregister(struct nf_logger *logger) | |||
| 98 | 101 | ||
| 99 | mutex_lock(&nf_log_mutex); | 102 | mutex_lock(&nf_log_mutex); |
| 100 | for (i = 0; i < NFPROTO_NUMPROTO; i++) | 103 | for (i = 0; i < NFPROTO_NUMPROTO; i++) |
| 101 | list_del(&logger->list[i]); | 104 | RCU_INIT_POINTER(loggers[i][logger->type], NULL); |
| 102 | mutex_unlock(&nf_log_mutex); | 105 | mutex_unlock(&nf_log_mutex); |
| 103 | } | 106 | } |
| 104 | EXPORT_SYMBOL(nf_log_unregister); | 107 | EXPORT_SYMBOL(nf_log_unregister); |
| @@ -129,6 +132,48 @@ void nf_log_unbind_pf(struct net *net, u_int8_t pf) | |||
| 129 | } | 132 | } |
| 130 | EXPORT_SYMBOL(nf_log_unbind_pf); | 133 | EXPORT_SYMBOL(nf_log_unbind_pf); |
| 131 | 134 | ||
| 135 | void nf_logger_request_module(int pf, enum nf_log_type type) | ||
| 136 | { | ||
| 137 | if (loggers[pf][type] == NULL) | ||
| 138 | request_module("nf-logger-%u-%u", pf, type); | ||
| 139 | } | ||
| 140 | EXPORT_SYMBOL_GPL(nf_logger_request_module); | ||
| 141 | |||
| 142 | int nf_logger_find_get(int pf, enum nf_log_type type) | ||
| 143 | { | ||
| 144 | struct nf_logger *logger; | ||
| 145 | int ret = -ENOENT; | ||
| 146 | |||
| 147 | logger = loggers[pf][type]; | ||
| 148 | if (logger == NULL) | ||
| 149 | request_module("nf-logger-%u-%u", pf, type); | ||
| 150 | |||
| 151 | rcu_read_lock(); | ||
| 152 | logger = rcu_dereference(loggers[pf][type]); | ||
| 153 | if (logger == NULL) | ||
| 154 | goto out; | ||
| 155 | |||
| 156 | if (logger && try_module_get(logger->me)) | ||
| 157 | ret = 0; | ||
| 158 | out: | ||
| 159 | rcu_read_unlock(); | ||
| 160 | return ret; | ||
| 161 | } | ||
| 162 | EXPORT_SYMBOL_GPL(nf_logger_find_get); | ||
| 163 | |||
| 164 | void nf_logger_put(int pf, enum nf_log_type type) | ||
| 165 | { | ||
| 166 | struct nf_logger *logger; | ||
| 167 | |||
| 168 | BUG_ON(loggers[pf][type] == NULL); | ||
| 169 | |||
| 170 | rcu_read_lock(); | ||
| 171 | logger = rcu_dereference(loggers[pf][type]); | ||
| 172 | module_put(logger->me); | ||
| 173 | rcu_read_unlock(); | ||
| 174 | } | ||
| 175 | EXPORT_SYMBOL_GPL(nf_logger_put); | ||
| 176 | |||
| 132 | void nf_log_packet(struct net *net, | 177 | void nf_log_packet(struct net *net, |
| 133 | u_int8_t pf, | 178 | u_int8_t pf, |
| 134 | unsigned int hooknum, | 179 | unsigned int hooknum, |
| @@ -143,7 +188,11 @@ void nf_log_packet(struct net *net, | |||
| 143 | const struct nf_logger *logger; | 188 | const struct nf_logger *logger; |
| 144 | 189 | ||
| 145 | rcu_read_lock(); | 190 | rcu_read_lock(); |
| 146 | logger = rcu_dereference(net->nf.nf_loggers[pf]); | 191 | if (loginfo != NULL) |
| 192 | logger = rcu_dereference(loggers[pf][loginfo->type]); | ||
| 193 | else | ||
| 194 | logger = rcu_dereference(net->nf.nf_loggers[pf]); | ||
| 195 | |||
| 147 | if (logger) { | 196 | if (logger) { |
| 148 | va_start(args, fmt); | 197 | va_start(args, fmt); |
| 149 | vsnprintf(prefix, sizeof(prefix), fmt, args); | 198 | vsnprintf(prefix, sizeof(prefix), fmt, args); |
| @@ -154,6 +203,63 @@ void nf_log_packet(struct net *net, | |||
| 154 | } | 203 | } |
| 155 | EXPORT_SYMBOL(nf_log_packet); | 204 | EXPORT_SYMBOL(nf_log_packet); |
| 156 | 205 | ||
| 206 | #define S_SIZE (1024 - (sizeof(unsigned int) + 1)) | ||
| 207 | |||
| 208 | struct nf_log_buf { | ||
| 209 | unsigned int count; | ||
| 210 | char buf[S_SIZE + 1]; | ||
| 211 | }; | ||
| 212 | static struct nf_log_buf emergency, *emergency_ptr = &emergency; | ||
| 213 | |||
| 214 | __printf(2, 3) int nf_log_buf_add(struct nf_log_buf *m, const char *f, ...) | ||
| 215 | { | ||
| 216 | va_list args; | ||
| 217 | int len; | ||
| 218 | |||
| 219 | if (likely(m->count < S_SIZE)) { | ||
| 220 | va_start(args, f); | ||
| 221 | len = vsnprintf(m->buf + m->count, S_SIZE - m->count, f, args); | ||
| 222 | va_end(args); | ||
| 223 | if (likely(m->count + len < S_SIZE)) { | ||
| 224 | m->count += len; | ||
| 225 | return 0; | ||
| 226 | } | ||
| 227 | } | ||
| 228 | m->count = S_SIZE; | ||
| 229 | printk_once(KERN_ERR KBUILD_MODNAME " please increase S_SIZE\n"); | ||
| 230 | return -1; | ||
| 231 | } | ||
| 232 | EXPORT_SYMBOL_GPL(nf_log_buf_add); | ||
| 233 | |||
| 234 | struct nf_log_buf *nf_log_buf_open(void) | ||
| 235 | { | ||
| 236 | struct nf_log_buf *m = kmalloc(sizeof(*m), GFP_ATOMIC); | ||
| 237 | |||
| 238 | if (unlikely(!m)) { | ||
| 239 | local_bh_disable(); | ||
| 240 | do { | ||
| 241 | m = xchg(&emergency_ptr, NULL); | ||
| 242 | } while (!m); | ||
| 243 | } | ||
| 244 | m->count = 0; | ||
| 245 | return m; | ||
| 246 | } | ||
| 247 | EXPORT_SYMBOL_GPL(nf_log_buf_open); | ||
| 248 | |||
| 249 | void nf_log_buf_close(struct nf_log_buf *m) | ||
| 250 | { | ||
| 251 | m->buf[m->count] = 0; | ||
| 252 | printk("%s\n", m->buf); | ||
| 253 | |||
| 254 | if (likely(m != &emergency)) | ||
| 255 | kfree(m); | ||
| 256 | else { | ||
| 257 | emergency_ptr = m; | ||
| 258 | local_bh_enable(); | ||
| 259 | } | ||
| 260 | } | ||
| 261 | EXPORT_SYMBOL_GPL(nf_log_buf_close); | ||
| 262 | |||
| 157 | #ifdef CONFIG_PROC_FS | 263 | #ifdef CONFIG_PROC_FS |
| 158 | static void *seq_start(struct seq_file *seq, loff_t *pos) | 264 | static void *seq_start(struct seq_file *seq, loff_t *pos) |
| 159 | { | 265 | { |
| @@ -188,8 +294,7 @@ static int seq_show(struct seq_file *s, void *v) | |||
| 188 | { | 294 | { |
| 189 | loff_t *pos = v; | 295 | loff_t *pos = v; |
| 190 | const struct nf_logger *logger; | 296 | const struct nf_logger *logger; |
| 191 | struct nf_logger *t; | 297 | int i, ret; |
| 192 | int ret; | ||
| 193 | struct net *net = seq_file_net(s); | 298 | struct net *net = seq_file_net(s); |
| 194 | 299 | ||
| 195 | logger = rcu_dereference_protected(net->nf.nf_loggers[*pos], | 300 | logger = rcu_dereference_protected(net->nf.nf_loggers[*pos], |
| @@ -203,11 +308,16 @@ static int seq_show(struct seq_file *s, void *v) | |||
| 203 | if (ret < 0) | 308 | if (ret < 0) |
| 204 | return ret; | 309 | return ret; |
| 205 | 310 | ||
| 206 | list_for_each_entry(t, &nf_loggers_l[*pos], list[*pos]) { | 311 | for (i = 0; i < NF_LOG_TYPE_MAX; i++) { |
| 207 | ret = seq_printf(s, "%s", t->name); | 312 | if (loggers[*pos][i] == NULL) |
| 313 | continue; | ||
| 314 | |||
| 315 | logger = rcu_dereference_protected(loggers[*pos][i], | ||
| 316 | lockdep_is_held(&nf_log_mutex)); | ||
| 317 | ret = seq_printf(s, "%s", logger->name); | ||
| 208 | if (ret < 0) | 318 | if (ret < 0) |
| 209 | return ret; | 319 | return ret; |
| 210 | if (&t->list[*pos] != nf_loggers_l[*pos].prev) { | 320 | if (i == 0 && loggers[*pos][i + 1] != NULL) { |
| 211 | ret = seq_printf(s, ","); | 321 | ret = seq_printf(s, ","); |
| 212 | if (ret < 0) | 322 | if (ret < 0) |
| 213 | return ret; | 323 | return ret; |
| @@ -389,14 +499,5 @@ static struct pernet_operations nf_log_net_ops = { | |||
| 389 | 499 | ||
| 390 | int __init netfilter_log_init(void) | 500 | int __init netfilter_log_init(void) |
| 391 | { | 501 | { |
| 392 | int i, ret; | 502 | return register_pernet_subsys(&nf_log_net_ops); |
| 393 | |||
| 394 | ret = register_pernet_subsys(&nf_log_net_ops); | ||
| 395 | if (ret < 0) | ||
| 396 | return ret; | ||
| 397 | |||
| 398 | for (i = NFPROTO_UNSPEC; i < NFPROTO_NUMPROTO; i++) | ||
| 399 | INIT_LIST_HEAD(&(nf_loggers_l[i])); | ||
| 400 | |||
| 401 | return 0; | ||
| 402 | } | 503 | } |
diff --git a/net/netfilter/nf_log_common.c b/net/netfilter/nf_log_common.c new file mode 100644 index 000000000000..eeb8ef4ff1a3 --- /dev/null +++ b/net/netfilter/nf_log_common.c | |||
| @@ -0,0 +1,187 @@ | |||
| 1 | /* (C) 1999-2001 Paul `Rusty' Russell | ||
| 2 | * (C) 2002-2004 Netfilter Core Team <coreteam@netfilter.org> | ||
| 3 | * | ||
| 4 | * This program is free software; you can redistribute it and/or modify | ||
| 5 | * it under the terms of the GNU General Public License version 2 as | ||
| 6 | * published by the Free Software Foundation. | ||
| 7 | */ | ||
| 8 | |||
| 9 | #include <linux/module.h> | ||
| 10 | #include <linux/spinlock.h> | ||
| 11 | #include <linux/skbuff.h> | ||
| 12 | #include <linux/if_arp.h> | ||
| 13 | #include <linux/ip.h> | ||
| 14 | #include <net/icmp.h> | ||
| 15 | #include <net/udp.h> | ||
| 16 | #include <net/tcp.h> | ||
| 17 | #include <net/route.h> | ||
| 18 | |||
| 19 | #include <linux/netfilter.h> | ||
| 20 | #include <linux/netfilter/xt_LOG.h> | ||
| 21 | #include <net/netfilter/nf_log.h> | ||
| 22 | |||
| 23 | int nf_log_dump_udp_header(struct nf_log_buf *m, const struct sk_buff *skb, | ||
| 24 | u8 proto, int fragment, unsigned int offset) | ||
| 25 | { | ||
| 26 | struct udphdr _udph; | ||
| 27 | const struct udphdr *uh; | ||
| 28 | |||
| 29 | if (proto == IPPROTO_UDP) | ||
| 30 | /* Max length: 10 "PROTO=UDP " */ | ||
| 31 | nf_log_buf_add(m, "PROTO=UDP "); | ||
| 32 | else /* Max length: 14 "PROTO=UDPLITE " */ | ||
| 33 | nf_log_buf_add(m, "PROTO=UDPLITE "); | ||
| 34 | |||
| 35 | if (fragment) | ||
| 36 | goto out; | ||
| 37 | |||
| 38 | /* Max length: 25 "INCOMPLETE [65535 bytes] " */ | ||
| 39 | uh = skb_header_pointer(skb, offset, sizeof(_udph), &_udph); | ||
| 40 | if (uh == NULL) { | ||
| 41 | nf_log_buf_add(m, "INCOMPLETE [%u bytes] ", skb->len - offset); | ||
| 42 | |||
| 43 | return 1; | ||
| 44 | } | ||
| 45 | |||
| 46 | /* Max length: 20 "SPT=65535 DPT=65535 " */ | ||
| 47 | nf_log_buf_add(m, "SPT=%u DPT=%u LEN=%u ", | ||
| 48 | ntohs(uh->source), ntohs(uh->dest), ntohs(uh->len)); | ||
| 49 | |||
| 50 | out: | ||
| 51 | return 0; | ||
| 52 | } | ||
| 53 | EXPORT_SYMBOL_GPL(nf_log_dump_udp_header); | ||
| 54 | |||
| 55 | int nf_log_dump_tcp_header(struct nf_log_buf *m, const struct sk_buff *skb, | ||
| 56 | u8 proto, int fragment, unsigned int offset, | ||
| 57 | unsigned int logflags) | ||
| 58 | { | ||
| 59 | struct tcphdr _tcph; | ||
| 60 | const struct tcphdr *th; | ||
| 61 | |||
| 62 | /* Max length: 10 "PROTO=TCP " */ | ||
| 63 | nf_log_buf_add(m, "PROTO=TCP "); | ||
| 64 | |||
| 65 | if (fragment) | ||
| 66 | return 0; | ||
| 67 | |||
| 68 | /* Max length: 25 "INCOMPLETE [65535 bytes] " */ | ||
| 69 | th = skb_header_pointer(skb, offset, sizeof(_tcph), &_tcph); | ||
| 70 | if (th == NULL) { | ||
| 71 | nf_log_buf_add(m, "INCOMPLETE [%u bytes] ", skb->len - offset); | ||
| 72 | return 1; | ||
| 73 | } | ||
| 74 | |||
| 75 | /* Max length: 20 "SPT=65535 DPT=65535 " */ | ||
| 76 | nf_log_buf_add(m, "SPT=%u DPT=%u ", | ||
| 77 | ntohs(th->source), ntohs(th->dest)); | ||
| 78 | /* Max length: 30 "SEQ=4294967295 ACK=4294967295 " */ | ||
| 79 | if (logflags & XT_LOG_TCPSEQ) { | ||
| 80 | nf_log_buf_add(m, "SEQ=%u ACK=%u ", | ||
| 81 | ntohl(th->seq), ntohl(th->ack_seq)); | ||
| 82 | } | ||
| 83 | |||
| 84 | /* Max length: 13 "WINDOW=65535 " */ | ||
| 85 | nf_log_buf_add(m, "WINDOW=%u ", ntohs(th->window)); | ||
| 86 | /* Max length: 9 "RES=0x3C " */ | ||
| 87 | nf_log_buf_add(m, "RES=0x%02x ", (u_int8_t)(ntohl(tcp_flag_word(th) & | ||
| 88 | TCP_RESERVED_BITS) >> 22)); | ||
| 89 | /* Max length: 32 "CWR ECE URG ACK PSH RST SYN FIN " */ | ||
| 90 | if (th->cwr) | ||
| 91 | nf_log_buf_add(m, "CWR "); | ||
| 92 | if (th->ece) | ||
| 93 | nf_log_buf_add(m, "ECE "); | ||
| 94 | if (th->urg) | ||
| 95 | nf_log_buf_add(m, "URG "); | ||
| 96 | if (th->ack) | ||
| 97 | nf_log_buf_add(m, "ACK "); | ||
| 98 | if (th->psh) | ||
| 99 | nf_log_buf_add(m, "PSH "); | ||
| 100 | if (th->rst) | ||
| 101 | nf_log_buf_add(m, "RST "); | ||
| 102 | if (th->syn) | ||
| 103 | nf_log_buf_add(m, "SYN "); | ||
| 104 | if (th->fin) | ||
| 105 | nf_log_buf_add(m, "FIN "); | ||
| 106 | /* Max length: 11 "URGP=65535 " */ | ||
| 107 | nf_log_buf_add(m, "URGP=%u ", ntohs(th->urg_ptr)); | ||
| 108 | |||
| 109 | if ((logflags & XT_LOG_TCPOPT) && th->doff*4 > sizeof(struct tcphdr)) { | ||
| 110 | u_int8_t _opt[60 - sizeof(struct tcphdr)]; | ||
| 111 | const u_int8_t *op; | ||
| 112 | unsigned int i; | ||
| 113 | unsigned int optsize = th->doff*4 - sizeof(struct tcphdr); | ||
| 114 | |||
| 115 | op = skb_header_pointer(skb, offset + sizeof(struct tcphdr), | ||
| 116 | optsize, _opt); | ||
| 117 | if (op == NULL) { | ||
| 118 | nf_log_buf_add(m, "OPT (TRUNCATED)"); | ||
| 119 | return 1; | ||
| 120 | } | ||
| 121 | |||
| 122 | /* Max length: 127 "OPT (" 15*4*2chars ") " */ | ||
| 123 | nf_log_buf_add(m, "OPT ("); | ||
| 124 | for (i = 0; i < optsize; i++) | ||
| 125 | nf_log_buf_add(m, "%02X", op[i]); | ||
| 126 | |||
| 127 | nf_log_buf_add(m, ") "); | ||
| 128 | } | ||
| 129 | |||
| 130 | return 0; | ||
| 131 | } | ||
| 132 | EXPORT_SYMBOL_GPL(nf_log_dump_tcp_header); | ||
| 133 | |||
| 134 | void nf_log_dump_sk_uid_gid(struct nf_log_buf *m, struct sock *sk) | ||
| 135 | { | ||
| 136 | if (!sk || sk->sk_state == TCP_TIME_WAIT) | ||
| 137 | return; | ||
| 138 | |||
| 139 | read_lock_bh(&sk->sk_callback_lock); | ||
| 140 | if (sk->sk_socket && sk->sk_socket->file) { | ||
| 141 | const struct cred *cred = sk->sk_socket->file->f_cred; | ||
| 142 | nf_log_buf_add(m, "UID=%u GID=%u ", | ||
| 143 | from_kuid_munged(&init_user_ns, cred->fsuid), | ||
| 144 | from_kgid_munged(&init_user_ns, cred->fsgid)); | ||
| 145 | } | ||
| 146 | read_unlock_bh(&sk->sk_callback_lock); | ||
| 147 | } | ||
| 148 | EXPORT_SYMBOL_GPL(nf_log_dump_sk_uid_gid); | ||
| 149 | |||
| 150 | void | ||
| 151 | nf_log_dump_packet_common(struct nf_log_buf *m, u_int8_t pf, | ||
| 152 | unsigned int hooknum, const struct sk_buff *skb, | ||
| 153 | const struct net_device *in, | ||
| 154 | const struct net_device *out, | ||
| 155 | const struct nf_loginfo *loginfo, const char *prefix) | ||
| 156 | { | ||
| 157 | nf_log_buf_add(m, KERN_SOH "%c%sIN=%s OUT=%s ", | ||
| 158 | '0' + loginfo->u.log.level, prefix, | ||
| 159 | in ? in->name : "", | ||
| 160 | out ? out->name : ""); | ||
| 161 | #ifdef CONFIG_BRIDGE_NETFILTER | ||
| 162 | if (skb->nf_bridge) { | ||
| 163 | const struct net_device *physindev; | ||
| 164 | const struct net_device *physoutdev; | ||
| 165 | |||
| 166 | physindev = skb->nf_bridge->physindev; | ||
| 167 | if (physindev && in != physindev) | ||
| 168 | nf_log_buf_add(m, "PHYSIN=%s ", physindev->name); | ||
| 169 | physoutdev = skb->nf_bridge->physoutdev; | ||
| 170 | if (physoutdev && out != physoutdev) | ||
| 171 | nf_log_buf_add(m, "PHYSOUT=%s ", physoutdev->name); | ||
| 172 | } | ||
| 173 | #endif | ||
| 174 | } | ||
| 175 | EXPORT_SYMBOL_GPL(nf_log_dump_packet_common); | ||
| 176 | |||
| 177 | static int __init nf_log_common_init(void) | ||
| 178 | { | ||
| 179 | return 0; | ||
| 180 | } | ||
| 181 | |||
| 182 | static void __exit nf_log_common_exit(void) {} | ||
| 183 | |||
| 184 | module_init(nf_log_common_init); | ||
| 185 | module_exit(nf_log_common_exit); | ||
| 186 | |||
| 187 | MODULE_LICENSE("GPL"); | ||
diff --git a/net/netfilter/nf_nat_core.c b/net/netfilter/nf_nat_core.c index a49907b1dabc..552f97cd9fde 100644 --- a/net/netfilter/nf_nat_core.c +++ b/net/netfilter/nf_nat_core.c | |||
| @@ -710,7 +710,7 @@ static struct nf_ct_ext_type nat_extend __read_mostly = { | |||
| 710 | .flags = NF_CT_EXT_F_PREALLOC, | 710 | .flags = NF_CT_EXT_F_PREALLOC, |
| 711 | }; | 711 | }; |
| 712 | 712 | ||
| 713 | #if defined(CONFIG_NF_CT_NETLINK) || defined(CONFIG_NF_CT_NETLINK_MODULE) | 713 | #if IS_ENABLED(CONFIG_NF_CT_NETLINK) |
| 714 | 714 | ||
| 715 | #include <linux/netfilter/nfnetlink.h> | 715 | #include <linux/netfilter/nfnetlink.h> |
| 716 | #include <linux/netfilter/nfnetlink_conntrack.h> | 716 | #include <linux/netfilter/nfnetlink_conntrack.h> |
diff --git a/net/netfilter/nf_nat_proto_common.c b/net/netfilter/nf_nat_proto_common.c index 83a72a235cae..fbce552a796e 100644 --- a/net/netfilter/nf_nat_proto_common.c +++ b/net/netfilter/nf_nat_proto_common.c | |||
| @@ -95,7 +95,7 @@ void nf_nat_l4proto_unique_tuple(const struct nf_nat_l3proto *l3proto, | |||
| 95 | } | 95 | } |
| 96 | EXPORT_SYMBOL_GPL(nf_nat_l4proto_unique_tuple); | 96 | EXPORT_SYMBOL_GPL(nf_nat_l4proto_unique_tuple); |
| 97 | 97 | ||
| 98 | #if defined(CONFIG_NF_CT_NETLINK) || defined(CONFIG_NF_CT_NETLINK_MODULE) | 98 | #if IS_ENABLED(CONFIG_NF_CT_NETLINK) |
| 99 | int nf_nat_l4proto_nlattr_to_range(struct nlattr *tb[], | 99 | int nf_nat_l4proto_nlattr_to_range(struct nlattr *tb[], |
| 100 | struct nf_nat_range *range) | 100 | struct nf_nat_range *range) |
| 101 | { | 101 | { |
diff --git a/net/netfilter/nf_nat_proto_dccp.c b/net/netfilter/nf_nat_proto_dccp.c index c8be2cdac0bf..b8067b53ff3a 100644 --- a/net/netfilter/nf_nat_proto_dccp.c +++ b/net/netfilter/nf_nat_proto_dccp.c | |||
| @@ -78,7 +78,7 @@ static const struct nf_nat_l4proto nf_nat_l4proto_dccp = { | |||
| 78 | .manip_pkt = dccp_manip_pkt, | 78 | .manip_pkt = dccp_manip_pkt, |
| 79 | .in_range = nf_nat_l4proto_in_range, | 79 | .in_range = nf_nat_l4proto_in_range, |
| 80 | .unique_tuple = dccp_unique_tuple, | 80 | .unique_tuple = dccp_unique_tuple, |
| 81 | #if defined(CONFIG_NF_CT_NETLINK) || defined(CONFIG_NF_CT_NETLINK_MODULE) | 81 | #if IS_ENABLED(CONFIG_NF_CT_NETLINK) |
| 82 | .nlattr_to_range = nf_nat_l4proto_nlattr_to_range, | 82 | .nlattr_to_range = nf_nat_l4proto_nlattr_to_range, |
| 83 | #endif | 83 | #endif |
| 84 | }; | 84 | }; |
diff --git a/net/netfilter/nf_nat_proto_sctp.c b/net/netfilter/nf_nat_proto_sctp.c index 754536f2c674..cbc7ade1487b 100644 --- a/net/netfilter/nf_nat_proto_sctp.c +++ b/net/netfilter/nf_nat_proto_sctp.c | |||
| @@ -59,7 +59,7 @@ static const struct nf_nat_l4proto nf_nat_l4proto_sctp = { | |||
| 59 | .manip_pkt = sctp_manip_pkt, | 59 | .manip_pkt = sctp_manip_pkt, |
| 60 | .in_range = nf_nat_l4proto_in_range, | 60 | .in_range = nf_nat_l4proto_in_range, |
| 61 | .unique_tuple = sctp_unique_tuple, | 61 | .unique_tuple = sctp_unique_tuple, |
| 62 | #if defined(CONFIG_NF_CT_NETLINK) || defined(CONFIG_NF_CT_NETLINK_MODULE) | 62 | #if IS_ENABLED(CONFIG_NF_CT_NETLINK) |
| 63 | .nlattr_to_range = nf_nat_l4proto_nlattr_to_range, | 63 | .nlattr_to_range = nf_nat_l4proto_nlattr_to_range, |
| 64 | #endif | 64 | #endif |
| 65 | }; | 65 | }; |
diff --git a/net/netfilter/nf_nat_proto_tcp.c b/net/netfilter/nf_nat_proto_tcp.c index 83ec8a6e4c36..37f5505f4529 100644 --- a/net/netfilter/nf_nat_proto_tcp.c +++ b/net/netfilter/nf_nat_proto_tcp.c | |||
| @@ -79,7 +79,7 @@ const struct nf_nat_l4proto nf_nat_l4proto_tcp = { | |||
| 79 | .manip_pkt = tcp_manip_pkt, | 79 | .manip_pkt = tcp_manip_pkt, |
| 80 | .in_range = nf_nat_l4proto_in_range, | 80 | .in_range = nf_nat_l4proto_in_range, |
| 81 | .unique_tuple = tcp_unique_tuple, | 81 | .unique_tuple = tcp_unique_tuple, |
| 82 | #if defined(CONFIG_NF_CT_NETLINK) || defined(CONFIG_NF_CT_NETLINK_MODULE) | 82 | #if IS_ENABLED(CONFIG_NF_CT_NETLINK) |
| 83 | .nlattr_to_range = nf_nat_l4proto_nlattr_to_range, | 83 | .nlattr_to_range = nf_nat_l4proto_nlattr_to_range, |
| 84 | #endif | 84 | #endif |
| 85 | }; | 85 | }; |
diff --git a/net/netfilter/nf_nat_proto_udp.c b/net/netfilter/nf_nat_proto_udp.c index 7df613fb34a2..b0ede2f0d8bc 100644 --- a/net/netfilter/nf_nat_proto_udp.c +++ b/net/netfilter/nf_nat_proto_udp.c | |||
| @@ -70,7 +70,7 @@ const struct nf_nat_l4proto nf_nat_l4proto_udp = { | |||
| 70 | .manip_pkt = udp_manip_pkt, | 70 | .manip_pkt = udp_manip_pkt, |
| 71 | .in_range = nf_nat_l4proto_in_range, | 71 | .in_range = nf_nat_l4proto_in_range, |
| 72 | .unique_tuple = udp_unique_tuple, | 72 | .unique_tuple = udp_unique_tuple, |
| 73 | #if defined(CONFIG_NF_CT_NETLINK) || defined(CONFIG_NF_CT_NETLINK_MODULE) | 73 | #if IS_ENABLED(CONFIG_NF_CT_NETLINK) |
| 74 | .nlattr_to_range = nf_nat_l4proto_nlattr_to_range, | 74 | .nlattr_to_range = nf_nat_l4proto_nlattr_to_range, |
| 75 | #endif | 75 | #endif |
| 76 | }; | 76 | }; |
diff --git a/net/netfilter/nf_nat_proto_udplite.c b/net/netfilter/nf_nat_proto_udplite.c index 776a0d1317b1..368f14e01e75 100644 --- a/net/netfilter/nf_nat_proto_udplite.c +++ b/net/netfilter/nf_nat_proto_udplite.c | |||
| @@ -69,7 +69,7 @@ static const struct nf_nat_l4proto nf_nat_l4proto_udplite = { | |||
| 69 | .manip_pkt = udplite_manip_pkt, | 69 | .manip_pkt = udplite_manip_pkt, |
| 70 | .in_range = nf_nat_l4proto_in_range, | 70 | .in_range = nf_nat_l4proto_in_range, |
| 71 | .unique_tuple = udplite_unique_tuple, | 71 | .unique_tuple = udplite_unique_tuple, |
| 72 | #if defined(CONFIG_NF_CT_NETLINK) || defined(CONFIG_NF_CT_NETLINK_MODULE) | 72 | #if IS_ENABLED(CONFIG_NF_CT_NETLINK) |
| 73 | .nlattr_to_range = nf_nat_l4proto_nlattr_to_range, | 73 | .nlattr_to_range = nf_nat_l4proto_nlattr_to_range, |
| 74 | #endif | 74 | #endif |
| 75 | }; | 75 | }; |
diff --git a/net/netfilter/nf_sockopt.c b/net/netfilter/nf_sockopt.c index f042ae521557..c68c1e58b362 100644 --- a/net/netfilter/nf_sockopt.c +++ b/net/netfilter/nf_sockopt.c | |||
| @@ -26,9 +26,7 @@ int nf_register_sockopt(struct nf_sockopt_ops *reg) | |||
| 26 | struct nf_sockopt_ops *ops; | 26 | struct nf_sockopt_ops *ops; |
| 27 | int ret = 0; | 27 | int ret = 0; |
| 28 | 28 | ||
| 29 | if (mutex_lock_interruptible(&nf_sockopt_mutex) != 0) | 29 | mutex_lock(&nf_sockopt_mutex); |
| 30 | return -EINTR; | ||
| 31 | |||
| 32 | list_for_each_entry(ops, &nf_sockopts, list) { | 30 | list_for_each_entry(ops, &nf_sockopts, list) { |
| 33 | if (ops->pf == reg->pf | 31 | if (ops->pf == reg->pf |
| 34 | && (overlap(ops->set_optmin, ops->set_optmax, | 32 | && (overlap(ops->set_optmin, ops->set_optmax, |
| @@ -65,9 +63,7 @@ static struct nf_sockopt_ops *nf_sockopt_find(struct sock *sk, u_int8_t pf, | |||
| 65 | { | 63 | { |
| 66 | struct nf_sockopt_ops *ops; | 64 | struct nf_sockopt_ops *ops; |
| 67 | 65 | ||
| 68 | if (mutex_lock_interruptible(&nf_sockopt_mutex) != 0) | 66 | mutex_lock(&nf_sockopt_mutex); |
| 69 | return ERR_PTR(-EINTR); | ||
| 70 | |||
| 71 | list_for_each_entry(ops, &nf_sockopts, list) { | 67 | list_for_each_entry(ops, &nf_sockopts, list) { |
| 72 | if (ops->pf == pf) { | 68 | if (ops->pf == pf) { |
| 73 | if (!try_module_get(ops->owner)) | 69 | if (!try_module_get(ops->owner)) |
diff --git a/net/netfilter/nf_tables_api.c b/net/netfilter/nf_tables_api.c index 8746ff9a8357..deeb95fb7028 100644 --- a/net/netfilter/nf_tables_api.c +++ b/net/netfilter/nf_tables_api.c | |||
| @@ -899,6 +899,9 @@ static struct nft_stats __percpu *nft_stats_alloc(const struct nlattr *attr) | |||
| 899 | static void nft_chain_stats_replace(struct nft_base_chain *chain, | 899 | static void nft_chain_stats_replace(struct nft_base_chain *chain, |
| 900 | struct nft_stats __percpu *newstats) | 900 | struct nft_stats __percpu *newstats) |
| 901 | { | 901 | { |
| 902 | if (newstats == NULL) | ||
| 903 | return; | ||
| 904 | |||
| 902 | if (chain->stats) { | 905 | if (chain->stats) { |
| 903 | struct nft_stats __percpu *oldstats = | 906 | struct nft_stats __percpu *oldstats = |
| 904 | nft_dereference(chain->stats); | 907 | nft_dereference(chain->stats); |
| @@ -2247,80 +2250,7 @@ err: | |||
| 2247 | return err; | 2250 | return err; |
| 2248 | } | 2251 | } |
| 2249 | 2252 | ||
| 2250 | static int nf_tables_dump_sets_table(struct nft_ctx *ctx, struct sk_buff *skb, | 2253 | static int nf_tables_dump_sets(struct sk_buff *skb, struct netlink_callback *cb) |
| 2251 | struct netlink_callback *cb) | ||
| 2252 | { | ||
| 2253 | const struct nft_set *set; | ||
| 2254 | unsigned int idx = 0, s_idx = cb->args[0]; | ||
| 2255 | |||
| 2256 | if (cb->args[1]) | ||
| 2257 | return skb->len; | ||
| 2258 | |||
| 2259 | rcu_read_lock(); | ||
| 2260 | cb->seq = ctx->net->nft.base_seq; | ||
| 2261 | |||
| 2262 | list_for_each_entry_rcu(set, &ctx->table->sets, list) { | ||
| 2263 | if (idx < s_idx) | ||
| 2264 | goto cont; | ||
| 2265 | if (nf_tables_fill_set(skb, ctx, set, NFT_MSG_NEWSET, | ||
| 2266 | NLM_F_MULTI) < 0) { | ||
| 2267 | cb->args[0] = idx; | ||
| 2268 | goto done; | ||
| 2269 | } | ||
| 2270 | nl_dump_check_consistent(cb, nlmsg_hdr(skb)); | ||
| 2271 | cont: | ||
| 2272 | idx++; | ||
| 2273 | } | ||
| 2274 | cb->args[1] = 1; | ||
| 2275 | done: | ||
| 2276 | rcu_read_unlock(); | ||
| 2277 | return skb->len; | ||
| 2278 | } | ||
| 2279 | |||
| 2280 | static int nf_tables_dump_sets_family(struct nft_ctx *ctx, struct sk_buff *skb, | ||
| 2281 | struct netlink_callback *cb) | ||
| 2282 | { | ||
| 2283 | const struct nft_set *set; | ||
| 2284 | unsigned int idx, s_idx = cb->args[0]; | ||
| 2285 | struct nft_table *table, *cur_table = (struct nft_table *)cb->args[2]; | ||
| 2286 | |||
| 2287 | if (cb->args[1]) | ||
| 2288 | return skb->len; | ||
| 2289 | |||
| 2290 | rcu_read_lock(); | ||
| 2291 | cb->seq = ctx->net->nft.base_seq; | ||
| 2292 | |||
| 2293 | list_for_each_entry_rcu(table, &ctx->afi->tables, list) { | ||
| 2294 | if (cur_table) { | ||
| 2295 | if (cur_table != table) | ||
| 2296 | continue; | ||
| 2297 | |||
| 2298 | cur_table = NULL; | ||
| 2299 | } | ||
| 2300 | ctx->table = table; | ||
| 2301 | idx = 0; | ||
| 2302 | list_for_each_entry_rcu(set, &ctx->table->sets, list) { | ||
| 2303 | if (idx < s_idx) | ||
| 2304 | goto cont; | ||
| 2305 | if (nf_tables_fill_set(skb, ctx, set, NFT_MSG_NEWSET, | ||
| 2306 | NLM_F_MULTI) < 0) { | ||
| 2307 | cb->args[0] = idx; | ||
| 2308 | cb->args[2] = (unsigned long) table; | ||
| 2309 | goto done; | ||
| 2310 | } | ||
| 2311 | nl_dump_check_consistent(cb, nlmsg_hdr(skb)); | ||
| 2312 | cont: | ||
| 2313 | idx++; | ||
| 2314 | } | ||
| 2315 | } | ||
| 2316 | cb->args[1] = 1; | ||
| 2317 | done: | ||
| 2318 | rcu_read_unlock(); | ||
| 2319 | return skb->len; | ||
| 2320 | } | ||
| 2321 | |||
| 2322 | static int nf_tables_dump_sets_all(struct nft_ctx *ctx, struct sk_buff *skb, | ||
| 2323 | struct netlink_callback *cb) | ||
| 2324 | { | 2254 | { |
| 2325 | const struct nft_set *set; | 2255 | const struct nft_set *set; |
| 2326 | unsigned int idx, s_idx = cb->args[0]; | 2256 | unsigned int idx, s_idx = cb->args[0]; |
| @@ -2328,6 +2258,7 @@ static int nf_tables_dump_sets_all(struct nft_ctx *ctx, struct sk_buff *skb, | |||
| 2328 | struct nft_table *table, *cur_table = (struct nft_table *)cb->args[2]; | 2258 | struct nft_table *table, *cur_table = (struct nft_table *)cb->args[2]; |
| 2329 | struct net *net = sock_net(skb->sk); | 2259 | struct net *net = sock_net(skb->sk); |
| 2330 | int cur_family = cb->args[3]; | 2260 | int cur_family = cb->args[3]; |
| 2261 | struct nft_ctx *ctx = cb->data, ctx_set; | ||
| 2331 | 2262 | ||
| 2332 | if (cb->args[1]) | 2263 | if (cb->args[1]) |
| 2333 | return skb->len; | 2264 | return skb->len; |
| @@ -2336,28 +2267,34 @@ static int nf_tables_dump_sets_all(struct nft_ctx *ctx, struct sk_buff *skb, | |||
| 2336 | cb->seq = net->nft.base_seq; | 2267 | cb->seq = net->nft.base_seq; |
| 2337 | 2268 | ||
| 2338 | list_for_each_entry_rcu(afi, &net->nft.af_info, list) { | 2269 | list_for_each_entry_rcu(afi, &net->nft.af_info, list) { |
| 2270 | if (ctx->afi && ctx->afi != afi) | ||
| 2271 | continue; | ||
| 2272 | |||
| 2339 | if (cur_family) { | 2273 | if (cur_family) { |
| 2340 | if (afi->family != cur_family) | 2274 | if (afi->family != cur_family) |
| 2341 | continue; | 2275 | continue; |
| 2342 | 2276 | ||
| 2343 | cur_family = 0; | 2277 | cur_family = 0; |
| 2344 | } | 2278 | } |
| 2345 | |||
| 2346 | list_for_each_entry_rcu(table, &afi->tables, list) { | 2279 | list_for_each_entry_rcu(table, &afi->tables, list) { |
| 2280 | if (ctx->table && ctx->table != table) | ||
| 2281 | continue; | ||
| 2282 | |||
| 2347 | if (cur_table) { | 2283 | if (cur_table) { |
| 2348 | if (cur_table != table) | 2284 | if (cur_table != table) |
| 2349 | continue; | 2285 | continue; |
| 2350 | 2286 | ||
| 2351 | cur_table = NULL; | 2287 | cur_table = NULL; |
| 2352 | } | 2288 | } |
| 2353 | |||
| 2354 | ctx->table = table; | ||
| 2355 | ctx->afi = afi; | ||
| 2356 | idx = 0; | 2289 | idx = 0; |
| 2357 | list_for_each_entry_rcu(set, &ctx->table->sets, list) { | 2290 | list_for_each_entry_rcu(set, &table->sets, list) { |
| 2358 | if (idx < s_idx) | 2291 | if (idx < s_idx) |
| 2359 | goto cont; | 2292 | goto cont; |
| 2360 | if (nf_tables_fill_set(skb, ctx, set, | 2293 | |
| 2294 | ctx_set = *ctx; | ||
| 2295 | ctx_set.table = table; | ||
| 2296 | ctx_set.afi = afi; | ||
| 2297 | if (nf_tables_fill_set(skb, &ctx_set, set, | ||
| 2361 | NFT_MSG_NEWSET, | 2298 | NFT_MSG_NEWSET, |
| 2362 | NLM_F_MULTI) < 0) { | 2299 | NLM_F_MULTI) < 0) { |
| 2363 | cb->args[0] = idx; | 2300 | cb->args[0] = idx; |
| @@ -2379,31 +2316,10 @@ done: | |||
| 2379 | return skb->len; | 2316 | return skb->len; |
| 2380 | } | 2317 | } |
| 2381 | 2318 | ||
| 2382 | static int nf_tables_dump_sets(struct sk_buff *skb, struct netlink_callback *cb) | 2319 | static int nf_tables_dump_sets_done(struct netlink_callback *cb) |
| 2383 | { | 2320 | { |
| 2384 | const struct nfgenmsg *nfmsg = nlmsg_data(cb->nlh); | 2321 | kfree(cb->data); |
| 2385 | struct nlattr *nla[NFTA_SET_MAX + 1]; | 2322 | return 0; |
| 2386 | struct nft_ctx ctx; | ||
| 2387 | int err, ret; | ||
| 2388 | |||
| 2389 | err = nlmsg_parse(cb->nlh, sizeof(*nfmsg), nla, NFTA_SET_MAX, | ||
| 2390 | nft_set_policy); | ||
| 2391 | if (err < 0) | ||
| 2392 | return err; | ||
| 2393 | |||
| 2394 | err = nft_ctx_init_from_setattr(&ctx, cb->skb, cb->nlh, (void *)nla); | ||
| 2395 | if (err < 0) | ||
| 2396 | return err; | ||
| 2397 | |||
| 2398 | if (ctx.table == NULL) { | ||
| 2399 | if (ctx.afi == NULL) | ||
| 2400 | ret = nf_tables_dump_sets_all(&ctx, skb, cb); | ||
| 2401 | else | ||
| 2402 | ret = nf_tables_dump_sets_family(&ctx, skb, cb); | ||
| 2403 | } else | ||
| 2404 | ret = nf_tables_dump_sets_table(&ctx, skb, cb); | ||
| 2405 | |||
| 2406 | return ret; | ||
| 2407 | } | 2323 | } |
| 2408 | 2324 | ||
| 2409 | #define NFT_SET_INACTIVE (1 << 15) /* Internal set flag */ | 2325 | #define NFT_SET_INACTIVE (1 << 15) /* Internal set flag */ |
| @@ -2426,7 +2342,17 @@ static int nf_tables_getset(struct sock *nlsk, struct sk_buff *skb, | |||
| 2426 | if (nlh->nlmsg_flags & NLM_F_DUMP) { | 2342 | if (nlh->nlmsg_flags & NLM_F_DUMP) { |
| 2427 | struct netlink_dump_control c = { | 2343 | struct netlink_dump_control c = { |
| 2428 | .dump = nf_tables_dump_sets, | 2344 | .dump = nf_tables_dump_sets, |
| 2345 | .done = nf_tables_dump_sets_done, | ||
| 2429 | }; | 2346 | }; |
| 2347 | struct nft_ctx *ctx_dump; | ||
| 2348 | |||
| 2349 | ctx_dump = kmalloc(sizeof(*ctx_dump), GFP_KERNEL); | ||
| 2350 | if (ctx_dump == NULL) | ||
| 2351 | return -ENOMEM; | ||
| 2352 | |||
| 2353 | *ctx_dump = ctx; | ||
| 2354 | c.data = ctx_dump; | ||
| 2355 | |||
| 2430 | return netlink_dump_start(nlsk, skb, nlh, &c); | 2356 | return netlink_dump_start(nlsk, skb, nlh, &c); |
| 2431 | } | 2357 | } |
| 2432 | 2358 | ||
| @@ -3150,6 +3076,9 @@ static int nf_tables_newsetelem(struct sock *nlsk, struct sk_buff *skb, | |||
| 3150 | struct nft_ctx ctx; | 3076 | struct nft_ctx ctx; |
| 3151 | int rem, err = 0; | 3077 | int rem, err = 0; |
| 3152 | 3078 | ||
| 3079 | if (nla[NFTA_SET_ELEM_LIST_ELEMENTS] == NULL) | ||
| 3080 | return -EINVAL; | ||
| 3081 | |||
| 3153 | err = nft_ctx_init_from_elemattr(&ctx, skb, nlh, nla, true); | 3082 | err = nft_ctx_init_from_elemattr(&ctx, skb, nlh, nla, true); |
| 3154 | if (err < 0) | 3083 | if (err < 0) |
| 3155 | return err; | 3084 | return err; |
| @@ -3208,16 +3137,14 @@ static int nft_del_setelem(struct nft_ctx *ctx, struct nft_set *set, | |||
| 3208 | goto err2; | 3137 | goto err2; |
| 3209 | 3138 | ||
| 3210 | trans = nft_trans_elem_alloc(ctx, NFT_MSG_DELSETELEM, set); | 3139 | trans = nft_trans_elem_alloc(ctx, NFT_MSG_DELSETELEM, set); |
| 3211 | if (trans == NULL) | 3140 | if (trans == NULL) { |
| 3141 | err = -ENOMEM; | ||
| 3212 | goto err2; | 3142 | goto err2; |
| 3143 | } | ||
| 3213 | 3144 | ||
| 3214 | nft_trans_elem(trans) = elem; | 3145 | nft_trans_elem(trans) = elem; |
| 3215 | list_add_tail(&trans->list, &ctx->net->nft.commit_list); | 3146 | list_add_tail(&trans->list, &ctx->net->nft.commit_list); |
| 3216 | 3147 | return 0; | |
| 3217 | nft_data_uninit(&elem.key, NFT_DATA_VALUE); | ||
| 3218 | if (set->flags & NFT_SET_MAP) | ||
| 3219 | nft_data_uninit(&elem.data, set->dtype); | ||
| 3220 | |||
| 3221 | err2: | 3148 | err2: |
| 3222 | nft_data_uninit(&elem.key, desc.type); | 3149 | nft_data_uninit(&elem.key, desc.type); |
| 3223 | err1: | 3150 | err1: |
| @@ -3233,6 +3160,9 @@ static int nf_tables_delsetelem(struct sock *nlsk, struct sk_buff *skb, | |||
| 3233 | struct nft_ctx ctx; | 3160 | struct nft_ctx ctx; |
| 3234 | int rem, err = 0; | 3161 | int rem, err = 0; |
| 3235 | 3162 | ||
| 3163 | if (nla[NFTA_SET_ELEM_LIST_ELEMENTS] == NULL) | ||
| 3164 | return -EINVAL; | ||
| 3165 | |||
| 3236 | err = nft_ctx_init_from_elemattr(&ctx, skb, nlh, nla, false); | 3166 | err = nft_ctx_init_from_elemattr(&ctx, skb, nlh, nla, false); |
| 3237 | if (err < 0) | 3167 | if (err < 0) |
| 3238 | return err; | 3168 | return err; |
| @@ -3380,7 +3310,7 @@ static int nf_tables_commit(struct sk_buff *skb) | |||
| 3380 | { | 3310 | { |
| 3381 | struct net *net = sock_net(skb->sk); | 3311 | struct net *net = sock_net(skb->sk); |
| 3382 | struct nft_trans *trans, *next; | 3312 | struct nft_trans *trans, *next; |
| 3383 | struct nft_set *set; | 3313 | struct nft_trans_elem *te; |
| 3384 | 3314 | ||
| 3385 | /* Bump generation counter, invalidate any dump in progress */ | 3315 | /* Bump generation counter, invalidate any dump in progress */ |
| 3386 | while (++net->nft.base_seq == 0); | 3316 | while (++net->nft.base_seq == 0); |
| @@ -3466,13 +3396,17 @@ static int nf_tables_commit(struct sk_buff *skb) | |||
| 3466 | nft_trans_destroy(trans); | 3396 | nft_trans_destroy(trans); |
| 3467 | break; | 3397 | break; |
| 3468 | case NFT_MSG_DELSETELEM: | 3398 | case NFT_MSG_DELSETELEM: |
| 3469 | nf_tables_setelem_notify(&trans->ctx, | 3399 | te = (struct nft_trans_elem *)trans->data; |
| 3470 | nft_trans_elem_set(trans), | 3400 | nf_tables_setelem_notify(&trans->ctx, te->set, |
| 3471 | &nft_trans_elem(trans), | 3401 | &te->elem, |
| 3472 | NFT_MSG_DELSETELEM, 0); | 3402 | NFT_MSG_DELSETELEM, 0); |
| 3473 | set = nft_trans_elem_set(trans); | 3403 | te->set->ops->get(te->set, &te->elem); |
| 3474 | set->ops->get(set, &nft_trans_elem(trans)); | 3404 | te->set->ops->remove(te->set, &te->elem); |
| 3475 | set->ops->remove(set, &nft_trans_elem(trans)); | 3405 | nft_data_uninit(&te->elem.key, NFT_DATA_VALUE); |
| 3406 | if (te->elem.flags & NFT_SET_MAP) { | ||
| 3407 | nft_data_uninit(&te->elem.data, | ||
| 3408 | te->set->dtype); | ||
| 3409 | } | ||
| 3476 | nft_trans_destroy(trans); | 3410 | nft_trans_destroy(trans); |
| 3477 | break; | 3411 | break; |
| 3478 | } | 3412 | } |
diff --git a/net/netfilter/nfnetlink_acct.c b/net/netfilter/nfnetlink_acct.c index 2baa125c2e8d..3ea0eacbd970 100644 --- a/net/netfilter/nfnetlink_acct.c +++ b/net/netfilter/nfnetlink_acct.c | |||
| @@ -41,6 +41,7 @@ struct nf_acct { | |||
| 41 | }; | 41 | }; |
| 42 | 42 | ||
| 43 | #define NFACCT_F_QUOTA (NFACCT_F_QUOTA_PKTS | NFACCT_F_QUOTA_BYTES) | 43 | #define NFACCT_F_QUOTA (NFACCT_F_QUOTA_PKTS | NFACCT_F_QUOTA_BYTES) |
| 44 | #define NFACCT_OVERQUOTA_BIT 2 /* NFACCT_F_OVERQUOTA */ | ||
| 44 | 45 | ||
| 45 | static int | 46 | static int |
| 46 | nfnl_acct_new(struct sock *nfnl, struct sk_buff *skb, | 47 | nfnl_acct_new(struct sock *nfnl, struct sk_buff *skb, |
| @@ -77,7 +78,8 @@ nfnl_acct_new(struct sock *nfnl, struct sk_buff *skb, | |||
| 77 | smp_mb__before_atomic(); | 78 | smp_mb__before_atomic(); |
| 78 | /* reset overquota flag if quota is enabled. */ | 79 | /* reset overquota flag if quota is enabled. */ |
| 79 | if ((matching->flags & NFACCT_F_QUOTA)) | 80 | if ((matching->flags & NFACCT_F_QUOTA)) |
| 80 | clear_bit(NFACCT_F_OVERQUOTA, &matching->flags); | 81 | clear_bit(NFACCT_OVERQUOTA_BIT, |
| 82 | &matching->flags); | ||
| 81 | return 0; | 83 | return 0; |
| 82 | } | 84 | } |
| 83 | return -EBUSY; | 85 | return -EBUSY; |
| @@ -129,6 +131,7 @@ nfnl_acct_fill_info(struct sk_buff *skb, u32 portid, u32 seq, u32 type, | |||
| 129 | struct nfgenmsg *nfmsg; | 131 | struct nfgenmsg *nfmsg; |
| 130 | unsigned int flags = portid ? NLM_F_MULTI : 0; | 132 | unsigned int flags = portid ? NLM_F_MULTI : 0; |
| 131 | u64 pkts, bytes; | 133 | u64 pkts, bytes; |
| 134 | u32 old_flags; | ||
| 132 | 135 | ||
| 133 | event |= NFNL_SUBSYS_ACCT << 8; | 136 | event |= NFNL_SUBSYS_ACCT << 8; |
| 134 | nlh = nlmsg_put(skb, portid, seq, event, sizeof(*nfmsg), flags); | 137 | nlh = nlmsg_put(skb, portid, seq, event, sizeof(*nfmsg), flags); |
| @@ -143,12 +146,13 @@ nfnl_acct_fill_info(struct sk_buff *skb, u32 portid, u32 seq, u32 type, | |||
| 143 | if (nla_put_string(skb, NFACCT_NAME, acct->name)) | 146 | if (nla_put_string(skb, NFACCT_NAME, acct->name)) |
| 144 | goto nla_put_failure; | 147 | goto nla_put_failure; |
| 145 | 148 | ||
| 149 | old_flags = acct->flags; | ||
| 146 | if (type == NFNL_MSG_ACCT_GET_CTRZERO) { | 150 | if (type == NFNL_MSG_ACCT_GET_CTRZERO) { |
| 147 | pkts = atomic64_xchg(&acct->pkts, 0); | 151 | pkts = atomic64_xchg(&acct->pkts, 0); |
| 148 | bytes = atomic64_xchg(&acct->bytes, 0); | 152 | bytes = atomic64_xchg(&acct->bytes, 0); |
| 149 | smp_mb__before_atomic(); | 153 | smp_mb__before_atomic(); |
| 150 | if (acct->flags & NFACCT_F_QUOTA) | 154 | if (acct->flags & NFACCT_F_QUOTA) |
| 151 | clear_bit(NFACCT_F_OVERQUOTA, &acct->flags); | 155 | clear_bit(NFACCT_OVERQUOTA_BIT, &acct->flags); |
| 152 | } else { | 156 | } else { |
| 153 | pkts = atomic64_read(&acct->pkts); | 157 | pkts = atomic64_read(&acct->pkts); |
| 154 | bytes = atomic64_read(&acct->bytes); | 158 | bytes = atomic64_read(&acct->bytes); |
| @@ -160,7 +164,7 @@ nfnl_acct_fill_info(struct sk_buff *skb, u32 portid, u32 seq, u32 type, | |||
| 160 | if (acct->flags & NFACCT_F_QUOTA) { | 164 | if (acct->flags & NFACCT_F_QUOTA) { |
| 161 | u64 *quota = (u64 *)acct->data; | 165 | u64 *quota = (u64 *)acct->data; |
| 162 | 166 | ||
| 163 | if (nla_put_be32(skb, NFACCT_FLAGS, htonl(acct->flags)) || | 167 | if (nla_put_be32(skb, NFACCT_FLAGS, htonl(old_flags)) || |
| 164 | nla_put_be64(skb, NFACCT_QUOTA, cpu_to_be64(*quota))) | 168 | nla_put_be64(skb, NFACCT_QUOTA, cpu_to_be64(*quota))) |
| 165 | goto nla_put_failure; | 169 | goto nla_put_failure; |
| 166 | } | 170 | } |
| @@ -412,7 +416,7 @@ int nfnl_acct_overquota(const struct sk_buff *skb, struct nf_acct *nfacct) | |||
| 412 | ret = now > *quota; | 416 | ret = now > *quota; |
| 413 | 417 | ||
| 414 | if (now >= *quota && | 418 | if (now >= *quota && |
| 415 | !test_and_set_bit(NFACCT_F_OVERQUOTA, &nfacct->flags)) { | 419 | !test_and_set_bit(NFACCT_OVERQUOTA_BIT, &nfacct->flags)) { |
| 416 | nfnl_overquota_report(nfacct); | 420 | nfnl_overquota_report(nfacct); |
| 417 | } | 421 | } |
| 418 | 422 | ||
diff --git a/net/netfilter/nfnetlink_log.c b/net/netfilter/nfnetlink_log.c index d292c8d286eb..a11c5ff2f720 100644 --- a/net/netfilter/nfnetlink_log.c +++ b/net/netfilter/nfnetlink_log.c | |||
| @@ -773,6 +773,7 @@ nfulnl_recv_unsupp(struct sock *ctnl, struct sk_buff *skb, | |||
| 773 | 773 | ||
| 774 | static struct nf_logger nfulnl_logger __read_mostly = { | 774 | static struct nf_logger nfulnl_logger __read_mostly = { |
| 775 | .name = "nfnetlink_log", | 775 | .name = "nfnetlink_log", |
| 776 | .type = NF_LOG_TYPE_ULOG, | ||
| 776 | .logfn = &nfulnl_log_packet, | 777 | .logfn = &nfulnl_log_packet, |
| 777 | .me = THIS_MODULE, | 778 | .me = THIS_MODULE, |
| 778 | }; | 779 | }; |
| @@ -1105,6 +1106,9 @@ MODULE_DESCRIPTION("netfilter userspace logging"); | |||
| 1105 | MODULE_AUTHOR("Harald Welte <laforge@netfilter.org>"); | 1106 | MODULE_AUTHOR("Harald Welte <laforge@netfilter.org>"); |
| 1106 | MODULE_LICENSE("GPL"); | 1107 | MODULE_LICENSE("GPL"); |
| 1107 | MODULE_ALIAS_NFNL_SUBSYS(NFNL_SUBSYS_ULOG); | 1108 | MODULE_ALIAS_NFNL_SUBSYS(NFNL_SUBSYS_ULOG); |
| 1109 | MODULE_ALIAS_NF_LOGGER(AF_INET, 1); | ||
| 1110 | MODULE_ALIAS_NF_LOGGER(AF_INET6, 1); | ||
| 1111 | MODULE_ALIAS_NF_LOGGER(AF_BRIDGE, 1); | ||
| 1108 | 1112 | ||
| 1109 | module_init(nfnetlink_log_init); | 1113 | module_init(nfnetlink_log_init); |
| 1110 | module_exit(nfnetlink_log_fini); | 1114 | module_exit(nfnetlink_log_fini); |
diff --git a/net/netfilter/nft_hash.c b/net/netfilter/nft_hash.c index 4080ed6a072b..28fb8f38e6ba 100644 --- a/net/netfilter/nft_hash.c +++ b/net/netfilter/nft_hash.c | |||
| @@ -15,209 +15,40 @@ | |||
| 15 | #include <linux/log2.h> | 15 | #include <linux/log2.h> |
| 16 | #include <linux/jhash.h> | 16 | #include <linux/jhash.h> |
| 17 | #include <linux/netlink.h> | 17 | #include <linux/netlink.h> |
| 18 | #include <linux/vmalloc.h> | 18 | #include <linux/rhashtable.h> |
| 19 | #include <linux/netfilter.h> | 19 | #include <linux/netfilter.h> |
| 20 | #include <linux/netfilter/nf_tables.h> | 20 | #include <linux/netfilter/nf_tables.h> |
| 21 | #include <net/netfilter/nf_tables.h> | 21 | #include <net/netfilter/nf_tables.h> |
| 22 | 22 | ||
| 23 | #define NFT_HASH_MIN_SIZE 4UL | 23 | /* We target a hash table size of 4, element hint is 75% of final size */ |
| 24 | 24 | #define NFT_HASH_ELEMENT_HINT 3 | |
| 25 | struct nft_hash { | ||
| 26 | struct nft_hash_table __rcu *tbl; | ||
| 27 | }; | ||
| 28 | |||
| 29 | struct nft_hash_table { | ||
| 30 | unsigned int size; | ||
| 31 | struct nft_hash_elem __rcu *buckets[]; | ||
| 32 | }; | ||
| 33 | 25 | ||
| 34 | struct nft_hash_elem { | 26 | struct nft_hash_elem { |
| 35 | struct nft_hash_elem __rcu *next; | 27 | struct rhash_head node; |
| 36 | struct nft_data key; | 28 | struct nft_data key; |
| 37 | struct nft_data data[]; | 29 | struct nft_data data[]; |
| 38 | }; | 30 | }; |
| 39 | 31 | ||
| 40 | #define nft_hash_for_each_entry(i, head) \ | ||
| 41 | for (i = nft_dereference(head); i != NULL; i = nft_dereference(i->next)) | ||
| 42 | #define nft_hash_for_each_entry_rcu(i, head) \ | ||
| 43 | for (i = rcu_dereference(head); i != NULL; i = rcu_dereference(i->next)) | ||
| 44 | |||
| 45 | static u32 nft_hash_rnd __read_mostly; | ||
| 46 | static bool nft_hash_rnd_initted __read_mostly; | ||
| 47 | |||
| 48 | static unsigned int nft_hash_data(const struct nft_data *data, | ||
| 49 | unsigned int hsize, unsigned int len) | ||
| 50 | { | ||
| 51 | unsigned int h; | ||
| 52 | |||
| 53 | h = jhash(data->data, len, nft_hash_rnd); | ||
| 54 | return h & (hsize - 1); | ||
| 55 | } | ||
| 56 | |||
| 57 | static bool nft_hash_lookup(const struct nft_set *set, | 32 | static bool nft_hash_lookup(const struct nft_set *set, |
| 58 | const struct nft_data *key, | 33 | const struct nft_data *key, |
| 59 | struct nft_data *data) | 34 | struct nft_data *data) |
| 60 | { | 35 | { |
| 61 | const struct nft_hash *priv = nft_set_priv(set); | 36 | const struct rhashtable *priv = nft_set_priv(set); |
| 62 | const struct nft_hash_table *tbl = rcu_dereference(priv->tbl); | ||
| 63 | const struct nft_hash_elem *he; | 37 | const struct nft_hash_elem *he; |
| 64 | unsigned int h; | ||
| 65 | |||
| 66 | h = nft_hash_data(key, tbl->size, set->klen); | ||
| 67 | nft_hash_for_each_entry_rcu(he, tbl->buckets[h]) { | ||
| 68 | if (nft_data_cmp(&he->key, key, set->klen)) | ||
| 69 | continue; | ||
| 70 | if (set->flags & NFT_SET_MAP) | ||
| 71 | nft_data_copy(data, he->data); | ||
| 72 | return true; | ||
| 73 | } | ||
| 74 | return false; | ||
| 75 | } | ||
| 76 | |||
| 77 | static void nft_hash_tbl_free(const struct nft_hash_table *tbl) | ||
| 78 | { | ||
| 79 | kvfree(tbl); | ||
| 80 | } | ||
| 81 | |||
| 82 | static unsigned int nft_hash_tbl_size(unsigned int nelem) | ||
| 83 | { | ||
| 84 | return max(roundup_pow_of_two(nelem * 4 / 3), NFT_HASH_MIN_SIZE); | ||
| 85 | } | ||
| 86 | |||
| 87 | static struct nft_hash_table *nft_hash_tbl_alloc(unsigned int nbuckets) | ||
| 88 | { | ||
| 89 | struct nft_hash_table *tbl; | ||
| 90 | size_t size; | ||
| 91 | |||
| 92 | size = sizeof(*tbl) + nbuckets * sizeof(tbl->buckets[0]); | ||
| 93 | tbl = kzalloc(size, GFP_KERNEL | __GFP_REPEAT | __GFP_NOWARN); | ||
| 94 | if (tbl == NULL) | ||
| 95 | tbl = vzalloc(size); | ||
| 96 | if (tbl == NULL) | ||
| 97 | return NULL; | ||
| 98 | tbl->size = nbuckets; | ||
| 99 | |||
| 100 | return tbl; | ||
| 101 | } | ||
| 102 | |||
| 103 | static void nft_hash_chain_unzip(const struct nft_set *set, | ||
| 104 | const struct nft_hash_table *ntbl, | ||
| 105 | struct nft_hash_table *tbl, unsigned int n) | ||
| 106 | { | ||
| 107 | struct nft_hash_elem *he, *last, *next; | ||
| 108 | unsigned int h; | ||
| 109 | |||
| 110 | he = nft_dereference(tbl->buckets[n]); | ||
| 111 | if (he == NULL) | ||
| 112 | return; | ||
| 113 | h = nft_hash_data(&he->key, ntbl->size, set->klen); | ||
| 114 | |||
| 115 | /* Find last element of first chain hashing to bucket h */ | ||
| 116 | last = he; | ||
| 117 | nft_hash_for_each_entry(he, he->next) { | ||
| 118 | if (nft_hash_data(&he->key, ntbl->size, set->klen) != h) | ||
| 119 | break; | ||
| 120 | last = he; | ||
| 121 | } | ||
| 122 | |||
| 123 | /* Unlink first chain from the old table */ | ||
| 124 | RCU_INIT_POINTER(tbl->buckets[n], last->next); | ||
| 125 | 38 | ||
| 126 | /* If end of chain reached, done */ | 39 | he = rhashtable_lookup(priv, key); |
| 127 | if (he == NULL) | 40 | if (he && set->flags & NFT_SET_MAP) |
| 128 | return; | 41 | nft_data_copy(data, he->data); |
| 129 | 42 | ||
| 130 | /* Find first element of second chain hashing to bucket h */ | 43 | return !!he; |
| 131 | next = NULL; | ||
| 132 | nft_hash_for_each_entry(he, he->next) { | ||
| 133 | if (nft_hash_data(&he->key, ntbl->size, set->klen) != h) | ||
| 134 | continue; | ||
| 135 | next = he; | ||
| 136 | break; | ||
| 137 | } | ||
| 138 | |||
| 139 | /* Link the two chains */ | ||
| 140 | RCU_INIT_POINTER(last->next, next); | ||
| 141 | } | ||
| 142 | |||
| 143 | static int nft_hash_tbl_expand(const struct nft_set *set, struct nft_hash *priv) | ||
| 144 | { | ||
| 145 | struct nft_hash_table *tbl = nft_dereference(priv->tbl), *ntbl; | ||
| 146 | struct nft_hash_elem *he; | ||
| 147 | unsigned int i, h; | ||
| 148 | bool complete; | ||
| 149 | |||
| 150 | ntbl = nft_hash_tbl_alloc(tbl->size * 2); | ||
| 151 | if (ntbl == NULL) | ||
| 152 | return -ENOMEM; | ||
| 153 | |||
| 154 | /* Link new table's buckets to first element in the old table | ||
| 155 | * hashing to the new bucket. | ||
| 156 | */ | ||
| 157 | for (i = 0; i < ntbl->size; i++) { | ||
| 158 | h = i < tbl->size ? i : i - tbl->size; | ||
| 159 | nft_hash_for_each_entry(he, tbl->buckets[h]) { | ||
| 160 | if (nft_hash_data(&he->key, ntbl->size, set->klen) != i) | ||
| 161 | continue; | ||
| 162 | RCU_INIT_POINTER(ntbl->buckets[i], he); | ||
| 163 | break; | ||
| 164 | } | ||
| 165 | } | ||
| 166 | |||
| 167 | /* Publish new table */ | ||
| 168 | rcu_assign_pointer(priv->tbl, ntbl); | ||
| 169 | |||
| 170 | /* Unzip interleaved hash chains */ | ||
| 171 | do { | ||
| 172 | /* Wait for readers to use new table/unzipped chains */ | ||
| 173 | synchronize_rcu(); | ||
| 174 | |||
| 175 | complete = true; | ||
| 176 | for (i = 0; i < tbl->size; i++) { | ||
| 177 | nft_hash_chain_unzip(set, ntbl, tbl, i); | ||
| 178 | if (tbl->buckets[i] != NULL) | ||
| 179 | complete = false; | ||
| 180 | } | ||
| 181 | } while (!complete); | ||
| 182 | |||
| 183 | nft_hash_tbl_free(tbl); | ||
| 184 | return 0; | ||
| 185 | } | ||
| 186 | |||
| 187 | static int nft_hash_tbl_shrink(const struct nft_set *set, struct nft_hash *priv) | ||
| 188 | { | ||
| 189 | struct nft_hash_table *tbl = nft_dereference(priv->tbl), *ntbl; | ||
| 190 | struct nft_hash_elem __rcu **pprev; | ||
| 191 | unsigned int i; | ||
| 192 | |||
| 193 | ntbl = nft_hash_tbl_alloc(tbl->size / 2); | ||
| 194 | if (ntbl == NULL) | ||
| 195 | return -ENOMEM; | ||
| 196 | |||
| 197 | for (i = 0; i < ntbl->size; i++) { | ||
| 198 | ntbl->buckets[i] = tbl->buckets[i]; | ||
| 199 | |||
| 200 | for (pprev = &ntbl->buckets[i]; *pprev != NULL; | ||
| 201 | pprev = &nft_dereference(*pprev)->next) | ||
| 202 | ; | ||
| 203 | RCU_INIT_POINTER(*pprev, tbl->buckets[i + ntbl->size]); | ||
| 204 | } | ||
| 205 | |||
| 206 | /* Publish new table */ | ||
| 207 | rcu_assign_pointer(priv->tbl, ntbl); | ||
| 208 | synchronize_rcu(); | ||
| 209 | |||
| 210 | nft_hash_tbl_free(tbl); | ||
| 211 | return 0; | ||
| 212 | } | 44 | } |
| 213 | 45 | ||
| 214 | static int nft_hash_insert(const struct nft_set *set, | 46 | static int nft_hash_insert(const struct nft_set *set, |
| 215 | const struct nft_set_elem *elem) | 47 | const struct nft_set_elem *elem) |
| 216 | { | 48 | { |
| 217 | struct nft_hash *priv = nft_set_priv(set); | 49 | struct rhashtable *priv = nft_set_priv(set); |
| 218 | struct nft_hash_table *tbl = nft_dereference(priv->tbl); | ||
| 219 | struct nft_hash_elem *he; | 50 | struct nft_hash_elem *he; |
| 220 | unsigned int size, h; | 51 | unsigned int size; |
| 221 | 52 | ||
| 222 | if (elem->flags != 0) | 53 | if (elem->flags != 0) |
| 223 | return -EINVAL; | 54 | return -EINVAL; |
| @@ -234,13 +65,7 @@ static int nft_hash_insert(const struct nft_set *set, | |||
| 234 | if (set->flags & NFT_SET_MAP) | 65 | if (set->flags & NFT_SET_MAP) |
| 235 | nft_data_copy(he->data, &elem->data); | 66 | nft_data_copy(he->data, &elem->data); |
| 236 | 67 | ||
| 237 | h = nft_hash_data(&he->key, tbl->size, set->klen); | 68 | rhashtable_insert(priv, &he->node, GFP_KERNEL); |
| 238 | RCU_INIT_POINTER(he->next, tbl->buckets[h]); | ||
| 239 | rcu_assign_pointer(tbl->buckets[h], he); | ||
| 240 | |||
| 241 | /* Expand table when exceeding 75% load */ | ||
| 242 | if (set->nelems + 1 > tbl->size / 4 * 3) | ||
| 243 | nft_hash_tbl_expand(set, priv); | ||
| 244 | 69 | ||
| 245 | return 0; | 70 | return 0; |
| 246 | } | 71 | } |
| @@ -257,36 +82,31 @@ static void nft_hash_elem_destroy(const struct nft_set *set, | |||
| 257 | static void nft_hash_remove(const struct nft_set *set, | 82 | static void nft_hash_remove(const struct nft_set *set, |
| 258 | const struct nft_set_elem *elem) | 83 | const struct nft_set_elem *elem) |
| 259 | { | 84 | { |
| 260 | struct nft_hash *priv = nft_set_priv(set); | 85 | struct rhashtable *priv = nft_set_priv(set); |
| 261 | struct nft_hash_table *tbl = nft_dereference(priv->tbl); | 86 | struct rhash_head *he, __rcu **pprev; |
| 262 | struct nft_hash_elem *he, __rcu **pprev; | ||
| 263 | 87 | ||
| 264 | pprev = elem->cookie; | 88 | pprev = elem->cookie; |
| 265 | he = nft_dereference((*pprev)); | 89 | he = rht_dereference((*pprev), priv); |
| 90 | |||
| 91 | rhashtable_remove_pprev(priv, he, pprev, GFP_KERNEL); | ||
| 266 | 92 | ||
| 267 | RCU_INIT_POINTER(*pprev, he->next); | ||
| 268 | synchronize_rcu(); | 93 | synchronize_rcu(); |
| 269 | kfree(he); | 94 | kfree(he); |
| 270 | |||
| 271 | /* Shrink table beneath 30% load */ | ||
| 272 | if (set->nelems - 1 < tbl->size * 3 / 10 && | ||
| 273 | tbl->size > NFT_HASH_MIN_SIZE) | ||
| 274 | nft_hash_tbl_shrink(set, priv); | ||
| 275 | } | 95 | } |
| 276 | 96 | ||
| 277 | static int nft_hash_get(const struct nft_set *set, struct nft_set_elem *elem) | 97 | static int nft_hash_get(const struct nft_set *set, struct nft_set_elem *elem) |
| 278 | { | 98 | { |
| 279 | const struct nft_hash *priv = nft_set_priv(set); | 99 | const struct rhashtable *priv = nft_set_priv(set); |
| 280 | const struct nft_hash_table *tbl = nft_dereference(priv->tbl); | 100 | const struct bucket_table *tbl = rht_dereference_rcu(priv->tbl, priv); |
| 281 | struct nft_hash_elem __rcu * const *pprev; | 101 | struct rhash_head __rcu * const *pprev; |
| 282 | struct nft_hash_elem *he; | 102 | struct nft_hash_elem *he; |
| 283 | unsigned int h; | 103 | u32 h; |
| 284 | 104 | ||
| 285 | h = nft_hash_data(&elem->key, tbl->size, set->klen); | 105 | h = rhashtable_hashfn(priv, &elem->key, set->klen); |
| 286 | pprev = &tbl->buckets[h]; | 106 | pprev = &tbl->buckets[h]; |
| 287 | nft_hash_for_each_entry(he, tbl->buckets[h]) { | 107 | rht_for_each_entry_rcu(he, tbl->buckets[h], node) { |
| 288 | if (nft_data_cmp(&he->key, &elem->key, set->klen)) { | 108 | if (nft_data_cmp(&he->key, &elem->key, set->klen)) { |
| 289 | pprev = &he->next; | 109 | pprev = &he->node.next; |
| 290 | continue; | 110 | continue; |
| 291 | } | 111 | } |
| 292 | 112 | ||
| @@ -302,14 +122,15 @@ static int nft_hash_get(const struct nft_set *set, struct nft_set_elem *elem) | |||
| 302 | static void nft_hash_walk(const struct nft_ctx *ctx, const struct nft_set *set, | 122 | static void nft_hash_walk(const struct nft_ctx *ctx, const struct nft_set *set, |
| 303 | struct nft_set_iter *iter) | 123 | struct nft_set_iter *iter) |
| 304 | { | 124 | { |
| 305 | const struct nft_hash *priv = nft_set_priv(set); | 125 | const struct rhashtable *priv = nft_set_priv(set); |
| 306 | const struct nft_hash_table *tbl = nft_dereference(priv->tbl); | 126 | const struct bucket_table *tbl; |
| 307 | const struct nft_hash_elem *he; | 127 | const struct nft_hash_elem *he; |
| 308 | struct nft_set_elem elem; | 128 | struct nft_set_elem elem; |
| 309 | unsigned int i; | 129 | unsigned int i; |
| 310 | 130 | ||
| 131 | tbl = rht_dereference_rcu(priv->tbl, priv); | ||
| 311 | for (i = 0; i < tbl->size; i++) { | 132 | for (i = 0; i < tbl->size; i++) { |
| 312 | nft_hash_for_each_entry(he, tbl->buckets[i]) { | 133 | rht_for_each_entry_rcu(he, tbl->buckets[i], node) { |
| 313 | if (iter->count < iter->skip) | 134 | if (iter->count < iter->skip) |
| 314 | goto cont; | 135 | goto cont; |
| 315 | 136 | ||
| @@ -329,48 +150,46 @@ cont: | |||
| 329 | 150 | ||
| 330 | static unsigned int nft_hash_privsize(const struct nlattr * const nla[]) | 151 | static unsigned int nft_hash_privsize(const struct nlattr * const nla[]) |
| 331 | { | 152 | { |
| 332 | return sizeof(struct nft_hash); | 153 | return sizeof(struct rhashtable); |
| 154 | } | ||
| 155 | |||
| 156 | static int lockdep_nfnl_lock_is_held(void) | ||
| 157 | { | ||
| 158 | return lockdep_nfnl_is_held(NFNL_SUBSYS_NFTABLES); | ||
| 333 | } | 159 | } |
| 334 | 160 | ||
| 335 | static int nft_hash_init(const struct nft_set *set, | 161 | static int nft_hash_init(const struct nft_set *set, |
| 336 | const struct nft_set_desc *desc, | 162 | const struct nft_set_desc *desc, |
| 337 | const struct nlattr * const tb[]) | 163 | const struct nlattr * const tb[]) |
| 338 | { | 164 | { |
| 339 | struct nft_hash *priv = nft_set_priv(set); | 165 | struct rhashtable *priv = nft_set_priv(set); |
| 340 | struct nft_hash_table *tbl; | 166 | struct rhashtable_params params = { |
| 341 | unsigned int size; | 167 | .nelem_hint = desc->size ? : NFT_HASH_ELEMENT_HINT, |
| 168 | .head_offset = offsetof(struct nft_hash_elem, node), | ||
| 169 | .key_offset = offsetof(struct nft_hash_elem, key), | ||
| 170 | .key_len = set->klen, | ||
| 171 | .hashfn = jhash, | ||
| 172 | .grow_decision = rht_grow_above_75, | ||
| 173 | .shrink_decision = rht_shrink_below_30, | ||
| 174 | .mutex_is_held = lockdep_nfnl_lock_is_held, | ||
| 175 | }; | ||
| 342 | 176 | ||
| 343 | if (unlikely(!nft_hash_rnd_initted)) { | 177 | return rhashtable_init(priv, ¶ms); |
| 344 | get_random_bytes(&nft_hash_rnd, 4); | ||
| 345 | nft_hash_rnd_initted = true; | ||
| 346 | } | ||
| 347 | |||
| 348 | size = NFT_HASH_MIN_SIZE; | ||
| 349 | if (desc->size) | ||
| 350 | size = nft_hash_tbl_size(desc->size); | ||
| 351 | |||
| 352 | tbl = nft_hash_tbl_alloc(size); | ||
| 353 | if (tbl == NULL) | ||
| 354 | return -ENOMEM; | ||
| 355 | RCU_INIT_POINTER(priv->tbl, tbl); | ||
| 356 | return 0; | ||
| 357 | } | 178 | } |
| 358 | 179 | ||
| 359 | static void nft_hash_destroy(const struct nft_set *set) | 180 | static void nft_hash_destroy(const struct nft_set *set) |
| 360 | { | 181 | { |
| 361 | const struct nft_hash *priv = nft_set_priv(set); | 182 | const struct rhashtable *priv = nft_set_priv(set); |
| 362 | const struct nft_hash_table *tbl = nft_dereference(priv->tbl); | 183 | const struct bucket_table *tbl; |
| 363 | struct nft_hash_elem *he, *next; | 184 | struct nft_hash_elem *he, *next; |
| 364 | unsigned int i; | 185 | unsigned int i; |
| 365 | 186 | ||
| 366 | for (i = 0; i < tbl->size; i++) { | 187 | tbl = rht_dereference(priv->tbl, priv); |
| 367 | for (he = nft_dereference(tbl->buckets[i]); he != NULL; | 188 | for (i = 0; i < tbl->size; i++) |
| 368 | he = next) { | 189 | rht_for_each_entry_safe(he, next, tbl->buckets[i], priv, node) |
| 369 | next = nft_dereference(he->next); | ||
| 370 | nft_hash_elem_destroy(set, he); | 190 | nft_hash_elem_destroy(set, he); |
| 371 | } | 191 | |
| 372 | } | 192 | rhashtable_destroy(priv); |
| 373 | kfree(tbl); | ||
| 374 | } | 193 | } |
| 375 | 194 | ||
| 376 | static bool nft_hash_estimate(const struct nft_set_desc *desc, u32 features, | 195 | static bool nft_hash_estimate(const struct nft_set_desc *desc, u32 features, |
| @@ -383,8 +202,8 @@ static bool nft_hash_estimate(const struct nft_set_desc *desc, u32 features, | |||
| 383 | esize += FIELD_SIZEOF(struct nft_hash_elem, data[0]); | 202 | esize += FIELD_SIZEOF(struct nft_hash_elem, data[0]); |
| 384 | 203 | ||
| 385 | if (desc->size) { | 204 | if (desc->size) { |
| 386 | est->size = sizeof(struct nft_hash) + | 205 | est->size = sizeof(struct rhashtable) + |
| 387 | nft_hash_tbl_size(desc->size) * | 206 | roundup_pow_of_two(desc->size * 4 / 3) * |
| 388 | sizeof(struct nft_hash_elem *) + | 207 | sizeof(struct nft_hash_elem *) + |
| 389 | desc->size * esize; | 208 | desc->size * esize; |
| 390 | } else { | 209 | } else { |
diff --git a/net/netfilter/nft_log.c b/net/netfilter/nft_log.c index 10cfb156cdf4..bde05f28cf14 100644 --- a/net/netfilter/nft_log.c +++ b/net/netfilter/nft_log.c | |||
| @@ -1,5 +1,6 @@ | |||
| 1 | /* | 1 | /* |
| 2 | * Copyright (c) 2008-2009 Patrick McHardy <kaber@trash.net> | 2 | * Copyright (c) 2008-2009 Patrick McHardy <kaber@trash.net> |
| 3 | * Copyright (c) 2012-2014 Pablo Neira Ayuso <pablo@netfilter.org> | ||
| 3 | * | 4 | * |
| 4 | * This program is free software; you can redistribute it and/or modify | 5 | * This program is free software; you can redistribute it and/or modify |
| 5 | * it under the terms of the GNU General Public License version 2 as | 6 | * it under the terms of the GNU General Public License version 2 as |
| @@ -41,6 +42,8 @@ static const struct nla_policy nft_log_policy[NFTA_LOG_MAX + 1] = { | |||
| 41 | [NFTA_LOG_PREFIX] = { .type = NLA_STRING }, | 42 | [NFTA_LOG_PREFIX] = { .type = NLA_STRING }, |
| 42 | [NFTA_LOG_SNAPLEN] = { .type = NLA_U32 }, | 43 | [NFTA_LOG_SNAPLEN] = { .type = NLA_U32 }, |
| 43 | [NFTA_LOG_QTHRESHOLD] = { .type = NLA_U16 }, | 44 | [NFTA_LOG_QTHRESHOLD] = { .type = NLA_U16 }, |
| 45 | [NFTA_LOG_LEVEL] = { .type = NLA_U32 }, | ||
| 46 | [NFTA_LOG_FLAGS] = { .type = NLA_U32 }, | ||
| 44 | }; | 47 | }; |
| 45 | 48 | ||
| 46 | static int nft_log_init(const struct nft_ctx *ctx, | 49 | static int nft_log_init(const struct nft_ctx *ctx, |
| @@ -50,6 +53,7 @@ static int nft_log_init(const struct nft_ctx *ctx, | |||
| 50 | struct nft_log *priv = nft_expr_priv(expr); | 53 | struct nft_log *priv = nft_expr_priv(expr); |
| 51 | struct nf_loginfo *li = &priv->loginfo; | 54 | struct nf_loginfo *li = &priv->loginfo; |
| 52 | const struct nlattr *nla; | 55 | const struct nlattr *nla; |
| 56 | int ret; | ||
| 53 | 57 | ||
| 54 | nla = tb[NFTA_LOG_PREFIX]; | 58 | nla = tb[NFTA_LOG_PREFIX]; |
| 55 | if (nla != NULL) { | 59 | if (nla != NULL) { |
| @@ -57,30 +61,74 @@ static int nft_log_init(const struct nft_ctx *ctx, | |||
| 57 | if (priv->prefix == NULL) | 61 | if (priv->prefix == NULL) |
| 58 | return -ENOMEM; | 62 | return -ENOMEM; |
| 59 | nla_strlcpy(priv->prefix, nla, nla_len(nla) + 1); | 63 | nla_strlcpy(priv->prefix, nla, nla_len(nla) + 1); |
| 60 | } else | 64 | } else { |
| 61 | priv->prefix = (char *)nft_log_null_prefix; | 65 | priv->prefix = (char *)nft_log_null_prefix; |
| 66 | } | ||
| 62 | 67 | ||
| 63 | li->type = NF_LOG_TYPE_ULOG; | 68 | li->type = NF_LOG_TYPE_LOG; |
| 69 | if (tb[NFTA_LOG_LEVEL] != NULL && | ||
| 70 | tb[NFTA_LOG_GROUP] != NULL) | ||
| 71 | return -EINVAL; | ||
| 64 | if (tb[NFTA_LOG_GROUP] != NULL) | 72 | if (tb[NFTA_LOG_GROUP] != NULL) |
| 73 | li->type = NF_LOG_TYPE_ULOG; | ||
| 74 | |||
| 75 | switch (li->type) { | ||
| 76 | case NF_LOG_TYPE_LOG: | ||
| 77 | if (tb[NFTA_LOG_LEVEL] != NULL) { | ||
| 78 | li->u.log.level = | ||
| 79 | ntohl(nla_get_be32(tb[NFTA_LOG_LEVEL])); | ||
| 80 | } else { | ||
| 81 | li->u.log.level = 4; | ||
| 82 | } | ||
| 83 | if (tb[NFTA_LOG_FLAGS] != NULL) { | ||
| 84 | li->u.log.logflags = | ||
| 85 | ntohl(nla_get_be32(tb[NFTA_LOG_FLAGS])); | ||
| 86 | } | ||
| 87 | break; | ||
| 88 | case NF_LOG_TYPE_ULOG: | ||
| 65 | li->u.ulog.group = ntohs(nla_get_be16(tb[NFTA_LOG_GROUP])); | 89 | li->u.ulog.group = ntohs(nla_get_be16(tb[NFTA_LOG_GROUP])); |
| 90 | if (tb[NFTA_LOG_SNAPLEN] != NULL) { | ||
| 91 | li->u.ulog.copy_len = | ||
| 92 | ntohl(nla_get_be32(tb[NFTA_LOG_SNAPLEN])); | ||
| 93 | } | ||
| 94 | if (tb[NFTA_LOG_QTHRESHOLD] != NULL) { | ||
| 95 | li->u.ulog.qthreshold = | ||
| 96 | ntohs(nla_get_be16(tb[NFTA_LOG_QTHRESHOLD])); | ||
| 97 | } | ||
| 98 | break; | ||
| 99 | } | ||
| 66 | 100 | ||
| 67 | if (tb[NFTA_LOG_SNAPLEN] != NULL) | 101 | if (ctx->afi->family == NFPROTO_INET) { |
| 68 | li->u.ulog.copy_len = ntohl(nla_get_be32(tb[NFTA_LOG_SNAPLEN])); | 102 | ret = nf_logger_find_get(NFPROTO_IPV4, li->type); |
| 69 | if (tb[NFTA_LOG_QTHRESHOLD] != NULL) { | 103 | if (ret < 0) |
| 70 | li->u.ulog.qthreshold = | 104 | return ret; |
| 71 | ntohs(nla_get_be16(tb[NFTA_LOG_QTHRESHOLD])); | 105 | |
| 106 | ret = nf_logger_find_get(NFPROTO_IPV6, li->type); | ||
| 107 | if (ret < 0) { | ||
| 108 | nf_logger_put(NFPROTO_IPV4, li->type); | ||
| 109 | return ret; | ||
| 110 | } | ||
| 111 | return 0; | ||
| 72 | } | 112 | } |
| 73 | 113 | ||
| 74 | return 0; | 114 | return nf_logger_find_get(ctx->afi->family, li->type); |
| 75 | } | 115 | } |
| 76 | 116 | ||
| 77 | static void nft_log_destroy(const struct nft_ctx *ctx, | 117 | static void nft_log_destroy(const struct nft_ctx *ctx, |
| 78 | const struct nft_expr *expr) | 118 | const struct nft_expr *expr) |
| 79 | { | 119 | { |
| 80 | struct nft_log *priv = nft_expr_priv(expr); | 120 | struct nft_log *priv = nft_expr_priv(expr); |
| 121 | struct nf_loginfo *li = &priv->loginfo; | ||
| 81 | 122 | ||
| 82 | if (priv->prefix != nft_log_null_prefix) | 123 | if (priv->prefix != nft_log_null_prefix) |
| 83 | kfree(priv->prefix); | 124 | kfree(priv->prefix); |
| 125 | |||
| 126 | if (ctx->afi->family == NFPROTO_INET) { | ||
| 127 | nf_logger_put(NFPROTO_IPV4, li->type); | ||
| 128 | nf_logger_put(NFPROTO_IPV6, li->type); | ||
| 129 | } else { | ||
| 130 | nf_logger_put(ctx->afi->family, li->type); | ||
| 131 | } | ||
| 84 | } | 132 | } |
| 85 | 133 | ||
| 86 | static int nft_log_dump(struct sk_buff *skb, const struct nft_expr *expr) | 134 | static int nft_log_dump(struct sk_buff *skb, const struct nft_expr *expr) |
| @@ -91,17 +139,33 @@ static int nft_log_dump(struct sk_buff *skb, const struct nft_expr *expr) | |||
| 91 | if (priv->prefix != nft_log_null_prefix) | 139 | if (priv->prefix != nft_log_null_prefix) |
| 92 | if (nla_put_string(skb, NFTA_LOG_PREFIX, priv->prefix)) | 140 | if (nla_put_string(skb, NFTA_LOG_PREFIX, priv->prefix)) |
| 93 | goto nla_put_failure; | 141 | goto nla_put_failure; |
| 94 | if (li->u.ulog.group) | 142 | switch (li->type) { |
| 95 | if (nla_put_be16(skb, NFTA_LOG_GROUP, htons(li->u.ulog.group))) | 143 | case NF_LOG_TYPE_LOG: |
| 96 | goto nla_put_failure; | 144 | if (nla_put_be32(skb, NFTA_LOG_LEVEL, htonl(li->u.log.level))) |
| 97 | if (li->u.ulog.copy_len) | ||
| 98 | if (nla_put_be32(skb, NFTA_LOG_SNAPLEN, | ||
| 99 | htonl(li->u.ulog.copy_len))) | ||
| 100 | goto nla_put_failure; | 145 | goto nla_put_failure; |
| 101 | if (li->u.ulog.qthreshold) | 146 | |
| 102 | if (nla_put_be16(skb, NFTA_LOG_QTHRESHOLD, | 147 | if (li->u.log.logflags) { |
| 103 | htons(li->u.ulog.qthreshold))) | 148 | if (nla_put_be32(skb, NFTA_LOG_FLAGS, |
| 149 | htonl(li->u.log.logflags))) | ||
| 150 | goto nla_put_failure; | ||
| 151 | } | ||
| 152 | break; | ||
| 153 | case NF_LOG_TYPE_ULOG: | ||
| 154 | if (nla_put_be16(skb, NFTA_LOG_GROUP, htons(li->u.ulog.group))) | ||
| 104 | goto nla_put_failure; | 155 | goto nla_put_failure; |
| 156 | |||
| 157 | if (li->u.ulog.copy_len) { | ||
| 158 | if (nla_put_be32(skb, NFTA_LOG_SNAPLEN, | ||
| 159 | htonl(li->u.ulog.copy_len))) | ||
| 160 | goto nla_put_failure; | ||
| 161 | } | ||
| 162 | if (li->u.ulog.qthreshold) { | ||
| 163 | if (nla_put_be16(skb, NFTA_LOG_QTHRESHOLD, | ||
| 164 | htons(li->u.ulog.qthreshold))) | ||
| 165 | goto nla_put_failure; | ||
| 166 | } | ||
| 167 | break; | ||
| 168 | } | ||
| 105 | return 0; | 169 | return 0; |
| 106 | 170 | ||
| 107 | nla_put_failure: | 171 | nla_put_failure: |
diff --git a/net/netfilter/x_tables.c b/net/netfilter/x_tables.c index 227aa11e8409..272ae4d6fdf4 100644 --- a/net/netfilter/x_tables.c +++ b/net/netfilter/x_tables.c | |||
| @@ -71,18 +71,14 @@ static const char *const xt_prefix[NFPROTO_NUMPROTO] = { | |||
| 71 | static const unsigned int xt_jumpstack_multiplier = 2; | 71 | static const unsigned int xt_jumpstack_multiplier = 2; |
| 72 | 72 | ||
| 73 | /* Registration hooks for targets. */ | 73 | /* Registration hooks for targets. */ |
| 74 | int | 74 | int xt_register_target(struct xt_target *target) |
| 75 | xt_register_target(struct xt_target *target) | ||
| 76 | { | 75 | { |
| 77 | u_int8_t af = target->family; | 76 | u_int8_t af = target->family; |
| 78 | int ret; | ||
| 79 | 77 | ||
| 80 | ret = mutex_lock_interruptible(&xt[af].mutex); | 78 | mutex_lock(&xt[af].mutex); |
| 81 | if (ret != 0) | ||
| 82 | return ret; | ||
| 83 | list_add(&target->list, &xt[af].target); | 79 | list_add(&target->list, &xt[af].target); |
| 84 | mutex_unlock(&xt[af].mutex); | 80 | mutex_unlock(&xt[af].mutex); |
| 85 | return ret; | 81 | return 0; |
| 86 | } | 82 | } |
| 87 | EXPORT_SYMBOL(xt_register_target); | 83 | EXPORT_SYMBOL(xt_register_target); |
| 88 | 84 | ||
| @@ -125,20 +121,14 @@ xt_unregister_targets(struct xt_target *target, unsigned int n) | |||
| 125 | } | 121 | } |
| 126 | EXPORT_SYMBOL(xt_unregister_targets); | 122 | EXPORT_SYMBOL(xt_unregister_targets); |
| 127 | 123 | ||
| 128 | int | 124 | int xt_register_match(struct xt_match *match) |
| 129 | xt_register_match(struct xt_match *match) | ||
| 130 | { | 125 | { |
| 131 | u_int8_t af = match->family; | 126 | u_int8_t af = match->family; |
| 132 | int ret; | ||
| 133 | |||
| 134 | ret = mutex_lock_interruptible(&xt[af].mutex); | ||
| 135 | if (ret != 0) | ||
| 136 | return ret; | ||
| 137 | 127 | ||
| 128 | mutex_lock(&xt[af].mutex); | ||
| 138 | list_add(&match->list, &xt[af].match); | 129 | list_add(&match->list, &xt[af].match); |
| 139 | mutex_unlock(&xt[af].mutex); | 130 | mutex_unlock(&xt[af].mutex); |
| 140 | 131 | return 0; | |
| 141 | return ret; | ||
| 142 | } | 132 | } |
| 143 | EXPORT_SYMBOL(xt_register_match); | 133 | EXPORT_SYMBOL(xt_register_match); |
| 144 | 134 | ||
| @@ -194,9 +184,7 @@ struct xt_match *xt_find_match(u8 af, const char *name, u8 revision) | |||
| 194 | struct xt_match *m; | 184 | struct xt_match *m; |
| 195 | int err = -ENOENT; | 185 | int err = -ENOENT; |
| 196 | 186 | ||
| 197 | if (mutex_lock_interruptible(&xt[af].mutex) != 0) | 187 | mutex_lock(&xt[af].mutex); |
| 198 | return ERR_PTR(-EINTR); | ||
| 199 | |||
| 200 | list_for_each_entry(m, &xt[af].match, list) { | 188 | list_for_each_entry(m, &xt[af].match, list) { |
| 201 | if (strcmp(m->name, name) == 0) { | 189 | if (strcmp(m->name, name) == 0) { |
| 202 | if (m->revision == revision) { | 190 | if (m->revision == revision) { |
| @@ -239,9 +227,7 @@ struct xt_target *xt_find_target(u8 af, const char *name, u8 revision) | |||
| 239 | struct xt_target *t; | 227 | struct xt_target *t; |
| 240 | int err = -ENOENT; | 228 | int err = -ENOENT; |
| 241 | 229 | ||
| 242 | if (mutex_lock_interruptible(&xt[af].mutex) != 0) | 230 | mutex_lock(&xt[af].mutex); |
| 243 | return ERR_PTR(-EINTR); | ||
| 244 | |||
| 245 | list_for_each_entry(t, &xt[af].target, list) { | 231 | list_for_each_entry(t, &xt[af].target, list) { |
| 246 | if (strcmp(t->name, name) == 0) { | 232 | if (strcmp(t->name, name) == 0) { |
| 247 | if (t->revision == revision) { | 233 | if (t->revision == revision) { |
| @@ -323,10 +309,7 @@ int xt_find_revision(u8 af, const char *name, u8 revision, int target, | |||
| 323 | { | 309 | { |
| 324 | int have_rev, best = -1; | 310 | int have_rev, best = -1; |
| 325 | 311 | ||
| 326 | if (mutex_lock_interruptible(&xt[af].mutex) != 0) { | 312 | mutex_lock(&xt[af].mutex); |
| 327 | *err = -EINTR; | ||
| 328 | return 1; | ||
| 329 | } | ||
| 330 | if (target == 1) | 313 | if (target == 1) |
| 331 | have_rev = target_revfn(af, name, revision, &best); | 314 | have_rev = target_revfn(af, name, revision, &best); |
| 332 | else | 315 | else |
| @@ -711,28 +694,15 @@ void xt_free_table_info(struct xt_table_info *info) | |||
| 711 | { | 694 | { |
| 712 | int cpu; | 695 | int cpu; |
| 713 | 696 | ||
| 714 | for_each_possible_cpu(cpu) { | 697 | for_each_possible_cpu(cpu) |
| 715 | if (info->size <= PAGE_SIZE) | 698 | kvfree(info->entries[cpu]); |
| 716 | kfree(info->entries[cpu]); | ||
| 717 | else | ||
| 718 | vfree(info->entries[cpu]); | ||
| 719 | } | ||
| 720 | 699 | ||
| 721 | if (info->jumpstack != NULL) { | 700 | if (info->jumpstack != NULL) { |
| 722 | if (sizeof(void *) * info->stacksize > PAGE_SIZE) { | 701 | for_each_possible_cpu(cpu) |
| 723 | for_each_possible_cpu(cpu) | 702 | kvfree(info->jumpstack[cpu]); |
| 724 | vfree(info->jumpstack[cpu]); | 703 | kvfree(info->jumpstack); |
| 725 | } else { | ||
| 726 | for_each_possible_cpu(cpu) | ||
| 727 | kfree(info->jumpstack[cpu]); | ||
| 728 | } | ||
| 729 | } | 704 | } |
| 730 | 705 | ||
| 731 | if (sizeof(void **) * nr_cpu_ids > PAGE_SIZE) | ||
| 732 | vfree(info->jumpstack); | ||
| 733 | else | ||
| 734 | kfree(info->jumpstack); | ||
| 735 | |||
| 736 | free_percpu(info->stackptr); | 706 | free_percpu(info->stackptr); |
| 737 | 707 | ||
| 738 | kfree(info); | 708 | kfree(info); |
| @@ -745,9 +715,7 @@ struct xt_table *xt_find_table_lock(struct net *net, u_int8_t af, | |||
| 745 | { | 715 | { |
| 746 | struct xt_table *t; | 716 | struct xt_table *t; |
| 747 | 717 | ||
| 748 | if (mutex_lock_interruptible(&xt[af].mutex) != 0) | 718 | mutex_lock(&xt[af].mutex); |
| 749 | return ERR_PTR(-EINTR); | ||
| 750 | |||
| 751 | list_for_each_entry(t, &net->xt.tables[af], list) | 719 | list_for_each_entry(t, &net->xt.tables[af], list) |
| 752 | if (strcmp(t->name, name) == 0 && try_module_get(t->me)) | 720 | if (strcmp(t->name, name) == 0 && try_module_get(t->me)) |
| 753 | return t; | 721 | return t; |
| @@ -896,10 +864,7 @@ struct xt_table *xt_register_table(struct net *net, | |||
| 896 | goto out; | 864 | goto out; |
| 897 | } | 865 | } |
| 898 | 866 | ||
| 899 | ret = mutex_lock_interruptible(&xt[table->af].mutex); | 867 | mutex_lock(&xt[table->af].mutex); |
| 900 | if (ret != 0) | ||
| 901 | goto out_free; | ||
| 902 | |||
| 903 | /* Don't autoload: we'd eat our tail... */ | 868 | /* Don't autoload: we'd eat our tail... */ |
| 904 | list_for_each_entry(t, &net->xt.tables[table->af], list) { | 869 | list_for_each_entry(t, &net->xt.tables[table->af], list) { |
| 905 | if (strcmp(t->name, table->name) == 0) { | 870 | if (strcmp(t->name, table->name) == 0) { |
| @@ -924,9 +889,8 @@ struct xt_table *xt_register_table(struct net *net, | |||
| 924 | mutex_unlock(&xt[table->af].mutex); | 889 | mutex_unlock(&xt[table->af].mutex); |
| 925 | return table; | 890 | return table; |
| 926 | 891 | ||
| 927 | unlock: | 892 | unlock: |
| 928 | mutex_unlock(&xt[table->af].mutex); | 893 | mutex_unlock(&xt[table->af].mutex); |
| 929 | out_free: | ||
| 930 | kfree(table); | 894 | kfree(table); |
| 931 | out: | 895 | out: |
| 932 | return ERR_PTR(ret); | 896 | return ERR_PTR(ret); |
diff --git a/net/netfilter/xt_LED.c b/net/netfilter/xt_LED.c index 993de2ba89d3..3ba31c194cce 100644 --- a/net/netfilter/xt_LED.c +++ b/net/netfilter/xt_LED.c | |||
| @@ -50,11 +50,14 @@ struct xt_led_info_internal { | |||
| 50 | struct timer_list timer; | 50 | struct timer_list timer; |
| 51 | }; | 51 | }; |
| 52 | 52 | ||
| 53 | #define XT_LED_BLINK_DELAY 50 /* ms */ | ||
| 54 | |||
| 53 | static unsigned int | 55 | static unsigned int |
| 54 | led_tg(struct sk_buff *skb, const struct xt_action_param *par) | 56 | led_tg(struct sk_buff *skb, const struct xt_action_param *par) |
| 55 | { | 57 | { |
| 56 | const struct xt_led_info *ledinfo = par->targinfo; | 58 | const struct xt_led_info *ledinfo = par->targinfo; |
| 57 | struct xt_led_info_internal *ledinternal = ledinfo->internal_data; | 59 | struct xt_led_info_internal *ledinternal = ledinfo->internal_data; |
| 60 | unsigned long led_delay = XT_LED_BLINK_DELAY; | ||
| 58 | 61 | ||
| 59 | /* | 62 | /* |
| 60 | * If "always blink" is enabled, and there's still some time until the | 63 | * If "always blink" is enabled, and there's still some time until the |
| @@ -62,9 +65,10 @@ led_tg(struct sk_buff *skb, const struct xt_action_param *par) | |||
| 62 | */ | 65 | */ |
| 63 | if ((ledinfo->delay > 0) && ledinfo->always_blink && | 66 | if ((ledinfo->delay > 0) && ledinfo->always_blink && |
| 64 | timer_pending(&ledinternal->timer)) | 67 | timer_pending(&ledinternal->timer)) |
| 65 | led_trigger_event(&ledinternal->netfilter_led_trigger, LED_OFF); | 68 | led_trigger_blink_oneshot(&ledinternal->netfilter_led_trigger, |
| 66 | 69 | &led_delay, &led_delay, 1); | |
| 67 | led_trigger_event(&ledinternal->netfilter_led_trigger, LED_FULL); | 70 | else |
| 71 | led_trigger_event(&ledinternal->netfilter_led_trigger, LED_FULL); | ||
| 68 | 72 | ||
| 69 | /* If there's a positive delay, start/update the timer */ | 73 | /* If there's a positive delay, start/update the timer */ |
| 70 | if (ledinfo->delay > 0) { | 74 | if (ledinfo->delay > 0) { |
| @@ -133,9 +137,7 @@ static int led_tg_check(const struct xt_tgchk_param *par) | |||
| 133 | 137 | ||
| 134 | err = led_trigger_register(&ledinternal->netfilter_led_trigger); | 138 | err = led_trigger_register(&ledinternal->netfilter_led_trigger); |
| 135 | if (err) { | 139 | if (err) { |
| 136 | pr_warning("led_trigger_register() failed\n"); | 140 | pr_err("Trigger name is already in use.\n"); |
| 137 | if (err == -EEXIST) | ||
| 138 | pr_warning("Trigger name is already in use.\n"); | ||
| 139 | goto exit_alloc; | 141 | goto exit_alloc; |
| 140 | } | 142 | } |
| 141 | 143 | ||
diff --git a/net/netfilter/xt_LOG.c b/net/netfilter/xt_LOG.c index 5ab24843370a..c13b79440ede 100644 --- a/net/netfilter/xt_LOG.c +++ b/net/netfilter/xt_LOG.c | |||
| @@ -27,806 +27,6 @@ | |||
| 27 | #include <linux/netfilter/xt_LOG.h> | 27 | #include <linux/netfilter/xt_LOG.h> |
| 28 | #include <linux/netfilter_ipv6/ip6_tables.h> | 28 | #include <linux/netfilter_ipv6/ip6_tables.h> |
| 29 | #include <net/netfilter/nf_log.h> | 29 | #include <net/netfilter/nf_log.h> |
| 30 | #include <net/netfilter/xt_log.h> | ||
| 31 | |||
| 32 | static struct nf_loginfo default_loginfo = { | ||
| 33 | .type = NF_LOG_TYPE_LOG, | ||
| 34 | .u = { | ||
| 35 | .log = { | ||
| 36 | .level = 5, | ||
| 37 | .logflags = NF_LOG_MASK, | ||
| 38 | }, | ||
| 39 | }, | ||
| 40 | }; | ||
| 41 | |||
| 42 | static int dump_udp_header(struct sbuff *m, const struct sk_buff *skb, | ||
| 43 | u8 proto, int fragment, unsigned int offset) | ||
| 44 | { | ||
| 45 | struct udphdr _udph; | ||
| 46 | const struct udphdr *uh; | ||
| 47 | |||
| 48 | if (proto == IPPROTO_UDP) | ||
| 49 | /* Max length: 10 "PROTO=UDP " */ | ||
| 50 | sb_add(m, "PROTO=UDP "); | ||
| 51 | else /* Max length: 14 "PROTO=UDPLITE " */ | ||
| 52 | sb_add(m, "PROTO=UDPLITE "); | ||
| 53 | |||
| 54 | if (fragment) | ||
| 55 | goto out; | ||
| 56 | |||
| 57 | /* Max length: 25 "INCOMPLETE [65535 bytes] " */ | ||
| 58 | uh = skb_header_pointer(skb, offset, sizeof(_udph), &_udph); | ||
| 59 | if (uh == NULL) { | ||
| 60 | sb_add(m, "INCOMPLETE [%u bytes] ", skb->len - offset); | ||
| 61 | |||
| 62 | return 1; | ||
| 63 | } | ||
| 64 | |||
| 65 | /* Max length: 20 "SPT=65535 DPT=65535 " */ | ||
| 66 | sb_add(m, "SPT=%u DPT=%u LEN=%u ", ntohs(uh->source), ntohs(uh->dest), | ||
| 67 | ntohs(uh->len)); | ||
| 68 | |||
| 69 | out: | ||
| 70 | return 0; | ||
| 71 | } | ||
| 72 | |||
| 73 | static int dump_tcp_header(struct sbuff *m, const struct sk_buff *skb, | ||
| 74 | u8 proto, int fragment, unsigned int offset, | ||
| 75 | unsigned int logflags) | ||
| 76 | { | ||
| 77 | struct tcphdr _tcph; | ||
| 78 | const struct tcphdr *th; | ||
| 79 | |||
| 80 | /* Max length: 10 "PROTO=TCP " */ | ||
| 81 | sb_add(m, "PROTO=TCP "); | ||
| 82 | |||
| 83 | if (fragment) | ||
| 84 | return 0; | ||
| 85 | |||
| 86 | /* Max length: 25 "INCOMPLETE [65535 bytes] " */ | ||
| 87 | th = skb_header_pointer(skb, offset, sizeof(_tcph), &_tcph); | ||
| 88 | if (th == NULL) { | ||
| 89 | sb_add(m, "INCOMPLETE [%u bytes] ", skb->len - offset); | ||
| 90 | return 1; | ||
| 91 | } | ||
| 92 | |||
| 93 | /* Max length: 20 "SPT=65535 DPT=65535 " */ | ||
| 94 | sb_add(m, "SPT=%u DPT=%u ", ntohs(th->source), ntohs(th->dest)); | ||
| 95 | /* Max length: 30 "SEQ=4294967295 ACK=4294967295 " */ | ||
| 96 | if (logflags & XT_LOG_TCPSEQ) | ||
| 97 | sb_add(m, "SEQ=%u ACK=%u ", ntohl(th->seq), ntohl(th->ack_seq)); | ||
| 98 | |||
| 99 | /* Max length: 13 "WINDOW=65535 " */ | ||
| 100 | sb_add(m, "WINDOW=%u ", ntohs(th->window)); | ||
| 101 | /* Max length: 9 "RES=0x3C " */ | ||
| 102 | sb_add(m, "RES=0x%02x ", (u_int8_t)(ntohl(tcp_flag_word(th) & | ||
| 103 | TCP_RESERVED_BITS) >> 22)); | ||
| 104 | /* Max length: 32 "CWR ECE URG ACK PSH RST SYN FIN " */ | ||
| 105 | if (th->cwr) | ||
| 106 | sb_add(m, "CWR "); | ||
| 107 | if (th->ece) | ||
| 108 | sb_add(m, "ECE "); | ||
| 109 | if (th->urg) | ||
| 110 | sb_add(m, "URG "); | ||
| 111 | if (th->ack) | ||
| 112 | sb_add(m, "ACK "); | ||
| 113 | if (th->psh) | ||
| 114 | sb_add(m, "PSH "); | ||
| 115 | if (th->rst) | ||
| 116 | sb_add(m, "RST "); | ||
| 117 | if (th->syn) | ||
| 118 | sb_add(m, "SYN "); | ||
| 119 | if (th->fin) | ||
| 120 | sb_add(m, "FIN "); | ||
| 121 | /* Max length: 11 "URGP=65535 " */ | ||
| 122 | sb_add(m, "URGP=%u ", ntohs(th->urg_ptr)); | ||
| 123 | |||
| 124 | if ((logflags & XT_LOG_TCPOPT) && th->doff*4 > sizeof(struct tcphdr)) { | ||
| 125 | u_int8_t _opt[60 - sizeof(struct tcphdr)]; | ||
| 126 | const u_int8_t *op; | ||
| 127 | unsigned int i; | ||
| 128 | unsigned int optsize = th->doff*4 - sizeof(struct tcphdr); | ||
| 129 | |||
| 130 | op = skb_header_pointer(skb, offset + sizeof(struct tcphdr), | ||
| 131 | optsize, _opt); | ||
| 132 | if (op == NULL) { | ||
| 133 | sb_add(m, "OPT (TRUNCATED)"); | ||
| 134 | return 1; | ||
| 135 | } | ||
| 136 | |||
| 137 | /* Max length: 127 "OPT (" 15*4*2chars ") " */ | ||
| 138 | sb_add(m, "OPT ("); | ||
| 139 | for (i = 0; i < optsize; i++) | ||
| 140 | sb_add(m, "%02X", op[i]); | ||
| 141 | |||
| 142 | sb_add(m, ") "); | ||
| 143 | } | ||
| 144 | |||
| 145 | return 0; | ||
| 146 | } | ||
| 147 | |||
| 148 | static void dump_sk_uid_gid(struct sbuff *m, struct sock *sk) | ||
| 149 | { | ||
| 150 | if (!sk || sk->sk_state == TCP_TIME_WAIT) | ||
| 151 | return; | ||
| 152 | |||
| 153 | read_lock_bh(&sk->sk_callback_lock); | ||
| 154 | if (sk->sk_socket && sk->sk_socket->file) { | ||
| 155 | const struct cred *cred = sk->sk_socket->file->f_cred; | ||
| 156 | sb_add(m, "UID=%u GID=%u ", | ||
| 157 | from_kuid_munged(&init_user_ns, cred->fsuid), | ||
| 158 | from_kgid_munged(&init_user_ns, cred->fsgid)); | ||
| 159 | } | ||
| 160 | read_unlock_bh(&sk->sk_callback_lock); | ||
| 161 | } | ||
| 162 | |||
| 163 | /* One level of recursion won't kill us */ | ||
| 164 | static void dump_ipv4_packet(struct sbuff *m, | ||
| 165 | const struct nf_loginfo *info, | ||
| 166 | const struct sk_buff *skb, | ||
| 167 | unsigned int iphoff) | ||
| 168 | { | ||
| 169 | struct iphdr _iph; | ||
| 170 | const struct iphdr *ih; | ||
| 171 | unsigned int logflags; | ||
| 172 | |||
| 173 | if (info->type == NF_LOG_TYPE_LOG) | ||
| 174 | logflags = info->u.log.logflags; | ||
| 175 | else | ||
| 176 | logflags = NF_LOG_MASK; | ||
| 177 | |||
| 178 | ih = skb_header_pointer(skb, iphoff, sizeof(_iph), &_iph); | ||
| 179 | if (ih == NULL) { | ||
| 180 | sb_add(m, "TRUNCATED"); | ||
| 181 | return; | ||
| 182 | } | ||
| 183 | |||
| 184 | /* Important fields: | ||
| 185 | * TOS, len, DF/MF, fragment offset, TTL, src, dst, options. */ | ||
| 186 | /* Max length: 40 "SRC=255.255.255.255 DST=255.255.255.255 " */ | ||
| 187 | sb_add(m, "SRC=%pI4 DST=%pI4 ", | ||
| 188 | &ih->saddr, &ih->daddr); | ||
| 189 | |||
| 190 | /* Max length: 46 "LEN=65535 TOS=0xFF PREC=0xFF TTL=255 ID=65535 " */ | ||
| 191 | sb_add(m, "LEN=%u TOS=0x%02X PREC=0x%02X TTL=%u ID=%u ", | ||
| 192 | ntohs(ih->tot_len), ih->tos & IPTOS_TOS_MASK, | ||
| 193 | ih->tos & IPTOS_PREC_MASK, ih->ttl, ntohs(ih->id)); | ||
| 194 | |||
| 195 | /* Max length: 6 "CE DF MF " */ | ||
| 196 | if (ntohs(ih->frag_off) & IP_CE) | ||
| 197 | sb_add(m, "CE "); | ||
| 198 | if (ntohs(ih->frag_off) & IP_DF) | ||
| 199 | sb_add(m, "DF "); | ||
| 200 | if (ntohs(ih->frag_off) & IP_MF) | ||
| 201 | sb_add(m, "MF "); | ||
| 202 | |||
| 203 | /* Max length: 11 "FRAG:65535 " */ | ||
| 204 | if (ntohs(ih->frag_off) & IP_OFFSET) | ||
| 205 | sb_add(m, "FRAG:%u ", ntohs(ih->frag_off) & IP_OFFSET); | ||
| 206 | |||
| 207 | if ((logflags & XT_LOG_IPOPT) && | ||
| 208 | ih->ihl * 4 > sizeof(struct iphdr)) { | ||
| 209 | const unsigned char *op; | ||
| 210 | unsigned char _opt[4 * 15 - sizeof(struct iphdr)]; | ||
| 211 | unsigned int i, optsize; | ||
| 212 | |||
| 213 | optsize = ih->ihl * 4 - sizeof(struct iphdr); | ||
| 214 | op = skb_header_pointer(skb, iphoff+sizeof(_iph), | ||
| 215 | optsize, _opt); | ||
| 216 | if (op == NULL) { | ||
| 217 | sb_add(m, "TRUNCATED"); | ||
| 218 | return; | ||
| 219 | } | ||
| 220 | |||
| 221 | /* Max length: 127 "OPT (" 15*4*2chars ") " */ | ||
| 222 | sb_add(m, "OPT ("); | ||
| 223 | for (i = 0; i < optsize; i++) | ||
| 224 | sb_add(m, "%02X", op[i]); | ||
| 225 | sb_add(m, ") "); | ||
| 226 | } | ||
| 227 | |||
| 228 | switch (ih->protocol) { | ||
| 229 | case IPPROTO_TCP: | ||
| 230 | if (dump_tcp_header(m, skb, ih->protocol, | ||
| 231 | ntohs(ih->frag_off) & IP_OFFSET, | ||
| 232 | iphoff+ih->ihl*4, logflags)) | ||
| 233 | return; | ||
| 234 | break; | ||
| 235 | case IPPROTO_UDP: | ||
| 236 | case IPPROTO_UDPLITE: | ||
| 237 | if (dump_udp_header(m, skb, ih->protocol, | ||
| 238 | ntohs(ih->frag_off) & IP_OFFSET, | ||
| 239 | iphoff+ih->ihl*4)) | ||
| 240 | return; | ||
| 241 | break; | ||
| 242 | case IPPROTO_ICMP: { | ||
| 243 | struct icmphdr _icmph; | ||
| 244 | const struct icmphdr *ich; | ||
| 245 | static const size_t required_len[NR_ICMP_TYPES+1] | ||
| 246 | = { [ICMP_ECHOREPLY] = 4, | ||
| 247 | [ICMP_DEST_UNREACH] | ||
| 248 | = 8 + sizeof(struct iphdr), | ||
| 249 | [ICMP_SOURCE_QUENCH] | ||
| 250 | = 8 + sizeof(struct iphdr), | ||
| 251 | [ICMP_REDIRECT] | ||
| 252 | = 8 + sizeof(struct iphdr), | ||
| 253 | [ICMP_ECHO] = 4, | ||
| 254 | [ICMP_TIME_EXCEEDED] | ||
| 255 | = 8 + sizeof(struct iphdr), | ||
| 256 | [ICMP_PARAMETERPROB] | ||
| 257 | = 8 + sizeof(struct iphdr), | ||
| 258 | [ICMP_TIMESTAMP] = 20, | ||
| 259 | [ICMP_TIMESTAMPREPLY] = 20, | ||
| 260 | [ICMP_ADDRESS] = 12, | ||
| 261 | [ICMP_ADDRESSREPLY] = 12 }; | ||
| 262 | |||
| 263 | /* Max length: 11 "PROTO=ICMP " */ | ||
| 264 | sb_add(m, "PROTO=ICMP "); | ||
| 265 | |||
| 266 | if (ntohs(ih->frag_off) & IP_OFFSET) | ||
| 267 | break; | ||
| 268 | |||
| 269 | /* Max length: 25 "INCOMPLETE [65535 bytes] " */ | ||
| 270 | ich = skb_header_pointer(skb, iphoff + ih->ihl * 4, | ||
| 271 | sizeof(_icmph), &_icmph); | ||
| 272 | if (ich == NULL) { | ||
| 273 | sb_add(m, "INCOMPLETE [%u bytes] ", | ||
| 274 | skb->len - iphoff - ih->ihl*4); | ||
| 275 | break; | ||
| 276 | } | ||
| 277 | |||
| 278 | /* Max length: 18 "TYPE=255 CODE=255 " */ | ||
| 279 | sb_add(m, "TYPE=%u CODE=%u ", ich->type, ich->code); | ||
| 280 | |||
| 281 | /* Max length: 25 "INCOMPLETE [65535 bytes] " */ | ||
| 282 | if (ich->type <= NR_ICMP_TYPES && | ||
| 283 | required_len[ich->type] && | ||
| 284 | skb->len-iphoff-ih->ihl*4 < required_len[ich->type]) { | ||
| 285 | sb_add(m, "INCOMPLETE [%u bytes] ", | ||
| 286 | skb->len - iphoff - ih->ihl*4); | ||
| 287 | break; | ||
| 288 | } | ||
| 289 | |||
| 290 | switch (ich->type) { | ||
| 291 | case ICMP_ECHOREPLY: | ||
| 292 | case ICMP_ECHO: | ||
| 293 | /* Max length: 19 "ID=65535 SEQ=65535 " */ | ||
| 294 | sb_add(m, "ID=%u SEQ=%u ", | ||
| 295 | ntohs(ich->un.echo.id), | ||
| 296 | ntohs(ich->un.echo.sequence)); | ||
| 297 | break; | ||
| 298 | |||
| 299 | case ICMP_PARAMETERPROB: | ||
| 300 | /* Max length: 14 "PARAMETER=255 " */ | ||
| 301 | sb_add(m, "PARAMETER=%u ", | ||
| 302 | ntohl(ich->un.gateway) >> 24); | ||
| 303 | break; | ||
| 304 | case ICMP_REDIRECT: | ||
| 305 | /* Max length: 24 "GATEWAY=255.255.255.255 " */ | ||
| 306 | sb_add(m, "GATEWAY=%pI4 ", &ich->un.gateway); | ||
| 307 | /* Fall through */ | ||
| 308 | case ICMP_DEST_UNREACH: | ||
| 309 | case ICMP_SOURCE_QUENCH: | ||
| 310 | case ICMP_TIME_EXCEEDED: | ||
| 311 | /* Max length: 3+maxlen */ | ||
| 312 | if (!iphoff) { /* Only recurse once. */ | ||
| 313 | sb_add(m, "["); | ||
| 314 | dump_ipv4_packet(m, info, skb, | ||
| 315 | iphoff + ih->ihl*4+sizeof(_icmph)); | ||
| 316 | sb_add(m, "] "); | ||
| 317 | } | ||
| 318 | |||
| 319 | /* Max length: 10 "MTU=65535 " */ | ||
| 320 | if (ich->type == ICMP_DEST_UNREACH && | ||
| 321 | ich->code == ICMP_FRAG_NEEDED) | ||
| 322 | sb_add(m, "MTU=%u ", ntohs(ich->un.frag.mtu)); | ||
| 323 | } | ||
| 324 | break; | ||
| 325 | } | ||
| 326 | /* Max Length */ | ||
| 327 | case IPPROTO_AH: { | ||
| 328 | struct ip_auth_hdr _ahdr; | ||
| 329 | const struct ip_auth_hdr *ah; | ||
| 330 | |||
| 331 | if (ntohs(ih->frag_off) & IP_OFFSET) | ||
| 332 | break; | ||
| 333 | |||
| 334 | /* Max length: 9 "PROTO=AH " */ | ||
| 335 | sb_add(m, "PROTO=AH "); | ||
| 336 | |||
| 337 | /* Max length: 25 "INCOMPLETE [65535 bytes] " */ | ||
| 338 | ah = skb_header_pointer(skb, iphoff+ih->ihl*4, | ||
| 339 | sizeof(_ahdr), &_ahdr); | ||
| 340 | if (ah == NULL) { | ||
| 341 | sb_add(m, "INCOMPLETE [%u bytes] ", | ||
| 342 | skb->len - iphoff - ih->ihl*4); | ||
| 343 | break; | ||
| 344 | } | ||
| 345 | |||
| 346 | /* Length: 15 "SPI=0xF1234567 " */ | ||
| 347 | sb_add(m, "SPI=0x%x ", ntohl(ah->spi)); | ||
| 348 | break; | ||
| 349 | } | ||
| 350 | case IPPROTO_ESP: { | ||
| 351 | struct ip_esp_hdr _esph; | ||
| 352 | const struct ip_esp_hdr *eh; | ||
| 353 | |||
| 354 | /* Max length: 10 "PROTO=ESP " */ | ||
| 355 | sb_add(m, "PROTO=ESP "); | ||
| 356 | |||
| 357 | if (ntohs(ih->frag_off) & IP_OFFSET) | ||
| 358 | break; | ||
| 359 | |||
| 360 | /* Max length: 25 "INCOMPLETE [65535 bytes] " */ | ||
| 361 | eh = skb_header_pointer(skb, iphoff+ih->ihl*4, | ||
| 362 | sizeof(_esph), &_esph); | ||
| 363 | if (eh == NULL) { | ||
| 364 | sb_add(m, "INCOMPLETE [%u bytes] ", | ||
| 365 | skb->len - iphoff - ih->ihl*4); | ||
| 366 | break; | ||
| 367 | } | ||
| 368 | |||
| 369 | /* Length: 15 "SPI=0xF1234567 " */ | ||
| 370 | sb_add(m, "SPI=0x%x ", ntohl(eh->spi)); | ||
| 371 | break; | ||
| 372 | } | ||
| 373 | /* Max length: 10 "PROTO 255 " */ | ||
| 374 | default: | ||
| 375 | sb_add(m, "PROTO=%u ", ih->protocol); | ||
| 376 | } | ||
| 377 | |||
| 378 | /* Max length: 15 "UID=4294967295 " */ | ||
| 379 | if ((logflags & XT_LOG_UID) && !iphoff) | ||
| 380 | dump_sk_uid_gid(m, skb->sk); | ||
| 381 | |||
| 382 | /* Max length: 16 "MARK=0xFFFFFFFF " */ | ||
| 383 | if (!iphoff && skb->mark) | ||
| 384 | sb_add(m, "MARK=0x%x ", skb->mark); | ||
| 385 | |||
| 386 | /* Proto Max log string length */ | ||
| 387 | /* IP: 40+46+6+11+127 = 230 */ | ||
| 388 | /* TCP: 10+max(25,20+30+13+9+32+11+127) = 252 */ | ||
| 389 | /* UDP: 10+max(25,20) = 35 */ | ||
| 390 | /* UDPLITE: 14+max(25,20) = 39 */ | ||
| 391 | /* ICMP: 11+max(25, 18+25+max(19,14,24+3+n+10,3+n+10)) = 91+n */ | ||
| 392 | /* ESP: 10+max(25)+15 = 50 */ | ||
| 393 | /* AH: 9+max(25)+15 = 49 */ | ||
| 394 | /* unknown: 10 */ | ||
| 395 | |||
| 396 | /* (ICMP allows recursion one level deep) */ | ||
| 397 | /* maxlen = IP + ICMP + IP + max(TCP,UDP,ICMP,unknown) */ | ||
| 398 | /* maxlen = 230+ 91 + 230 + 252 = 803 */ | ||
| 399 | } | ||
| 400 | |||
| 401 | static void dump_ipv4_mac_header(struct sbuff *m, | ||
| 402 | const struct nf_loginfo *info, | ||
| 403 | const struct sk_buff *skb) | ||
| 404 | { | ||
| 405 | struct net_device *dev = skb->dev; | ||
| 406 | unsigned int logflags = 0; | ||
| 407 | |||
| 408 | if (info->type == NF_LOG_TYPE_LOG) | ||
| 409 | logflags = info->u.log.logflags; | ||
| 410 | |||
| 411 | if (!(logflags & XT_LOG_MACDECODE)) | ||
| 412 | goto fallback; | ||
| 413 | |||
| 414 | switch (dev->type) { | ||
| 415 | case ARPHRD_ETHER: | ||
| 416 | sb_add(m, "MACSRC=%pM MACDST=%pM MACPROTO=%04x ", | ||
| 417 | eth_hdr(skb)->h_source, eth_hdr(skb)->h_dest, | ||
| 418 | ntohs(eth_hdr(skb)->h_proto)); | ||
| 419 | return; | ||
| 420 | default: | ||
| 421 | break; | ||
| 422 | } | ||
| 423 | |||
| 424 | fallback: | ||
| 425 | sb_add(m, "MAC="); | ||
| 426 | if (dev->hard_header_len && | ||
| 427 | skb->mac_header != skb->network_header) { | ||
| 428 | const unsigned char *p = skb_mac_header(skb); | ||
| 429 | unsigned int i; | ||
| 430 | |||
| 431 | sb_add(m, "%02x", *p++); | ||
| 432 | for (i = 1; i < dev->hard_header_len; i++, p++) | ||
| 433 | sb_add(m, ":%02x", *p); | ||
| 434 | } | ||
| 435 | sb_add(m, " "); | ||
| 436 | } | ||
| 437 | |||
| 438 | static void | ||
| 439 | log_packet_common(struct sbuff *m, | ||
| 440 | u_int8_t pf, | ||
| 441 | unsigned int hooknum, | ||
| 442 | const struct sk_buff *skb, | ||
| 443 | const struct net_device *in, | ||
| 444 | const struct net_device *out, | ||
| 445 | const struct nf_loginfo *loginfo, | ||
| 446 | const char *prefix) | ||
| 447 | { | ||
| 448 | sb_add(m, KERN_SOH "%c%sIN=%s OUT=%s ", | ||
| 449 | '0' + loginfo->u.log.level, prefix, | ||
| 450 | in ? in->name : "", | ||
| 451 | out ? out->name : ""); | ||
| 452 | #ifdef CONFIG_BRIDGE_NETFILTER | ||
| 453 | if (skb->nf_bridge) { | ||
| 454 | const struct net_device *physindev; | ||
| 455 | const struct net_device *physoutdev; | ||
| 456 | |||
| 457 | physindev = skb->nf_bridge->physindev; | ||
| 458 | if (physindev && in != physindev) | ||
| 459 | sb_add(m, "PHYSIN=%s ", physindev->name); | ||
| 460 | physoutdev = skb->nf_bridge->physoutdev; | ||
| 461 | if (physoutdev && out != physoutdev) | ||
| 462 | sb_add(m, "PHYSOUT=%s ", physoutdev->name); | ||
| 463 | } | ||
| 464 | #endif | ||
| 465 | } | ||
| 466 | |||
| 467 | |||
| 468 | static void | ||
| 469 | ipt_log_packet(struct net *net, | ||
| 470 | u_int8_t pf, | ||
| 471 | unsigned int hooknum, | ||
| 472 | const struct sk_buff *skb, | ||
| 473 | const struct net_device *in, | ||
| 474 | const struct net_device *out, | ||
| 475 | const struct nf_loginfo *loginfo, | ||
| 476 | const char *prefix) | ||
| 477 | { | ||
| 478 | struct sbuff *m; | ||
| 479 | |||
| 480 | /* FIXME: Disabled from containers until syslog ns is supported */ | ||
| 481 | if (!net_eq(net, &init_net)) | ||
| 482 | return; | ||
| 483 | |||
| 484 | m = sb_open(); | ||
| 485 | |||
| 486 | if (!loginfo) | ||
| 487 | loginfo = &default_loginfo; | ||
| 488 | |||
| 489 | log_packet_common(m, pf, hooknum, skb, in, out, loginfo, prefix); | ||
| 490 | |||
| 491 | if (in != NULL) | ||
| 492 | dump_ipv4_mac_header(m, loginfo, skb); | ||
| 493 | |||
| 494 | dump_ipv4_packet(m, loginfo, skb, 0); | ||
| 495 | |||
| 496 | sb_close(m); | ||
| 497 | } | ||
| 498 | |||
| 499 | #if IS_ENABLED(CONFIG_IP6_NF_IPTABLES) | ||
| 500 | /* One level of recursion won't kill us */ | ||
| 501 | static void dump_ipv6_packet(struct sbuff *m, | ||
| 502 | const struct nf_loginfo *info, | ||
| 503 | const struct sk_buff *skb, unsigned int ip6hoff, | ||
| 504 | int recurse) | ||
| 505 | { | ||
| 506 | u_int8_t currenthdr; | ||
| 507 | int fragment; | ||
| 508 | struct ipv6hdr _ip6h; | ||
| 509 | const struct ipv6hdr *ih; | ||
| 510 | unsigned int ptr; | ||
| 511 | unsigned int hdrlen = 0; | ||
| 512 | unsigned int logflags; | ||
| 513 | |||
| 514 | if (info->type == NF_LOG_TYPE_LOG) | ||
| 515 | logflags = info->u.log.logflags; | ||
| 516 | else | ||
| 517 | logflags = NF_LOG_MASK; | ||
| 518 | |||
| 519 | ih = skb_header_pointer(skb, ip6hoff, sizeof(_ip6h), &_ip6h); | ||
| 520 | if (ih == NULL) { | ||
| 521 | sb_add(m, "TRUNCATED"); | ||
| 522 | return; | ||
| 523 | } | ||
| 524 | |||
| 525 | /* Max length: 88 "SRC=0000.0000.0000.0000.0000.0000.0000.0000 DST=0000.0000.0000.0000.0000.0000.0000.0000 " */ | ||
| 526 | sb_add(m, "SRC=%pI6 DST=%pI6 ", &ih->saddr, &ih->daddr); | ||
| 527 | |||
| 528 | /* Max length: 44 "LEN=65535 TC=255 HOPLIMIT=255 FLOWLBL=FFFFF " */ | ||
| 529 | sb_add(m, "LEN=%Zu TC=%u HOPLIMIT=%u FLOWLBL=%u ", | ||
| 530 | ntohs(ih->payload_len) + sizeof(struct ipv6hdr), | ||
| 531 | (ntohl(*(__be32 *)ih) & 0x0ff00000) >> 20, | ||
| 532 | ih->hop_limit, | ||
| 533 | (ntohl(*(__be32 *)ih) & 0x000fffff)); | ||
| 534 | |||
| 535 | fragment = 0; | ||
| 536 | ptr = ip6hoff + sizeof(struct ipv6hdr); | ||
| 537 | currenthdr = ih->nexthdr; | ||
| 538 | while (currenthdr != NEXTHDR_NONE && ip6t_ext_hdr(currenthdr)) { | ||
| 539 | struct ipv6_opt_hdr _hdr; | ||
| 540 | const struct ipv6_opt_hdr *hp; | ||
| 541 | |||
| 542 | hp = skb_header_pointer(skb, ptr, sizeof(_hdr), &_hdr); | ||
| 543 | if (hp == NULL) { | ||
| 544 | sb_add(m, "TRUNCATED"); | ||
| 545 | return; | ||
| 546 | } | ||
| 547 | |||
| 548 | /* Max length: 48 "OPT (...) " */ | ||
| 549 | if (logflags & XT_LOG_IPOPT) | ||
| 550 | sb_add(m, "OPT ( "); | ||
| 551 | |||
| 552 | switch (currenthdr) { | ||
| 553 | case IPPROTO_FRAGMENT: { | ||
| 554 | struct frag_hdr _fhdr; | ||
| 555 | const struct frag_hdr *fh; | ||
| 556 | |||
| 557 | sb_add(m, "FRAG:"); | ||
| 558 | fh = skb_header_pointer(skb, ptr, sizeof(_fhdr), | ||
| 559 | &_fhdr); | ||
| 560 | if (fh == NULL) { | ||
| 561 | sb_add(m, "TRUNCATED "); | ||
| 562 | return; | ||
| 563 | } | ||
| 564 | |||
| 565 | /* Max length: 6 "65535 " */ | ||
| 566 | sb_add(m, "%u ", ntohs(fh->frag_off) & 0xFFF8); | ||
| 567 | |||
| 568 | /* Max length: 11 "INCOMPLETE " */ | ||
| 569 | if (fh->frag_off & htons(0x0001)) | ||
| 570 | sb_add(m, "INCOMPLETE "); | ||
| 571 | |||
| 572 | sb_add(m, "ID:%08x ", ntohl(fh->identification)); | ||
| 573 | |||
| 574 | if (ntohs(fh->frag_off) & 0xFFF8) | ||
| 575 | fragment = 1; | ||
| 576 | |||
| 577 | hdrlen = 8; | ||
| 578 | |||
| 579 | break; | ||
| 580 | } | ||
| 581 | case IPPROTO_DSTOPTS: | ||
| 582 | case IPPROTO_ROUTING: | ||
| 583 | case IPPROTO_HOPOPTS: | ||
| 584 | if (fragment) { | ||
| 585 | if (logflags & XT_LOG_IPOPT) | ||
| 586 | sb_add(m, ")"); | ||
| 587 | return; | ||
| 588 | } | ||
| 589 | hdrlen = ipv6_optlen(hp); | ||
| 590 | break; | ||
| 591 | /* Max Length */ | ||
| 592 | case IPPROTO_AH: | ||
| 593 | if (logflags & XT_LOG_IPOPT) { | ||
| 594 | struct ip_auth_hdr _ahdr; | ||
| 595 | const struct ip_auth_hdr *ah; | ||
| 596 | |||
| 597 | /* Max length: 3 "AH " */ | ||
| 598 | sb_add(m, "AH "); | ||
| 599 | |||
| 600 | if (fragment) { | ||
| 601 | sb_add(m, ")"); | ||
| 602 | return; | ||
| 603 | } | ||
| 604 | |||
| 605 | ah = skb_header_pointer(skb, ptr, sizeof(_ahdr), | ||
| 606 | &_ahdr); | ||
| 607 | if (ah == NULL) { | ||
| 608 | /* | ||
| 609 | * Max length: 26 "INCOMPLETE [65535 | ||
| 610 | * bytes] )" | ||
| 611 | */ | ||
| 612 | sb_add(m, "INCOMPLETE [%u bytes] )", | ||
| 613 | skb->len - ptr); | ||
| 614 | return; | ||
| 615 | } | ||
| 616 | |||
| 617 | /* Length: 15 "SPI=0xF1234567 */ | ||
| 618 | sb_add(m, "SPI=0x%x ", ntohl(ah->spi)); | ||
| 619 | |||
| 620 | } | ||
| 621 | |||
| 622 | hdrlen = (hp->hdrlen+2)<<2; | ||
| 623 | break; | ||
| 624 | case IPPROTO_ESP: | ||
| 625 | if (logflags & XT_LOG_IPOPT) { | ||
| 626 | struct ip_esp_hdr _esph; | ||
| 627 | const struct ip_esp_hdr *eh; | ||
| 628 | |||
| 629 | /* Max length: 4 "ESP " */ | ||
| 630 | sb_add(m, "ESP "); | ||
| 631 | |||
| 632 | if (fragment) { | ||
| 633 | sb_add(m, ")"); | ||
| 634 | return; | ||
| 635 | } | ||
| 636 | |||
| 637 | /* | ||
| 638 | * Max length: 26 "INCOMPLETE [65535 bytes] )" | ||
| 639 | */ | ||
| 640 | eh = skb_header_pointer(skb, ptr, sizeof(_esph), | ||
| 641 | &_esph); | ||
| 642 | if (eh == NULL) { | ||
| 643 | sb_add(m, "INCOMPLETE [%u bytes] )", | ||
| 644 | skb->len - ptr); | ||
| 645 | return; | ||
| 646 | } | ||
| 647 | |||
| 648 | /* Length: 16 "SPI=0xF1234567 )" */ | ||
| 649 | sb_add(m, "SPI=0x%x )", ntohl(eh->spi)); | ||
| 650 | |||
| 651 | } | ||
| 652 | return; | ||
| 653 | default: | ||
| 654 | /* Max length: 20 "Unknown Ext Hdr 255" */ | ||
| 655 | sb_add(m, "Unknown Ext Hdr %u", currenthdr); | ||
| 656 | return; | ||
| 657 | } | ||
| 658 | if (logflags & XT_LOG_IPOPT) | ||
| 659 | sb_add(m, ") "); | ||
| 660 | |||
| 661 | currenthdr = hp->nexthdr; | ||
| 662 | ptr += hdrlen; | ||
| 663 | } | ||
| 664 | |||
| 665 | switch (currenthdr) { | ||
| 666 | case IPPROTO_TCP: | ||
| 667 | if (dump_tcp_header(m, skb, currenthdr, fragment, ptr, | ||
| 668 | logflags)) | ||
| 669 | return; | ||
| 670 | break; | ||
| 671 | case IPPROTO_UDP: | ||
| 672 | case IPPROTO_UDPLITE: | ||
| 673 | if (dump_udp_header(m, skb, currenthdr, fragment, ptr)) | ||
| 674 | return; | ||
| 675 | break; | ||
| 676 | case IPPROTO_ICMPV6: { | ||
| 677 | struct icmp6hdr _icmp6h; | ||
| 678 | const struct icmp6hdr *ic; | ||
| 679 | |||
| 680 | /* Max length: 13 "PROTO=ICMPv6 " */ | ||
| 681 | sb_add(m, "PROTO=ICMPv6 "); | ||
| 682 | |||
| 683 | if (fragment) | ||
| 684 | break; | ||
| 685 | |||
| 686 | /* Max length: 25 "INCOMPLETE [65535 bytes] " */ | ||
| 687 | ic = skb_header_pointer(skb, ptr, sizeof(_icmp6h), &_icmp6h); | ||
| 688 | if (ic == NULL) { | ||
| 689 | sb_add(m, "INCOMPLETE [%u bytes] ", skb->len - ptr); | ||
| 690 | return; | ||
| 691 | } | ||
| 692 | |||
| 693 | /* Max length: 18 "TYPE=255 CODE=255 " */ | ||
| 694 | sb_add(m, "TYPE=%u CODE=%u ", ic->icmp6_type, ic->icmp6_code); | ||
| 695 | |||
| 696 | switch (ic->icmp6_type) { | ||
| 697 | case ICMPV6_ECHO_REQUEST: | ||
| 698 | case ICMPV6_ECHO_REPLY: | ||
| 699 | /* Max length: 19 "ID=65535 SEQ=65535 " */ | ||
| 700 | sb_add(m, "ID=%u SEQ=%u ", | ||
| 701 | ntohs(ic->icmp6_identifier), | ||
| 702 | ntohs(ic->icmp6_sequence)); | ||
| 703 | break; | ||
| 704 | case ICMPV6_MGM_QUERY: | ||
| 705 | case ICMPV6_MGM_REPORT: | ||
| 706 | case ICMPV6_MGM_REDUCTION: | ||
| 707 | break; | ||
| 708 | |||
| 709 | case ICMPV6_PARAMPROB: | ||
| 710 | /* Max length: 17 "POINTER=ffffffff " */ | ||
| 711 | sb_add(m, "POINTER=%08x ", ntohl(ic->icmp6_pointer)); | ||
| 712 | /* Fall through */ | ||
| 713 | case ICMPV6_DEST_UNREACH: | ||
| 714 | case ICMPV6_PKT_TOOBIG: | ||
| 715 | case ICMPV6_TIME_EXCEED: | ||
| 716 | /* Max length: 3+maxlen */ | ||
| 717 | if (recurse) { | ||
| 718 | sb_add(m, "["); | ||
| 719 | dump_ipv6_packet(m, info, skb, | ||
| 720 | ptr + sizeof(_icmp6h), 0); | ||
| 721 | sb_add(m, "] "); | ||
| 722 | } | ||
| 723 | |||
| 724 | /* Max length: 10 "MTU=65535 " */ | ||
| 725 | if (ic->icmp6_type == ICMPV6_PKT_TOOBIG) | ||
| 726 | sb_add(m, "MTU=%u ", ntohl(ic->icmp6_mtu)); | ||
| 727 | } | ||
| 728 | break; | ||
| 729 | } | ||
| 730 | /* Max length: 10 "PROTO=255 " */ | ||
| 731 | default: | ||
| 732 | sb_add(m, "PROTO=%u ", currenthdr); | ||
| 733 | } | ||
| 734 | |||
| 735 | /* Max length: 15 "UID=4294967295 " */ | ||
| 736 | if ((logflags & XT_LOG_UID) && recurse) | ||
| 737 | dump_sk_uid_gid(m, skb->sk); | ||
| 738 | |||
| 739 | /* Max length: 16 "MARK=0xFFFFFFFF " */ | ||
| 740 | if (recurse && skb->mark) | ||
| 741 | sb_add(m, "MARK=0x%x ", skb->mark); | ||
| 742 | } | ||
| 743 | |||
| 744 | static void dump_ipv6_mac_header(struct sbuff *m, | ||
| 745 | const struct nf_loginfo *info, | ||
| 746 | const struct sk_buff *skb) | ||
| 747 | { | ||
| 748 | struct net_device *dev = skb->dev; | ||
| 749 | unsigned int logflags = 0; | ||
| 750 | |||
| 751 | if (info->type == NF_LOG_TYPE_LOG) | ||
| 752 | logflags = info->u.log.logflags; | ||
| 753 | |||
| 754 | if (!(logflags & XT_LOG_MACDECODE)) | ||
| 755 | goto fallback; | ||
| 756 | |||
| 757 | switch (dev->type) { | ||
| 758 | case ARPHRD_ETHER: | ||
| 759 | sb_add(m, "MACSRC=%pM MACDST=%pM MACPROTO=%04x ", | ||
| 760 | eth_hdr(skb)->h_source, eth_hdr(skb)->h_dest, | ||
| 761 | ntohs(eth_hdr(skb)->h_proto)); | ||
| 762 | return; | ||
| 763 | default: | ||
| 764 | break; | ||
| 765 | } | ||
| 766 | |||
| 767 | fallback: | ||
| 768 | sb_add(m, "MAC="); | ||
| 769 | if (dev->hard_header_len && | ||
| 770 | skb->mac_header != skb->network_header) { | ||
| 771 | const unsigned char *p = skb_mac_header(skb); | ||
| 772 | unsigned int len = dev->hard_header_len; | ||
| 773 | unsigned int i; | ||
| 774 | |||
| 775 | if (dev->type == ARPHRD_SIT) { | ||
| 776 | p -= ETH_HLEN; | ||
| 777 | |||
| 778 | if (p < skb->head) | ||
| 779 | p = NULL; | ||
| 780 | } | ||
| 781 | |||
| 782 | if (p != NULL) { | ||
| 783 | sb_add(m, "%02x", *p++); | ||
| 784 | for (i = 1; i < len; i++) | ||
| 785 | sb_add(m, ":%02x", *p++); | ||
| 786 | } | ||
| 787 | sb_add(m, " "); | ||
| 788 | |||
| 789 | if (dev->type == ARPHRD_SIT) { | ||
| 790 | const struct iphdr *iph = | ||
| 791 | (struct iphdr *)skb_mac_header(skb); | ||
| 792 | sb_add(m, "TUNNEL=%pI4->%pI4 ", &iph->saddr, | ||
| 793 | &iph->daddr); | ||
| 794 | } | ||
| 795 | } else | ||
| 796 | sb_add(m, " "); | ||
| 797 | } | ||
| 798 | |||
| 799 | static void | ||
| 800 | ip6t_log_packet(struct net *net, | ||
| 801 | u_int8_t pf, | ||
| 802 | unsigned int hooknum, | ||
| 803 | const struct sk_buff *skb, | ||
| 804 | const struct net_device *in, | ||
| 805 | const struct net_device *out, | ||
| 806 | const struct nf_loginfo *loginfo, | ||
| 807 | const char *prefix) | ||
| 808 | { | ||
| 809 | struct sbuff *m; | ||
| 810 | |||
| 811 | /* FIXME: Disabled from containers until syslog ns is supported */ | ||
| 812 | if (!net_eq(net, &init_net)) | ||
| 813 | return; | ||
| 814 | |||
| 815 | m = sb_open(); | ||
| 816 | |||
| 817 | if (!loginfo) | ||
| 818 | loginfo = &default_loginfo; | ||
| 819 | |||
| 820 | log_packet_common(m, pf, hooknum, skb, in, out, loginfo, prefix); | ||
| 821 | |||
| 822 | if (in != NULL) | ||
| 823 | dump_ipv6_mac_header(m, loginfo, skb); | ||
| 824 | |||
| 825 | dump_ipv6_packet(m, loginfo, skb, skb_network_offset(skb), 1); | ||
| 826 | |||
| 827 | sb_close(m); | ||
| 828 | } | ||
| 829 | #endif | ||
| 830 | 30 | ||
| 831 | static unsigned int | 31 | static unsigned int |
| 832 | log_tg(struct sk_buff *skb, const struct xt_action_param *par) | 32 | log_tg(struct sk_buff *skb, const struct xt_action_param *par) |
| @@ -839,17 +39,8 @@ log_tg(struct sk_buff *skb, const struct xt_action_param *par) | |||
| 839 | li.u.log.level = loginfo->level; | 39 | li.u.log.level = loginfo->level; |
| 840 | li.u.log.logflags = loginfo->logflags; | 40 | li.u.log.logflags = loginfo->logflags; |
| 841 | 41 | ||
| 842 | if (par->family == NFPROTO_IPV4) | 42 | nf_log_packet(net, par->family, par->hooknum, skb, par->in, par->out, |
| 843 | ipt_log_packet(net, NFPROTO_IPV4, par->hooknum, skb, par->in, | 43 | &li, "%s", loginfo->prefix); |
| 844 | par->out, &li, loginfo->prefix); | ||
| 845 | #if IS_ENABLED(CONFIG_IP6_NF_IPTABLES) | ||
| 846 | else if (par->family == NFPROTO_IPV6) | ||
| 847 | ip6t_log_packet(net, NFPROTO_IPV6, par->hooknum, skb, par->in, | ||
| 848 | par->out, &li, loginfo->prefix); | ||
| 849 | #endif | ||
| 850 | else | ||
| 851 | WARN_ON_ONCE(1); | ||
| 852 | |||
| 853 | return XT_CONTINUE; | 44 | return XT_CONTINUE; |
| 854 | } | 45 | } |
| 855 | 46 | ||
| @@ -870,7 +61,12 @@ static int log_tg_check(const struct xt_tgchk_param *par) | |||
| 870 | return -EINVAL; | 61 | return -EINVAL; |
| 871 | } | 62 | } |
| 872 | 63 | ||
| 873 | return 0; | 64 | return nf_logger_find_get(par->family, NF_LOG_TYPE_LOG); |
| 65 | } | ||
| 66 | |||
| 67 | static void log_tg_destroy(const struct xt_tgdtor_param *par) | ||
| 68 | { | ||
| 69 | nf_logger_put(par->family, NF_LOG_TYPE_LOG); | ||
| 874 | } | 70 | } |
| 875 | 71 | ||
| 876 | static struct xt_target log_tg_regs[] __read_mostly = { | 72 | static struct xt_target log_tg_regs[] __read_mostly = { |
| @@ -880,6 +76,7 @@ static struct xt_target log_tg_regs[] __read_mostly = { | |||
| 880 | .target = log_tg, | 76 | .target = log_tg, |
| 881 | .targetsize = sizeof(struct xt_log_info), | 77 | .targetsize = sizeof(struct xt_log_info), |
| 882 | .checkentry = log_tg_check, | 78 | .checkentry = log_tg_check, |
| 79 | .destroy = log_tg_destroy, | ||
| 883 | .me = THIS_MODULE, | 80 | .me = THIS_MODULE, |
| 884 | }, | 81 | }, |
| 885 | #if IS_ENABLED(CONFIG_IP6_NF_IPTABLES) | 82 | #if IS_ENABLED(CONFIG_IP6_NF_IPTABLES) |
| @@ -889,78 +86,19 @@ static struct xt_target log_tg_regs[] __read_mostly = { | |||
| 889 | .target = log_tg, | 86 | .target = log_tg, |
| 890 | .targetsize = sizeof(struct xt_log_info), | 87 | .targetsize = sizeof(struct xt_log_info), |
| 891 | .checkentry = log_tg_check, | 88 | .checkentry = log_tg_check, |
| 89 | .destroy = log_tg_destroy, | ||
| 892 | .me = THIS_MODULE, | 90 | .me = THIS_MODULE, |
| 893 | }, | 91 | }, |
| 894 | #endif | 92 | #endif |
| 895 | }; | 93 | }; |
| 896 | 94 | ||
| 897 | static struct nf_logger ipt_log_logger __read_mostly = { | ||
| 898 | .name = "ipt_LOG", | ||
| 899 | .logfn = &ipt_log_packet, | ||
| 900 | .me = THIS_MODULE, | ||
| 901 | }; | ||
| 902 | |||
| 903 | #if IS_ENABLED(CONFIG_IP6_NF_IPTABLES) | ||
| 904 | static struct nf_logger ip6t_log_logger __read_mostly = { | ||
| 905 | .name = "ip6t_LOG", | ||
| 906 | .logfn = &ip6t_log_packet, | ||
| 907 | .me = THIS_MODULE, | ||
| 908 | }; | ||
| 909 | #endif | ||
| 910 | |||
| 911 | static int __net_init log_net_init(struct net *net) | ||
| 912 | { | ||
| 913 | nf_log_set(net, NFPROTO_IPV4, &ipt_log_logger); | ||
| 914 | #if IS_ENABLED(CONFIG_IP6_NF_IPTABLES) | ||
| 915 | nf_log_set(net, NFPROTO_IPV6, &ip6t_log_logger); | ||
| 916 | #endif | ||
| 917 | return 0; | ||
| 918 | } | ||
| 919 | |||
| 920 | static void __net_exit log_net_exit(struct net *net) | ||
| 921 | { | ||
| 922 | nf_log_unset(net, &ipt_log_logger); | ||
| 923 | #if IS_ENABLED(CONFIG_IP6_NF_IPTABLES) | ||
| 924 | nf_log_unset(net, &ip6t_log_logger); | ||
| 925 | #endif | ||
| 926 | } | ||
| 927 | |||
| 928 | static struct pernet_operations log_net_ops = { | ||
| 929 | .init = log_net_init, | ||
| 930 | .exit = log_net_exit, | ||
| 931 | }; | ||
| 932 | |||
| 933 | static int __init log_tg_init(void) | 95 | static int __init log_tg_init(void) |
| 934 | { | 96 | { |
| 935 | int ret; | 97 | return xt_register_targets(log_tg_regs, ARRAY_SIZE(log_tg_regs)); |
| 936 | |||
| 937 | ret = register_pernet_subsys(&log_net_ops); | ||
| 938 | if (ret < 0) | ||
| 939 | goto err_pernet; | ||
| 940 | |||
| 941 | ret = xt_register_targets(log_tg_regs, ARRAY_SIZE(log_tg_regs)); | ||
| 942 | if (ret < 0) | ||
| 943 | goto err_target; | ||
| 944 | |||
| 945 | nf_log_register(NFPROTO_IPV4, &ipt_log_logger); | ||
| 946 | #if IS_ENABLED(CONFIG_IP6_NF_IPTABLES) | ||
| 947 | nf_log_register(NFPROTO_IPV6, &ip6t_log_logger); | ||
| 948 | #endif | ||
| 949 | return 0; | ||
| 950 | |||
| 951 | err_target: | ||
| 952 | unregister_pernet_subsys(&log_net_ops); | ||
| 953 | err_pernet: | ||
| 954 | return ret; | ||
| 955 | } | 98 | } |
| 956 | 99 | ||
| 957 | static void __exit log_tg_exit(void) | 100 | static void __exit log_tg_exit(void) |
| 958 | { | 101 | { |
| 959 | unregister_pernet_subsys(&log_net_ops); | ||
| 960 | nf_log_unregister(&ipt_log_logger); | ||
| 961 | #if IS_ENABLED(CONFIG_IP6_NF_IPTABLES) | ||
| 962 | nf_log_unregister(&ip6t_log_logger); | ||
| 963 | #endif | ||
| 964 | xt_unregister_targets(log_tg_regs, ARRAY_SIZE(log_tg_regs)); | 102 | xt_unregister_targets(log_tg_regs, ARRAY_SIZE(log_tg_regs)); |
| 965 | } | 103 | } |
| 966 | 104 | ||
diff --git a/net/netfilter/xt_bpf.c b/net/netfilter/xt_bpf.c index bbffdbdaf603..dffee9d47ec4 100644 --- a/net/netfilter/xt_bpf.c +++ b/net/netfilter/xt_bpf.c | |||
| @@ -28,7 +28,7 @@ static int bpf_mt_check(const struct xt_mtchk_param *par) | |||
| 28 | program.len = info->bpf_program_num_elem; | 28 | program.len = info->bpf_program_num_elem; |
| 29 | program.filter = info->bpf_program; | 29 | program.filter = info->bpf_program; |
| 30 | 30 | ||
| 31 | if (sk_unattached_filter_create(&info->filter, &program)) { | 31 | if (bpf_prog_create(&info->filter, &program)) { |
| 32 | pr_info("bpf: check failed: parse error\n"); | 32 | pr_info("bpf: check failed: parse error\n"); |
| 33 | return -EINVAL; | 33 | return -EINVAL; |
| 34 | } | 34 | } |
| @@ -40,13 +40,13 @@ static bool bpf_mt(const struct sk_buff *skb, struct xt_action_param *par) | |||
| 40 | { | 40 | { |
| 41 | const struct xt_bpf_info *info = par->matchinfo; | 41 | const struct xt_bpf_info *info = par->matchinfo; |
| 42 | 42 | ||
| 43 | return SK_RUN_FILTER(info->filter, skb); | 43 | return BPF_PROG_RUN(info->filter, skb); |
| 44 | } | 44 | } |
| 45 | 45 | ||
| 46 | static void bpf_mt_destroy(const struct xt_mtdtor_param *par) | 46 | static void bpf_mt_destroy(const struct xt_mtdtor_param *par) |
| 47 | { | 47 | { |
| 48 | const struct xt_bpf_info *info = par->matchinfo; | 48 | const struct xt_bpf_info *info = par->matchinfo; |
| 49 | sk_unattached_filter_destroy(info->filter); | 49 | bpf_prog_destroy(info->filter); |
| 50 | } | 50 | } |
| 51 | 51 | ||
| 52 | static struct xt_match bpf_mt_reg __read_mostly = { | 52 | static struct xt_match bpf_mt_reg __read_mostly = { |
diff --git a/net/netfilter/xt_hashlimit.c b/net/netfilter/xt_hashlimit.c index a3910fc2122b..47dc6836830a 100644 --- a/net/netfilter/xt_hashlimit.c +++ b/net/netfilter/xt_hashlimit.c | |||
| @@ -104,7 +104,7 @@ struct xt_hashlimit_htable { | |||
| 104 | spinlock_t lock; /* lock for list_head */ | 104 | spinlock_t lock; /* lock for list_head */ |
| 105 | u_int32_t rnd; /* random seed for hash */ | 105 | u_int32_t rnd; /* random seed for hash */ |
| 106 | unsigned int count; /* number entries in table */ | 106 | unsigned int count; /* number entries in table */ |
| 107 | struct timer_list timer; /* timer for gc */ | 107 | struct delayed_work gc_work; |
| 108 | 108 | ||
| 109 | /* seq_file stuff */ | 109 | /* seq_file stuff */ |
| 110 | struct proc_dir_entry *pde; | 110 | struct proc_dir_entry *pde; |
| @@ -213,7 +213,7 @@ dsthash_free(struct xt_hashlimit_htable *ht, struct dsthash_ent *ent) | |||
| 213 | call_rcu_bh(&ent->rcu, dsthash_free_rcu); | 213 | call_rcu_bh(&ent->rcu, dsthash_free_rcu); |
| 214 | ht->count--; | 214 | ht->count--; |
| 215 | } | 215 | } |
| 216 | static void htable_gc(unsigned long htlong); | 216 | static void htable_gc(struct work_struct *work); |
| 217 | 217 | ||
| 218 | static int htable_create(struct net *net, struct xt_hashlimit_mtinfo1 *minfo, | 218 | static int htable_create(struct net *net, struct xt_hashlimit_mtinfo1 *minfo, |
| 219 | u_int8_t family) | 219 | u_int8_t family) |
| @@ -273,9 +273,9 @@ static int htable_create(struct net *net, struct xt_hashlimit_mtinfo1 *minfo, | |||
| 273 | } | 273 | } |
| 274 | hinfo->net = net; | 274 | hinfo->net = net; |
| 275 | 275 | ||
| 276 | setup_timer(&hinfo->timer, htable_gc, (unsigned long)hinfo); | 276 | INIT_DEFERRABLE_WORK(&hinfo->gc_work, htable_gc); |
| 277 | hinfo->timer.expires = jiffies + msecs_to_jiffies(hinfo->cfg.gc_interval); | 277 | queue_delayed_work(system_power_efficient_wq, &hinfo->gc_work, |
| 278 | add_timer(&hinfo->timer); | 278 | msecs_to_jiffies(hinfo->cfg.gc_interval)); |
| 279 | 279 | ||
| 280 | hlist_add_head(&hinfo->node, &hashlimit_net->htables); | 280 | hlist_add_head(&hinfo->node, &hashlimit_net->htables); |
| 281 | 281 | ||
| @@ -300,29 +300,30 @@ static void htable_selective_cleanup(struct xt_hashlimit_htable *ht, | |||
| 300 | { | 300 | { |
| 301 | unsigned int i; | 301 | unsigned int i; |
| 302 | 302 | ||
| 303 | /* lock hash table and iterate over it */ | ||
| 304 | spin_lock_bh(&ht->lock); | ||
| 305 | for (i = 0; i < ht->cfg.size; i++) { | 303 | for (i = 0; i < ht->cfg.size; i++) { |
| 306 | struct dsthash_ent *dh; | 304 | struct dsthash_ent *dh; |
| 307 | struct hlist_node *n; | 305 | struct hlist_node *n; |
| 306 | |||
| 307 | spin_lock_bh(&ht->lock); | ||
| 308 | hlist_for_each_entry_safe(dh, n, &ht->hash[i], node) { | 308 | hlist_for_each_entry_safe(dh, n, &ht->hash[i], node) { |
| 309 | if ((*select)(ht, dh)) | 309 | if ((*select)(ht, dh)) |
| 310 | dsthash_free(ht, dh); | 310 | dsthash_free(ht, dh); |
| 311 | } | 311 | } |
| 312 | spin_unlock_bh(&ht->lock); | ||
| 313 | cond_resched(); | ||
| 312 | } | 314 | } |
| 313 | spin_unlock_bh(&ht->lock); | ||
| 314 | } | 315 | } |
| 315 | 316 | ||
| 316 | /* hash table garbage collector, run by timer */ | 317 | static void htable_gc(struct work_struct *work) |
| 317 | static void htable_gc(unsigned long htlong) | ||
| 318 | { | 318 | { |
| 319 | struct xt_hashlimit_htable *ht = (struct xt_hashlimit_htable *)htlong; | 319 | struct xt_hashlimit_htable *ht; |
| 320 | |||
| 321 | ht = container_of(work, struct xt_hashlimit_htable, gc_work.work); | ||
| 320 | 322 | ||
| 321 | htable_selective_cleanup(ht, select_gc); | 323 | htable_selective_cleanup(ht, select_gc); |
| 322 | 324 | ||
| 323 | /* re-add the timer accordingly */ | 325 | queue_delayed_work(system_power_efficient_wq, |
| 324 | ht->timer.expires = jiffies + msecs_to_jiffies(ht->cfg.gc_interval); | 326 | &ht->gc_work, msecs_to_jiffies(ht->cfg.gc_interval)); |
| 325 | add_timer(&ht->timer); | ||
| 326 | } | 327 | } |
| 327 | 328 | ||
| 328 | static void htable_remove_proc_entry(struct xt_hashlimit_htable *hinfo) | 329 | static void htable_remove_proc_entry(struct xt_hashlimit_htable *hinfo) |
| @@ -341,7 +342,7 @@ static void htable_remove_proc_entry(struct xt_hashlimit_htable *hinfo) | |||
| 341 | 342 | ||
| 342 | static void htable_destroy(struct xt_hashlimit_htable *hinfo) | 343 | static void htable_destroy(struct xt_hashlimit_htable *hinfo) |
| 343 | { | 344 | { |
| 344 | del_timer_sync(&hinfo->timer); | 345 | cancel_delayed_work_sync(&hinfo->gc_work); |
| 345 | htable_remove_proc_entry(hinfo); | 346 | htable_remove_proc_entry(hinfo); |
| 346 | htable_selective_cleanup(hinfo, select_all); | 347 | htable_selective_cleanup(hinfo, select_all); |
| 347 | kfree(hinfo->name); | 348 | kfree(hinfo->name); |
diff --git a/net/netlabel/netlabel_kapi.c b/net/netlabel/netlabel_kapi.c index 3045a964f39c..0b4692dd1c5e 100644 --- a/net/netlabel/netlabel_kapi.c +++ b/net/netlabel/netlabel_kapi.c | |||
| @@ -170,7 +170,6 @@ int netlbl_cfg_unlbl_map_add(const char *domain, | |||
| 170 | #endif /* IPv6 */ | 170 | #endif /* IPv6 */ |
| 171 | default: | 171 | default: |
| 172 | goto cfg_unlbl_map_add_failure; | 172 | goto cfg_unlbl_map_add_failure; |
| 173 | break; | ||
| 174 | } | 173 | } |
| 175 | 174 | ||
| 176 | entry->def.addrsel = addrmap; | 175 | entry->def.addrsel = addrmap; |
| @@ -405,8 +404,72 @@ out_entry: | |||
| 405 | * Security Attribute Functions | 404 | * Security Attribute Functions |
| 406 | */ | 405 | */ |
| 407 | 406 | ||
| 407 | #define _CM_F_NONE 0x00000000 | ||
| 408 | #define _CM_F_ALLOC 0x00000001 | ||
| 409 | #define _CM_F_WALK 0x00000002 | ||
| 410 | |||
| 411 | /** | ||
| 412 | * _netlbl_catmap_getnode - Get a individual node from a catmap | ||
| 413 | * @catmap: pointer to the category bitmap | ||
| 414 | * @offset: the requested offset | ||
| 415 | * @cm_flags: catmap flags, see _CM_F_* | ||
| 416 | * @gfp_flags: memory allocation flags | ||
| 417 | * | ||
| 418 | * Description: | ||
| 419 | * Iterate through the catmap looking for the node associated with @offset. | ||
| 420 | * If the _CM_F_ALLOC flag is set in @cm_flags and there is no associated node, | ||
| 421 | * one will be created and inserted into the catmap. If the _CM_F_WALK flag is | ||
| 422 | * set in @cm_flags and there is no associated node, the next highest node will | ||
| 423 | * be returned. Returns a pointer to the node on success, NULL on failure. | ||
| 424 | * | ||
| 425 | */ | ||
| 426 | static struct netlbl_lsm_catmap *_netlbl_catmap_getnode( | ||
| 427 | struct netlbl_lsm_catmap **catmap, | ||
| 428 | u32 offset, | ||
| 429 | unsigned int cm_flags, | ||
| 430 | gfp_t gfp_flags) | ||
| 431 | { | ||
| 432 | struct netlbl_lsm_catmap *iter = *catmap; | ||
| 433 | struct netlbl_lsm_catmap *prev = NULL; | ||
| 434 | |||
| 435 | if (iter == NULL) | ||
| 436 | goto catmap_getnode_alloc; | ||
| 437 | if (offset < iter->startbit) | ||
| 438 | goto catmap_getnode_walk; | ||
| 439 | while (iter && offset >= (iter->startbit + NETLBL_CATMAP_SIZE)) { | ||
| 440 | prev = iter; | ||
| 441 | iter = iter->next; | ||
| 442 | } | ||
| 443 | if (iter == NULL || offset < iter->startbit) | ||
| 444 | goto catmap_getnode_walk; | ||
| 445 | |||
| 446 | return iter; | ||
| 447 | |||
| 448 | catmap_getnode_walk: | ||
| 449 | if (cm_flags & _CM_F_WALK) | ||
| 450 | return iter; | ||
| 451 | catmap_getnode_alloc: | ||
| 452 | if (!(cm_flags & _CM_F_ALLOC)) | ||
| 453 | return NULL; | ||
| 454 | |||
| 455 | iter = netlbl_catmap_alloc(gfp_flags); | ||
| 456 | if (iter == NULL) | ||
| 457 | return NULL; | ||
| 458 | iter->startbit = offset & ~(NETLBL_CATMAP_SIZE - 1); | ||
| 459 | |||
| 460 | if (prev == NULL) { | ||
| 461 | iter->next = *catmap; | ||
| 462 | *catmap = iter; | ||
| 463 | } else { | ||
| 464 | iter->next = prev->next; | ||
| 465 | prev->next = iter; | ||
| 466 | } | ||
| 467 | |||
| 468 | return iter; | ||
| 469 | } | ||
| 470 | |||
| 408 | /** | 471 | /** |
| 409 | * netlbl_secattr_catmap_walk - Walk a LSM secattr catmap looking for a bit | 472 | * netlbl_catmap_walk - Walk a LSM secattr catmap looking for a bit |
| 410 | * @catmap: the category bitmap | 473 | * @catmap: the category bitmap |
| 411 | * @offset: the offset to start searching at, in bits | 474 | * @offset: the offset to start searching at, in bits |
| 412 | * | 475 | * |
| @@ -415,54 +478,51 @@ out_entry: | |||
| 415 | * returns the spot of the first set bit or -ENOENT if no bits are set. | 478 | * returns the spot of the first set bit or -ENOENT if no bits are set. |
| 416 | * | 479 | * |
| 417 | */ | 480 | */ |
| 418 | int netlbl_secattr_catmap_walk(struct netlbl_lsm_secattr_catmap *catmap, | 481 | int netlbl_catmap_walk(struct netlbl_lsm_catmap *catmap, u32 offset) |
| 419 | u32 offset) | ||
| 420 | { | 482 | { |
| 421 | struct netlbl_lsm_secattr_catmap *iter = catmap; | 483 | struct netlbl_lsm_catmap *iter = catmap; |
| 422 | u32 node_idx; | 484 | u32 idx; |
| 423 | u32 node_bit; | 485 | u32 bit; |
| 424 | NETLBL_CATMAP_MAPTYPE bitmap; | 486 | NETLBL_CATMAP_MAPTYPE bitmap; |
| 425 | 487 | ||
| 488 | iter = _netlbl_catmap_getnode(&catmap, offset, _CM_F_WALK, 0); | ||
| 489 | if (iter == NULL) | ||
| 490 | return -ENOENT; | ||
| 426 | if (offset > iter->startbit) { | 491 | if (offset > iter->startbit) { |
| 427 | while (offset >= (iter->startbit + NETLBL_CATMAP_SIZE)) { | 492 | offset -= iter->startbit; |
| 428 | iter = iter->next; | 493 | idx = offset / NETLBL_CATMAP_MAPSIZE; |
| 429 | if (iter == NULL) | 494 | bit = offset % NETLBL_CATMAP_MAPSIZE; |
| 430 | return -ENOENT; | ||
| 431 | } | ||
| 432 | node_idx = (offset - iter->startbit) / NETLBL_CATMAP_MAPSIZE; | ||
| 433 | node_bit = offset - iter->startbit - | ||
| 434 | (NETLBL_CATMAP_MAPSIZE * node_idx); | ||
| 435 | } else { | 495 | } else { |
| 436 | node_idx = 0; | 496 | idx = 0; |
| 437 | node_bit = 0; | 497 | bit = 0; |
| 438 | } | 498 | } |
| 439 | bitmap = iter->bitmap[node_idx] >> node_bit; | 499 | bitmap = iter->bitmap[idx] >> bit; |
| 440 | 500 | ||
| 441 | for (;;) { | 501 | for (;;) { |
| 442 | if (bitmap != 0) { | 502 | if (bitmap != 0) { |
| 443 | while ((bitmap & NETLBL_CATMAP_BIT) == 0) { | 503 | while ((bitmap & NETLBL_CATMAP_BIT) == 0) { |
| 444 | bitmap >>= 1; | 504 | bitmap >>= 1; |
| 445 | node_bit++; | 505 | bit++; |
| 446 | } | 506 | } |
| 447 | return iter->startbit + | 507 | return iter->startbit + |
| 448 | (NETLBL_CATMAP_MAPSIZE * node_idx) + node_bit; | 508 | (NETLBL_CATMAP_MAPSIZE * idx) + bit; |
| 449 | } | 509 | } |
| 450 | if (++node_idx >= NETLBL_CATMAP_MAPCNT) { | 510 | if (++idx >= NETLBL_CATMAP_MAPCNT) { |
| 451 | if (iter->next != NULL) { | 511 | if (iter->next != NULL) { |
| 452 | iter = iter->next; | 512 | iter = iter->next; |
| 453 | node_idx = 0; | 513 | idx = 0; |
| 454 | } else | 514 | } else |
| 455 | return -ENOENT; | 515 | return -ENOENT; |
| 456 | } | 516 | } |
| 457 | bitmap = iter->bitmap[node_idx]; | 517 | bitmap = iter->bitmap[idx]; |
| 458 | node_bit = 0; | 518 | bit = 0; |
| 459 | } | 519 | } |
| 460 | 520 | ||
| 461 | return -ENOENT; | 521 | return -ENOENT; |
| 462 | } | 522 | } |
| 463 | 523 | ||
| 464 | /** | 524 | /** |
| 465 | * netlbl_secattr_catmap_walk_rng - Find the end of a string of set bits | 525 | * netlbl_catmap_walkrng - Find the end of a string of set bits |
| 466 | * @catmap: the category bitmap | 526 | * @catmap: the category bitmap |
| 467 | * @offset: the offset to start searching at, in bits | 527 | * @offset: the offset to start searching at, in bits |
| 468 | * | 528 | * |
| @@ -472,57 +532,105 @@ int netlbl_secattr_catmap_walk(struct netlbl_lsm_secattr_catmap *catmap, | |||
| 472 | * the end of the bitmap. | 532 | * the end of the bitmap. |
| 473 | * | 533 | * |
| 474 | */ | 534 | */ |
| 475 | int netlbl_secattr_catmap_walk_rng(struct netlbl_lsm_secattr_catmap *catmap, | 535 | int netlbl_catmap_walkrng(struct netlbl_lsm_catmap *catmap, u32 offset) |
| 476 | u32 offset) | ||
| 477 | { | 536 | { |
| 478 | struct netlbl_lsm_secattr_catmap *iter = catmap; | 537 | struct netlbl_lsm_catmap *iter; |
| 479 | u32 node_idx; | 538 | struct netlbl_lsm_catmap *prev = NULL; |
| 480 | u32 node_bit; | 539 | u32 idx; |
| 540 | u32 bit; | ||
| 481 | NETLBL_CATMAP_MAPTYPE bitmask; | 541 | NETLBL_CATMAP_MAPTYPE bitmask; |
| 482 | NETLBL_CATMAP_MAPTYPE bitmap; | 542 | NETLBL_CATMAP_MAPTYPE bitmap; |
| 483 | 543 | ||
| 544 | iter = _netlbl_catmap_getnode(&catmap, offset, _CM_F_WALK, 0); | ||
| 545 | if (iter == NULL) | ||
| 546 | return -ENOENT; | ||
| 484 | if (offset > iter->startbit) { | 547 | if (offset > iter->startbit) { |
| 485 | while (offset >= (iter->startbit + NETLBL_CATMAP_SIZE)) { | 548 | offset -= iter->startbit; |
| 486 | iter = iter->next; | 549 | idx = offset / NETLBL_CATMAP_MAPSIZE; |
| 487 | if (iter == NULL) | 550 | bit = offset % NETLBL_CATMAP_MAPSIZE; |
| 488 | return -ENOENT; | ||
| 489 | } | ||
| 490 | node_idx = (offset - iter->startbit) / NETLBL_CATMAP_MAPSIZE; | ||
| 491 | node_bit = offset - iter->startbit - | ||
| 492 | (NETLBL_CATMAP_MAPSIZE * node_idx); | ||
| 493 | } else { | 551 | } else { |
| 494 | node_idx = 0; | 552 | idx = 0; |
| 495 | node_bit = 0; | 553 | bit = 0; |
| 496 | } | 554 | } |
| 497 | bitmask = NETLBL_CATMAP_BIT << node_bit; | 555 | bitmask = NETLBL_CATMAP_BIT << bit; |
| 498 | 556 | ||
| 499 | for (;;) { | 557 | for (;;) { |
| 500 | bitmap = iter->bitmap[node_idx]; | 558 | bitmap = iter->bitmap[idx]; |
| 501 | while (bitmask != 0 && (bitmap & bitmask) != 0) { | 559 | while (bitmask != 0 && (bitmap & bitmask) != 0) { |
| 502 | bitmask <<= 1; | 560 | bitmask <<= 1; |
| 503 | node_bit++; | 561 | bit++; |
| 504 | } | 562 | } |
| 505 | 563 | ||
| 506 | if (bitmask != 0) | 564 | if (prev && idx == 0 && bit == 0) |
| 565 | return prev->startbit + NETLBL_CATMAP_SIZE - 1; | ||
| 566 | else if (bitmask != 0) | ||
| 507 | return iter->startbit + | 567 | return iter->startbit + |
| 508 | (NETLBL_CATMAP_MAPSIZE * node_idx) + | 568 | (NETLBL_CATMAP_MAPSIZE * idx) + bit - 1; |
| 509 | node_bit - 1; | 569 | else if (++idx >= NETLBL_CATMAP_MAPCNT) { |
| 510 | else if (++node_idx >= NETLBL_CATMAP_MAPCNT) { | ||
| 511 | if (iter->next == NULL) | 570 | if (iter->next == NULL) |
| 512 | return iter->startbit + NETLBL_CATMAP_SIZE - 1; | 571 | return iter->startbit + NETLBL_CATMAP_SIZE - 1; |
| 572 | prev = iter; | ||
| 513 | iter = iter->next; | 573 | iter = iter->next; |
| 514 | node_idx = 0; | 574 | idx = 0; |
| 515 | } | 575 | } |
| 516 | bitmask = NETLBL_CATMAP_BIT; | 576 | bitmask = NETLBL_CATMAP_BIT; |
| 517 | node_bit = 0; | 577 | bit = 0; |
| 518 | } | 578 | } |
| 519 | 579 | ||
| 520 | return -ENOENT; | 580 | return -ENOENT; |
| 521 | } | 581 | } |
| 522 | 582 | ||
| 523 | /** | 583 | /** |
| 524 | * netlbl_secattr_catmap_setbit - Set a bit in a LSM secattr catmap | 584 | * netlbl_catmap_getlong - Export an unsigned long bitmap |
| 525 | * @catmap: the category bitmap | 585 | * @catmap: pointer to the category bitmap |
| 586 | * @offset: pointer to the requested offset | ||
| 587 | * @bitmap: the exported bitmap | ||
| 588 | * | ||
| 589 | * Description: | ||
| 590 | * Export a bitmap with an offset greater than or equal to @offset and return | ||
| 591 | * it in @bitmap. The @offset must be aligned to an unsigned long and will be | ||
| 592 | * updated on return if different from what was requested; if the catmap is | ||
| 593 | * empty at the requested offset and beyond, the @offset is set to (u32)-1. | ||
| 594 | * Returns zero on sucess, negative values on failure. | ||
| 595 | * | ||
| 596 | */ | ||
| 597 | int netlbl_catmap_getlong(struct netlbl_lsm_catmap *catmap, | ||
| 598 | u32 *offset, | ||
| 599 | unsigned long *bitmap) | ||
| 600 | { | ||
| 601 | struct netlbl_lsm_catmap *iter; | ||
| 602 | u32 off = *offset; | ||
| 603 | u32 idx; | ||
| 604 | |||
| 605 | /* only allow aligned offsets */ | ||
| 606 | if ((off & (BITS_PER_LONG - 1)) != 0) | ||
| 607 | return -EINVAL; | ||
| 608 | |||
| 609 | if (off < catmap->startbit) { | ||
| 610 | off = catmap->startbit; | ||
| 611 | *offset = off; | ||
| 612 | } | ||
| 613 | iter = _netlbl_catmap_getnode(&catmap, off, _CM_F_NONE, 0); | ||
| 614 | if (iter == NULL) { | ||
| 615 | *offset = (u32)-1; | ||
| 616 | return 0; | ||
| 617 | } | ||
| 618 | |||
| 619 | if (off < iter->startbit) { | ||
| 620 | off = iter->startbit; | ||
| 621 | *offset = off; | ||
| 622 | } else | ||
| 623 | off -= iter->startbit; | ||
| 624 | |||
| 625 | idx = off / NETLBL_CATMAP_MAPSIZE; | ||
| 626 | *bitmap = iter->bitmap[idx] >> (off % NETLBL_CATMAP_SIZE); | ||
| 627 | |||
| 628 | return 0; | ||
| 629 | } | ||
| 630 | |||
| 631 | /** | ||
| 632 | * netlbl_catmap_setbit - Set a bit in a LSM secattr catmap | ||
| 633 | * @catmap: pointer to the category bitmap | ||
| 526 | * @bit: the bit to set | 634 | * @bit: the bit to set |
| 527 | * @flags: memory allocation flags | 635 | * @flags: memory allocation flags |
| 528 | * | 636 | * |
| @@ -531,36 +639,27 @@ int netlbl_secattr_catmap_walk_rng(struct netlbl_lsm_secattr_catmap *catmap, | |||
| 531 | * negative values on failure. | 639 | * negative values on failure. |
| 532 | * | 640 | * |
| 533 | */ | 641 | */ |
| 534 | int netlbl_secattr_catmap_setbit(struct netlbl_lsm_secattr_catmap *catmap, | 642 | int netlbl_catmap_setbit(struct netlbl_lsm_catmap **catmap, |
| 535 | u32 bit, | 643 | u32 bit, |
| 536 | gfp_t flags) | 644 | gfp_t flags) |
| 537 | { | 645 | { |
| 538 | struct netlbl_lsm_secattr_catmap *iter = catmap; | 646 | struct netlbl_lsm_catmap *iter; |
| 539 | u32 node_bit; | 647 | u32 idx; |
| 540 | u32 node_idx; | ||
| 541 | 648 | ||
| 542 | while (iter->next != NULL && | 649 | iter = _netlbl_catmap_getnode(catmap, bit, _CM_F_ALLOC, flags); |
| 543 | bit >= (iter->startbit + NETLBL_CATMAP_SIZE)) | 650 | if (iter == NULL) |
| 544 | iter = iter->next; | 651 | return -ENOMEM; |
| 545 | if (bit >= (iter->startbit + NETLBL_CATMAP_SIZE)) { | ||
| 546 | iter->next = netlbl_secattr_catmap_alloc(flags); | ||
| 547 | if (iter->next == NULL) | ||
| 548 | return -ENOMEM; | ||
| 549 | iter = iter->next; | ||
| 550 | iter->startbit = bit & ~(NETLBL_CATMAP_SIZE - 1); | ||
| 551 | } | ||
| 552 | 652 | ||
| 553 | /* gcc always rounds to zero when doing integer division */ | 653 | bit -= iter->startbit; |
| 554 | node_idx = (bit - iter->startbit) / NETLBL_CATMAP_MAPSIZE; | 654 | idx = bit / NETLBL_CATMAP_MAPSIZE; |
| 555 | node_bit = bit - iter->startbit - (NETLBL_CATMAP_MAPSIZE * node_idx); | 655 | iter->bitmap[idx] |= NETLBL_CATMAP_BIT << (bit % NETLBL_CATMAP_MAPSIZE); |
| 556 | iter->bitmap[node_idx] |= NETLBL_CATMAP_BIT << node_bit; | ||
| 557 | 656 | ||
| 558 | return 0; | 657 | return 0; |
| 559 | } | 658 | } |
| 560 | 659 | ||
| 561 | /** | 660 | /** |
| 562 | * netlbl_secattr_catmap_setrng - Set a range of bits in a LSM secattr catmap | 661 | * netlbl_catmap_setrng - Set a range of bits in a LSM secattr catmap |
| 563 | * @catmap: the category bitmap | 662 | * @catmap: pointer to the category bitmap |
| 564 | * @start: the starting bit | 663 | * @start: the starting bit |
| 565 | * @end: the last bit in the string | 664 | * @end: the last bit in the string |
| 566 | * @flags: memory allocation flags | 665 | * @flags: memory allocation flags |
| @@ -570,36 +669,63 @@ int netlbl_secattr_catmap_setbit(struct netlbl_lsm_secattr_catmap *catmap, | |||
| 570 | * on success, negative values on failure. | 669 | * on success, negative values on failure. |
| 571 | * | 670 | * |
| 572 | */ | 671 | */ |
| 573 | int netlbl_secattr_catmap_setrng(struct netlbl_lsm_secattr_catmap *catmap, | 672 | int netlbl_catmap_setrng(struct netlbl_lsm_catmap **catmap, |
| 574 | u32 start, | 673 | u32 start, |
| 575 | u32 end, | 674 | u32 end, |
| 576 | gfp_t flags) | 675 | gfp_t flags) |
| 577 | { | 676 | { |
| 578 | int ret_val = 0; | 677 | int rc = 0; |
| 579 | struct netlbl_lsm_secattr_catmap *iter = catmap; | 678 | u32 spot = start; |
| 580 | u32 iter_max_spot; | 679 | |
| 581 | u32 spot; | 680 | while (rc == 0 && spot <= end) { |
| 582 | 681 | if (((spot & (BITS_PER_LONG - 1)) != 0) && | |
| 583 | /* XXX - This could probably be made a bit faster by combining writes | 682 | ((end - spot) > BITS_PER_LONG)) { |
| 584 | * to the catmap instead of setting a single bit each time, but for | 683 | rc = netlbl_catmap_setlong(catmap, |
| 585 | * right now skipping to the start of the range in the catmap should | 684 | spot, |
| 586 | * be a nice improvement over calling the individual setbit function | 685 | (unsigned long)-1, |
| 587 | * repeatedly from a loop. */ | 686 | flags); |
| 588 | 687 | spot += BITS_PER_LONG; | |
| 589 | while (iter->next != NULL && | 688 | } else |
| 590 | start >= (iter->startbit + NETLBL_CATMAP_SIZE)) | 689 | rc = netlbl_catmap_setbit(catmap, spot++, flags); |
| 591 | iter = iter->next; | ||
| 592 | iter_max_spot = iter->startbit + NETLBL_CATMAP_SIZE; | ||
| 593 | |||
| 594 | for (spot = start; spot <= end && ret_val == 0; spot++) { | ||
| 595 | if (spot >= iter_max_spot && iter->next != NULL) { | ||
| 596 | iter = iter->next; | ||
| 597 | iter_max_spot = iter->startbit + NETLBL_CATMAP_SIZE; | ||
| 598 | } | ||
| 599 | ret_val = netlbl_secattr_catmap_setbit(iter, spot, flags); | ||
| 600 | } | 690 | } |
| 601 | 691 | ||
| 602 | return ret_val; | 692 | return rc; |
| 693 | } | ||
| 694 | |||
| 695 | /** | ||
| 696 | * netlbl_catmap_setlong - Import an unsigned long bitmap | ||
| 697 | * @catmap: pointer to the category bitmap | ||
| 698 | * @offset: offset to the start of the imported bitmap | ||
| 699 | * @bitmap: the bitmap to import | ||
| 700 | * @flags: memory allocation flags | ||
| 701 | * | ||
| 702 | * Description: | ||
| 703 | * Import the bitmap specified in @bitmap into @catmap, using the offset | ||
| 704 | * in @offset. The offset must be aligned to an unsigned long. Returns zero | ||
| 705 | * on success, negative values on failure. | ||
| 706 | * | ||
| 707 | */ | ||
| 708 | int netlbl_catmap_setlong(struct netlbl_lsm_catmap **catmap, | ||
| 709 | u32 offset, | ||
| 710 | unsigned long bitmap, | ||
| 711 | gfp_t flags) | ||
| 712 | { | ||
| 713 | struct netlbl_lsm_catmap *iter; | ||
| 714 | u32 idx; | ||
| 715 | |||
| 716 | /* only allow aligned offsets */ | ||
| 717 | if ((offset & (BITS_PER_LONG - 1)) != 0) | ||
| 718 | return -EINVAL; | ||
| 719 | |||
| 720 | iter = _netlbl_catmap_getnode(catmap, offset, _CM_F_ALLOC, flags); | ||
| 721 | if (iter == NULL) | ||
| 722 | return -ENOMEM; | ||
| 723 | |||
| 724 | offset -= iter->startbit; | ||
| 725 | idx = offset / NETLBL_CATMAP_MAPSIZE; | ||
| 726 | iter->bitmap[idx] |= bitmap << (offset % NETLBL_CATMAP_MAPSIZE); | ||
| 727 | |||
| 728 | return 0; | ||
| 603 | } | 729 | } |
| 604 | 730 | ||
| 605 | /* | 731 | /* |
diff --git a/net/netlink/af_netlink.c b/net/netlink/af_netlink.c index e6fac7e3db52..c416725d28c4 100644 --- a/net/netlink/af_netlink.c +++ b/net/netlink/af_netlink.c | |||
| @@ -58,7 +58,9 @@ | |||
| 58 | #include <linux/mutex.h> | 58 | #include <linux/mutex.h> |
| 59 | #include <linux/vmalloc.h> | 59 | #include <linux/vmalloc.h> |
| 60 | #include <linux/if_arp.h> | 60 | #include <linux/if_arp.h> |
| 61 | #include <linux/rhashtable.h> | ||
| 61 | #include <asm/cacheflush.h> | 62 | #include <asm/cacheflush.h> |
| 63 | #include <linux/hash.h> | ||
| 62 | 64 | ||
| 63 | #include <net/net_namespace.h> | 65 | #include <net/net_namespace.h> |
| 64 | #include <net/sock.h> | 66 | #include <net/sock.h> |
| @@ -100,6 +102,19 @@ static atomic_t nl_table_users = ATOMIC_INIT(0); | |||
| 100 | 102 | ||
| 101 | #define nl_deref_protected(X) rcu_dereference_protected(X, lockdep_is_held(&nl_table_lock)); | 103 | #define nl_deref_protected(X) rcu_dereference_protected(X, lockdep_is_held(&nl_table_lock)); |
| 102 | 104 | ||
| 105 | /* Protects netlink socket hash table mutations */ | ||
| 106 | DEFINE_MUTEX(nl_sk_hash_lock); | ||
| 107 | EXPORT_SYMBOL_GPL(nl_sk_hash_lock); | ||
| 108 | |||
| 109 | static int lockdep_nl_sk_hash_is_held(void) | ||
| 110 | { | ||
| 111 | #ifdef CONFIG_LOCKDEP | ||
| 112 | return (debug_locks) ? lockdep_is_held(&nl_sk_hash_lock) : 1; | ||
| 113 | #else | ||
| 114 | return 1; | ||
| 115 | #endif | ||
| 116 | } | ||
| 117 | |||
| 103 | static ATOMIC_NOTIFIER_HEAD(netlink_chain); | 118 | static ATOMIC_NOTIFIER_HEAD(netlink_chain); |
| 104 | 119 | ||
| 105 | static DEFINE_SPINLOCK(netlink_tap_lock); | 120 | static DEFINE_SPINLOCK(netlink_tap_lock); |
| @@ -110,11 +125,6 @@ static inline u32 netlink_group_mask(u32 group) | |||
| 110 | return group ? 1 << (group - 1) : 0; | 125 | return group ? 1 << (group - 1) : 0; |
| 111 | } | 126 | } |
| 112 | 127 | ||
| 113 | static inline struct hlist_head *nl_portid_hashfn(struct nl_portid_hash *hash, u32 portid) | ||
| 114 | { | ||
| 115 | return &hash->table[jhash_1word(portid, hash->rnd) & hash->mask]; | ||
| 116 | } | ||
| 117 | |||
| 118 | int netlink_add_tap(struct netlink_tap *nt) | 128 | int netlink_add_tap(struct netlink_tap *nt) |
| 119 | { | 129 | { |
| 120 | if (unlikely(nt->dev->type != ARPHRD_NETLINK)) | 130 | if (unlikely(nt->dev->type != ARPHRD_NETLINK)) |
| @@ -170,7 +180,6 @@ EXPORT_SYMBOL_GPL(netlink_remove_tap); | |||
| 170 | static bool netlink_filter_tap(const struct sk_buff *skb) | 180 | static bool netlink_filter_tap(const struct sk_buff *skb) |
| 171 | { | 181 | { |
| 172 | struct sock *sk = skb->sk; | 182 | struct sock *sk = skb->sk; |
| 173 | bool pass = false; | ||
| 174 | 183 | ||
| 175 | /* We take the more conservative approach and | 184 | /* We take the more conservative approach and |
| 176 | * whitelist socket protocols that may pass. | 185 | * whitelist socket protocols that may pass. |
| @@ -184,11 +193,10 @@ static bool netlink_filter_tap(const struct sk_buff *skb) | |||
| 184 | case NETLINK_FIB_LOOKUP: | 193 | case NETLINK_FIB_LOOKUP: |
| 185 | case NETLINK_NETFILTER: | 194 | case NETLINK_NETFILTER: |
| 186 | case NETLINK_GENERIC: | 195 | case NETLINK_GENERIC: |
| 187 | pass = true; | 196 | return true; |
| 188 | break; | ||
| 189 | } | 197 | } |
| 190 | 198 | ||
| 191 | return pass; | 199 | return false; |
| 192 | } | 200 | } |
| 193 | 201 | ||
| 194 | static int __netlink_deliver_tap_skb(struct sk_buff *skb, | 202 | static int __netlink_deliver_tap_skb(struct sk_buff *skb, |
| @@ -205,7 +213,7 @@ static int __netlink_deliver_tap_skb(struct sk_buff *skb, | |||
| 205 | nskb->protocol = htons((u16) sk->sk_protocol); | 213 | nskb->protocol = htons((u16) sk->sk_protocol); |
| 206 | nskb->pkt_type = netlink_is_kernel(sk) ? | 214 | nskb->pkt_type = netlink_is_kernel(sk) ? |
| 207 | PACKET_KERNEL : PACKET_USER; | 215 | PACKET_KERNEL : PACKET_USER; |
| 208 | 216 | skb_reset_network_header(nskb); | |
| 209 | ret = dev_queue_xmit(nskb); | 217 | ret = dev_queue_xmit(nskb); |
| 210 | if (unlikely(ret > 0)) | 218 | if (unlikely(ret > 0)) |
| 211 | ret = net_xmit_errno(ret); | 219 | ret = net_xmit_errno(ret); |
| @@ -376,7 +384,7 @@ static int netlink_set_ring(struct sock *sk, struct nl_mmap_req *req, | |||
| 376 | 384 | ||
| 377 | if ((int)req->nm_block_size <= 0) | 385 | if ((int)req->nm_block_size <= 0) |
| 378 | return -EINVAL; | 386 | return -EINVAL; |
| 379 | if (!IS_ALIGNED(req->nm_block_size, PAGE_SIZE)) | 387 | if (!PAGE_ALIGNED(req->nm_block_size)) |
| 380 | return -EINVAL; | 388 | return -EINVAL; |
| 381 | if (req->nm_frame_size < NL_MMAP_HDRLEN) | 389 | if (req->nm_frame_size < NL_MMAP_HDRLEN) |
| 382 | return -EINVAL; | 390 | return -EINVAL; |
| @@ -985,105 +993,48 @@ netlink_unlock_table(void) | |||
| 985 | wake_up(&nl_table_wait); | 993 | wake_up(&nl_table_wait); |
| 986 | } | 994 | } |
| 987 | 995 | ||
| 988 | static bool netlink_compare(struct net *net, struct sock *sk) | 996 | struct netlink_compare_arg |
| 989 | { | 997 | { |
| 990 | return net_eq(sock_net(sk), net); | 998 | struct net *net; |
| 991 | } | 999 | u32 portid; |
| 992 | 1000 | }; | |
| 993 | static struct sock *netlink_lookup(struct net *net, int protocol, u32 portid) | ||
| 994 | { | ||
| 995 | struct netlink_table *table = &nl_table[protocol]; | ||
| 996 | struct nl_portid_hash *hash = &table->hash; | ||
| 997 | struct hlist_head *head; | ||
| 998 | struct sock *sk; | ||
| 999 | |||
| 1000 | read_lock(&nl_table_lock); | ||
| 1001 | head = nl_portid_hashfn(hash, portid); | ||
| 1002 | sk_for_each(sk, head) { | ||
| 1003 | if (table->compare(net, sk) && | ||
| 1004 | (nlk_sk(sk)->portid == portid)) { | ||
| 1005 | sock_hold(sk); | ||
| 1006 | goto found; | ||
| 1007 | } | ||
| 1008 | } | ||
| 1009 | sk = NULL; | ||
| 1010 | found: | ||
| 1011 | read_unlock(&nl_table_lock); | ||
| 1012 | return sk; | ||
| 1013 | } | ||
| 1014 | 1001 | ||
| 1015 | static struct hlist_head *nl_portid_hash_zalloc(size_t size) | 1002 | static bool netlink_compare(void *ptr, void *arg) |
| 1016 | { | 1003 | { |
| 1017 | if (size <= PAGE_SIZE) | 1004 | struct netlink_compare_arg *x = arg; |
| 1018 | return kzalloc(size, GFP_ATOMIC); | 1005 | struct sock *sk = ptr; |
| 1019 | else | ||
| 1020 | return (struct hlist_head *) | ||
| 1021 | __get_free_pages(GFP_ATOMIC | __GFP_ZERO, | ||
| 1022 | get_order(size)); | ||
| 1023 | } | ||
| 1024 | 1006 | ||
| 1025 | static void nl_portid_hash_free(struct hlist_head *table, size_t size) | 1007 | return nlk_sk(sk)->portid == x->portid && |
| 1026 | { | 1008 | net_eq(sock_net(sk), x->net); |
| 1027 | if (size <= PAGE_SIZE) | ||
| 1028 | kfree(table); | ||
| 1029 | else | ||
| 1030 | free_pages((unsigned long)table, get_order(size)); | ||
| 1031 | } | 1009 | } |
| 1032 | 1010 | ||
| 1033 | static int nl_portid_hash_rehash(struct nl_portid_hash *hash, int grow) | 1011 | static struct sock *__netlink_lookup(struct netlink_table *table, u32 portid, |
| 1012 | struct net *net) | ||
| 1034 | { | 1013 | { |
| 1035 | unsigned int omask, mask, shift; | 1014 | struct netlink_compare_arg arg = { |
| 1036 | size_t osize, size; | 1015 | .net = net, |
| 1037 | struct hlist_head *otable, *table; | 1016 | .portid = portid, |
| 1038 | int i; | 1017 | }; |
| 1039 | 1018 | u32 hash; | |
| 1040 | omask = mask = hash->mask; | ||
| 1041 | osize = size = (mask + 1) * sizeof(*table); | ||
| 1042 | shift = hash->shift; | ||
| 1043 | |||
| 1044 | if (grow) { | ||
| 1045 | if (++shift > hash->max_shift) | ||
| 1046 | return 0; | ||
| 1047 | mask = mask * 2 + 1; | ||
| 1048 | size *= 2; | ||
| 1049 | } | ||
| 1050 | |||
| 1051 | table = nl_portid_hash_zalloc(size); | ||
| 1052 | if (!table) | ||
| 1053 | return 0; | ||
| 1054 | |||
| 1055 | otable = hash->table; | ||
| 1056 | hash->table = table; | ||
| 1057 | hash->mask = mask; | ||
| 1058 | hash->shift = shift; | ||
| 1059 | get_random_bytes(&hash->rnd, sizeof(hash->rnd)); | ||
| 1060 | 1019 | ||
| 1061 | for (i = 0; i <= omask; i++) { | 1020 | hash = rhashtable_hashfn(&table->hash, &portid, sizeof(portid)); |
| 1062 | struct sock *sk; | ||
| 1063 | struct hlist_node *tmp; | ||
| 1064 | |||
| 1065 | sk_for_each_safe(sk, tmp, &otable[i]) | ||
| 1066 | __sk_add_node(sk, nl_portid_hashfn(hash, nlk_sk(sk)->portid)); | ||
| 1067 | } | ||
| 1068 | 1021 | ||
| 1069 | nl_portid_hash_free(otable, osize); | 1022 | return rhashtable_lookup_compare(&table->hash, hash, |
| 1070 | hash->rehash_time = jiffies + 10 * 60 * HZ; | 1023 | &netlink_compare, &arg); |
| 1071 | return 1; | ||
| 1072 | } | 1024 | } |
| 1073 | 1025 | ||
| 1074 | static inline int nl_portid_hash_dilute(struct nl_portid_hash *hash, int len) | 1026 | static struct sock *netlink_lookup(struct net *net, int protocol, u32 portid) |
| 1075 | { | 1027 | { |
| 1076 | int avg = hash->entries >> hash->shift; | 1028 | struct netlink_table *table = &nl_table[protocol]; |
| 1077 | 1029 | struct sock *sk; | |
| 1078 | if (unlikely(avg > 1) && nl_portid_hash_rehash(hash, 1)) | ||
| 1079 | return 1; | ||
| 1080 | 1030 | ||
| 1081 | if (unlikely(len > avg) && time_after(jiffies, hash->rehash_time)) { | 1031 | rcu_read_lock(); |
| 1082 | nl_portid_hash_rehash(hash, 0); | 1032 | sk = __netlink_lookup(table, portid, net); |
| 1083 | return 1; | 1033 | if (sk) |
| 1084 | } | 1034 | sock_hold(sk); |
| 1035 | rcu_read_unlock(); | ||
| 1085 | 1036 | ||
| 1086 | return 0; | 1037 | return sk; |
| 1087 | } | 1038 | } |
| 1088 | 1039 | ||
| 1089 | static const struct proto_ops netlink_ops; | 1040 | static const struct proto_ops netlink_ops; |
| @@ -1115,22 +1066,10 @@ netlink_update_listeners(struct sock *sk) | |||
| 1115 | static int netlink_insert(struct sock *sk, struct net *net, u32 portid) | 1066 | static int netlink_insert(struct sock *sk, struct net *net, u32 portid) |
| 1116 | { | 1067 | { |
| 1117 | struct netlink_table *table = &nl_table[sk->sk_protocol]; | 1068 | struct netlink_table *table = &nl_table[sk->sk_protocol]; |
| 1118 | struct nl_portid_hash *hash = &table->hash; | ||
| 1119 | struct hlist_head *head; | ||
| 1120 | int err = -EADDRINUSE; | 1069 | int err = -EADDRINUSE; |
| 1121 | struct sock *osk; | ||
| 1122 | int len; | ||
| 1123 | 1070 | ||
| 1124 | netlink_table_grab(); | 1071 | mutex_lock(&nl_sk_hash_lock); |
| 1125 | head = nl_portid_hashfn(hash, portid); | 1072 | if (__netlink_lookup(table, portid, net)) |
| 1126 | len = 0; | ||
| 1127 | sk_for_each(osk, head) { | ||
| 1128 | if (table->compare(net, osk) && | ||
| 1129 | (nlk_sk(osk)->portid == portid)) | ||
| 1130 | break; | ||
| 1131 | len++; | ||
| 1132 | } | ||
| 1133 | if (osk) | ||
| 1134 | goto err; | 1073 | goto err; |
| 1135 | 1074 | ||
| 1136 | err = -EBUSY; | 1075 | err = -EBUSY; |
| @@ -1138,26 +1077,31 @@ static int netlink_insert(struct sock *sk, struct net *net, u32 portid) | |||
| 1138 | goto err; | 1077 | goto err; |
| 1139 | 1078 | ||
| 1140 | err = -ENOMEM; | 1079 | err = -ENOMEM; |
| 1141 | if (BITS_PER_LONG > 32 && unlikely(hash->entries >= UINT_MAX)) | 1080 | if (BITS_PER_LONG > 32 && unlikely(table->hash.nelems >= UINT_MAX)) |
| 1142 | goto err; | 1081 | goto err; |
| 1143 | 1082 | ||
| 1144 | if (len && nl_portid_hash_dilute(hash, len)) | ||
| 1145 | head = nl_portid_hashfn(hash, portid); | ||
| 1146 | hash->entries++; | ||
| 1147 | nlk_sk(sk)->portid = portid; | 1083 | nlk_sk(sk)->portid = portid; |
| 1148 | sk_add_node(sk, head); | 1084 | sock_hold(sk); |
| 1085 | rhashtable_insert(&table->hash, &nlk_sk(sk)->node, GFP_KERNEL); | ||
| 1149 | err = 0; | 1086 | err = 0; |
| 1150 | |||
| 1151 | err: | 1087 | err: |
| 1152 | netlink_table_ungrab(); | 1088 | mutex_unlock(&nl_sk_hash_lock); |
| 1153 | return err; | 1089 | return err; |
| 1154 | } | 1090 | } |
| 1155 | 1091 | ||
| 1156 | static void netlink_remove(struct sock *sk) | 1092 | static void netlink_remove(struct sock *sk) |
| 1157 | { | 1093 | { |
| 1094 | struct netlink_table *table; | ||
| 1095 | |||
| 1096 | mutex_lock(&nl_sk_hash_lock); | ||
| 1097 | table = &nl_table[sk->sk_protocol]; | ||
| 1098 | if (rhashtable_remove(&table->hash, &nlk_sk(sk)->node, GFP_KERNEL)) { | ||
| 1099 | WARN_ON(atomic_read(&sk->sk_refcnt) == 1); | ||
| 1100 | __sock_put(sk); | ||
| 1101 | } | ||
| 1102 | mutex_unlock(&nl_sk_hash_lock); | ||
| 1103 | |||
| 1158 | netlink_table_grab(); | 1104 | netlink_table_grab(); |
| 1159 | if (sk_del_node_init(sk)) | ||
| 1160 | nl_table[sk->sk_protocol].hash.entries--; | ||
| 1161 | if (nlk_sk(sk)->subscriptions) | 1105 | if (nlk_sk(sk)->subscriptions) |
| 1162 | __sk_del_bind_node(sk); | 1106 | __sk_del_bind_node(sk); |
| 1163 | netlink_table_ungrab(); | 1107 | netlink_table_ungrab(); |
| @@ -1313,6 +1257,9 @@ static int netlink_release(struct socket *sock) | |||
| 1313 | } | 1257 | } |
| 1314 | netlink_table_ungrab(); | 1258 | netlink_table_ungrab(); |
| 1315 | 1259 | ||
| 1260 | /* Wait for readers to complete */ | ||
| 1261 | synchronize_net(); | ||
| 1262 | |||
| 1316 | kfree(nlk->groups); | 1263 | kfree(nlk->groups); |
| 1317 | nlk->groups = NULL; | 1264 | nlk->groups = NULL; |
| 1318 | 1265 | ||
| @@ -1328,30 +1275,22 @@ static int netlink_autobind(struct socket *sock) | |||
| 1328 | struct sock *sk = sock->sk; | 1275 | struct sock *sk = sock->sk; |
| 1329 | struct net *net = sock_net(sk); | 1276 | struct net *net = sock_net(sk); |
| 1330 | struct netlink_table *table = &nl_table[sk->sk_protocol]; | 1277 | struct netlink_table *table = &nl_table[sk->sk_protocol]; |
| 1331 | struct nl_portid_hash *hash = &table->hash; | ||
| 1332 | struct hlist_head *head; | ||
| 1333 | struct sock *osk; | ||
| 1334 | s32 portid = task_tgid_vnr(current); | 1278 | s32 portid = task_tgid_vnr(current); |
| 1335 | int err; | 1279 | int err; |
| 1336 | static s32 rover = -4097; | 1280 | static s32 rover = -4097; |
| 1337 | 1281 | ||
| 1338 | retry: | 1282 | retry: |
| 1339 | cond_resched(); | 1283 | cond_resched(); |
| 1340 | netlink_table_grab(); | 1284 | rcu_read_lock(); |
| 1341 | head = nl_portid_hashfn(hash, portid); | 1285 | if (__netlink_lookup(table, portid, net)) { |
| 1342 | sk_for_each(osk, head) { | 1286 | /* Bind collision, search negative portid values. */ |
| 1343 | if (!table->compare(net, osk)) | 1287 | portid = rover--; |
| 1344 | continue; | 1288 | if (rover > -4097) |
| 1345 | if (nlk_sk(osk)->portid == portid) { | 1289 | rover = -4097; |
| 1346 | /* Bind collision, search negative portid values. */ | 1290 | rcu_read_unlock(); |
| 1347 | portid = rover--; | 1291 | goto retry; |
| 1348 | if (rover > -4097) | ||
| 1349 | rover = -4097; | ||
| 1350 | netlink_table_ungrab(); | ||
| 1351 | goto retry; | ||
| 1352 | } | ||
| 1353 | } | 1292 | } |
| 1354 | netlink_table_ungrab(); | 1293 | rcu_read_unlock(); |
| 1355 | 1294 | ||
| 1356 | err = netlink_insert(sk, net, portid); | 1295 | err = netlink_insert(sk, net, portid); |
| 1357 | if (err == -EADDRINUSE) | 1296 | if (err == -EADDRINUSE) |
| @@ -1961,25 +1900,25 @@ struct netlink_broadcast_data { | |||
| 1961 | void *tx_data; | 1900 | void *tx_data; |
| 1962 | }; | 1901 | }; |
| 1963 | 1902 | ||
| 1964 | static int do_one_broadcast(struct sock *sk, | 1903 | static void do_one_broadcast(struct sock *sk, |
| 1965 | struct netlink_broadcast_data *p) | 1904 | struct netlink_broadcast_data *p) |
| 1966 | { | 1905 | { |
| 1967 | struct netlink_sock *nlk = nlk_sk(sk); | 1906 | struct netlink_sock *nlk = nlk_sk(sk); |
| 1968 | int val; | 1907 | int val; |
| 1969 | 1908 | ||
| 1970 | if (p->exclude_sk == sk) | 1909 | if (p->exclude_sk == sk) |
| 1971 | goto out; | 1910 | return; |
| 1972 | 1911 | ||
| 1973 | if (nlk->portid == p->portid || p->group - 1 >= nlk->ngroups || | 1912 | if (nlk->portid == p->portid || p->group - 1 >= nlk->ngroups || |
| 1974 | !test_bit(p->group - 1, nlk->groups)) | 1913 | !test_bit(p->group - 1, nlk->groups)) |
| 1975 | goto out; | 1914 | return; |
| 1976 | 1915 | ||
| 1977 | if (!net_eq(sock_net(sk), p->net)) | 1916 | if (!net_eq(sock_net(sk), p->net)) |
| 1978 | goto out; | 1917 | return; |
| 1979 | 1918 | ||
| 1980 | if (p->failure) { | 1919 | if (p->failure) { |
| 1981 | netlink_overrun(sk); | 1920 | netlink_overrun(sk); |
| 1982 | goto out; | 1921 | return; |
| 1983 | } | 1922 | } |
| 1984 | 1923 | ||
| 1985 | sock_hold(sk); | 1924 | sock_hold(sk); |
| @@ -2017,9 +1956,6 @@ static int do_one_broadcast(struct sock *sk, | |||
| 2017 | p->skb2 = NULL; | 1956 | p->skb2 = NULL; |
| 2018 | } | 1957 | } |
| 2019 | sock_put(sk); | 1958 | sock_put(sk); |
| 2020 | |||
| 2021 | out: | ||
| 2022 | return 0; | ||
| 2023 | } | 1959 | } |
| 2024 | 1960 | ||
| 2025 | int netlink_broadcast_filtered(struct sock *ssk, struct sk_buff *skb, u32 portid, | 1961 | int netlink_broadcast_filtered(struct sock *ssk, struct sk_buff *skb, u32 portid, |
| @@ -2958,14 +2894,18 @@ static struct sock *netlink_seq_socket_idx(struct seq_file *seq, loff_t pos) | |||
| 2958 | { | 2894 | { |
| 2959 | struct nl_seq_iter *iter = seq->private; | 2895 | struct nl_seq_iter *iter = seq->private; |
| 2960 | int i, j; | 2896 | int i, j; |
| 2897 | struct netlink_sock *nlk; | ||
| 2961 | struct sock *s; | 2898 | struct sock *s; |
| 2962 | loff_t off = 0; | 2899 | loff_t off = 0; |
| 2963 | 2900 | ||
| 2964 | for (i = 0; i < MAX_LINKS; i++) { | 2901 | for (i = 0; i < MAX_LINKS; i++) { |
| 2965 | struct nl_portid_hash *hash = &nl_table[i].hash; | 2902 | struct rhashtable *ht = &nl_table[i].hash; |
| 2903 | const struct bucket_table *tbl = rht_dereference_rcu(ht->tbl, ht); | ||
| 2904 | |||
| 2905 | for (j = 0; j < tbl->size; j++) { | ||
| 2906 | rht_for_each_entry_rcu(nlk, tbl->buckets[j], node) { | ||
| 2907 | s = (struct sock *)nlk; | ||
| 2966 | 2908 | ||
| 2967 | for (j = 0; j <= hash->mask; j++) { | ||
| 2968 | sk_for_each(s, &hash->table[j]) { | ||
| 2969 | if (sock_net(s) != seq_file_net(seq)) | 2909 | if (sock_net(s) != seq_file_net(seq)) |
| 2970 | continue; | 2910 | continue; |
| 2971 | if (off == pos) { | 2911 | if (off == pos) { |
| @@ -2981,15 +2921,15 @@ static struct sock *netlink_seq_socket_idx(struct seq_file *seq, loff_t pos) | |||
| 2981 | } | 2921 | } |
| 2982 | 2922 | ||
| 2983 | static void *netlink_seq_start(struct seq_file *seq, loff_t *pos) | 2923 | static void *netlink_seq_start(struct seq_file *seq, loff_t *pos) |
| 2984 | __acquires(nl_table_lock) | 2924 | __acquires(RCU) |
| 2985 | { | 2925 | { |
| 2986 | read_lock(&nl_table_lock); | 2926 | rcu_read_lock(); |
| 2987 | return *pos ? netlink_seq_socket_idx(seq, *pos - 1) : SEQ_START_TOKEN; | 2927 | return *pos ? netlink_seq_socket_idx(seq, *pos - 1) : SEQ_START_TOKEN; |
| 2988 | } | 2928 | } |
| 2989 | 2929 | ||
| 2990 | static void *netlink_seq_next(struct seq_file *seq, void *v, loff_t *pos) | 2930 | static void *netlink_seq_next(struct seq_file *seq, void *v, loff_t *pos) |
| 2991 | { | 2931 | { |
| 2992 | struct sock *s; | 2932 | struct netlink_sock *nlk; |
| 2993 | struct nl_seq_iter *iter; | 2933 | struct nl_seq_iter *iter; |
| 2994 | struct net *net; | 2934 | struct net *net; |
| 2995 | int i, j; | 2935 | int i, j; |
| @@ -3001,28 +2941,26 @@ static void *netlink_seq_next(struct seq_file *seq, void *v, loff_t *pos) | |||
| 3001 | 2941 | ||
| 3002 | net = seq_file_net(seq); | 2942 | net = seq_file_net(seq); |
| 3003 | iter = seq->private; | 2943 | iter = seq->private; |
| 3004 | s = v; | 2944 | nlk = v; |
| 3005 | do { | 2945 | |
| 3006 | s = sk_next(s); | 2946 | rht_for_each_entry_rcu(nlk, nlk->node.next, node) |
| 3007 | } while (s && !nl_table[s->sk_protocol].compare(net, s)); | 2947 | if (net_eq(sock_net((struct sock *)nlk), net)) |
| 3008 | if (s) | 2948 | return nlk; |
| 3009 | return s; | ||
| 3010 | 2949 | ||
| 3011 | i = iter->link; | 2950 | i = iter->link; |
| 3012 | j = iter->hash_idx + 1; | 2951 | j = iter->hash_idx + 1; |
| 3013 | 2952 | ||
| 3014 | do { | 2953 | do { |
| 3015 | struct nl_portid_hash *hash = &nl_table[i].hash; | 2954 | struct rhashtable *ht = &nl_table[i].hash; |
| 3016 | 2955 | const struct bucket_table *tbl = rht_dereference_rcu(ht->tbl, ht); | |
| 3017 | for (; j <= hash->mask; j++) { | ||
| 3018 | s = sk_head(&hash->table[j]); | ||
| 3019 | 2956 | ||
| 3020 | while (s && !nl_table[s->sk_protocol].compare(net, s)) | 2957 | for (; j < tbl->size; j++) { |
| 3021 | s = sk_next(s); | 2958 | rht_for_each_entry_rcu(nlk, tbl->buckets[j], node) { |
| 3022 | if (s) { | 2959 | if (net_eq(sock_net((struct sock *)nlk), net)) { |
| 3023 | iter->link = i; | 2960 | iter->link = i; |
| 3024 | iter->hash_idx = j; | 2961 | iter->hash_idx = j; |
| 3025 | return s; | 2962 | return nlk; |
| 2963 | } | ||
| 3026 | } | 2964 | } |
| 3027 | } | 2965 | } |
| 3028 | 2966 | ||
| @@ -3033,9 +2971,9 @@ static void *netlink_seq_next(struct seq_file *seq, void *v, loff_t *pos) | |||
| 3033 | } | 2971 | } |
| 3034 | 2972 | ||
| 3035 | static void netlink_seq_stop(struct seq_file *seq, void *v) | 2973 | static void netlink_seq_stop(struct seq_file *seq, void *v) |
| 3036 | __releases(nl_table_lock) | 2974 | __releases(RCU) |
| 3037 | { | 2975 | { |
| 3038 | read_unlock(&nl_table_lock); | 2976 | rcu_read_unlock(); |
| 3039 | } | 2977 | } |
| 3040 | 2978 | ||
| 3041 | 2979 | ||
| @@ -3173,9 +3111,17 @@ static struct pernet_operations __net_initdata netlink_net_ops = { | |||
| 3173 | static int __init netlink_proto_init(void) | 3111 | static int __init netlink_proto_init(void) |
| 3174 | { | 3112 | { |
| 3175 | int i; | 3113 | int i; |
| 3176 | unsigned long limit; | ||
| 3177 | unsigned int order; | ||
| 3178 | int err = proto_register(&netlink_proto, 0); | 3114 | int err = proto_register(&netlink_proto, 0); |
| 3115 | struct rhashtable_params ht_params = { | ||
| 3116 | .head_offset = offsetof(struct netlink_sock, node), | ||
| 3117 | .key_offset = offsetof(struct netlink_sock, portid), | ||
| 3118 | .key_len = sizeof(u32), /* portid */ | ||
| 3119 | .hashfn = arch_fast_hash, | ||
| 3120 | .max_shift = 16, /* 64K */ | ||
| 3121 | .grow_decision = rht_grow_above_75, | ||
| 3122 | .shrink_decision = rht_shrink_below_30, | ||
| 3123 | .mutex_is_held = lockdep_nl_sk_hash_is_held, | ||
| 3124 | }; | ||
| 3179 | 3125 | ||
| 3180 | if (err != 0) | 3126 | if (err != 0) |
| 3181 | goto out; | 3127 | goto out; |
| @@ -3186,32 +3132,13 @@ static int __init netlink_proto_init(void) | |||
| 3186 | if (!nl_table) | 3132 | if (!nl_table) |
| 3187 | goto panic; | 3133 | goto panic; |
| 3188 | 3134 | ||
| 3189 | if (totalram_pages >= (128 * 1024)) | ||
| 3190 | limit = totalram_pages >> (21 - PAGE_SHIFT); | ||
| 3191 | else | ||
| 3192 | limit = totalram_pages >> (23 - PAGE_SHIFT); | ||
| 3193 | |||
| 3194 | order = get_bitmask_order(limit) - 1 + PAGE_SHIFT; | ||
| 3195 | limit = (1UL << order) / sizeof(struct hlist_head); | ||
| 3196 | order = get_bitmask_order(min(limit, (unsigned long)UINT_MAX)) - 1; | ||
| 3197 | |||
| 3198 | for (i = 0; i < MAX_LINKS; i++) { | 3135 | for (i = 0; i < MAX_LINKS; i++) { |
| 3199 | struct nl_portid_hash *hash = &nl_table[i].hash; | 3136 | if (rhashtable_init(&nl_table[i].hash, &ht_params) < 0) { |
| 3200 | 3137 | while (--i > 0) | |
| 3201 | hash->table = nl_portid_hash_zalloc(1 * sizeof(*hash->table)); | 3138 | rhashtable_destroy(&nl_table[i].hash); |
| 3202 | if (!hash->table) { | ||
| 3203 | while (i-- > 0) | ||
| 3204 | nl_portid_hash_free(nl_table[i].hash.table, | ||
| 3205 | 1 * sizeof(*hash->table)); | ||
| 3206 | kfree(nl_table); | 3139 | kfree(nl_table); |
| 3207 | goto panic; | 3140 | goto panic; |
| 3208 | } | 3141 | } |
| 3209 | hash->max_shift = order; | ||
| 3210 | hash->shift = 0; | ||
| 3211 | hash->mask = 0; | ||
| 3212 | hash->rehash_time = jiffies; | ||
| 3213 | |||
| 3214 | nl_table[i].compare = netlink_compare; | ||
| 3215 | } | 3142 | } |
| 3216 | 3143 | ||
| 3217 | INIT_LIST_HEAD(&netlink_tap_all); | 3144 | INIT_LIST_HEAD(&netlink_tap_all); |
diff --git a/net/netlink/af_netlink.h b/net/netlink/af_netlink.h index 0b59d441f5b6..b20a1731759b 100644 --- a/net/netlink/af_netlink.h +++ b/net/netlink/af_netlink.h | |||
| @@ -1,6 +1,7 @@ | |||
| 1 | #ifndef _AF_NETLINK_H | 1 | #ifndef _AF_NETLINK_H |
| 2 | #define _AF_NETLINK_H | 2 | #define _AF_NETLINK_H |
| 3 | 3 | ||
| 4 | #include <linux/rhashtable.h> | ||
| 4 | #include <net/sock.h> | 5 | #include <net/sock.h> |
| 5 | 6 | ||
| 6 | #define NLGRPSZ(x) (ALIGN(x, sizeof(unsigned long) * 8) / 8) | 7 | #define NLGRPSZ(x) (ALIGN(x, sizeof(unsigned long) * 8) / 8) |
| @@ -47,6 +48,8 @@ struct netlink_sock { | |||
| 47 | struct netlink_ring tx_ring; | 48 | struct netlink_ring tx_ring; |
| 48 | atomic_t mapped; | 49 | atomic_t mapped; |
| 49 | #endif /* CONFIG_NETLINK_MMAP */ | 50 | #endif /* CONFIG_NETLINK_MMAP */ |
| 51 | |||
| 52 | struct rhash_head node; | ||
| 50 | }; | 53 | }; |
| 51 | 54 | ||
| 52 | static inline struct netlink_sock *nlk_sk(struct sock *sk) | 55 | static inline struct netlink_sock *nlk_sk(struct sock *sk) |
| @@ -54,21 +57,8 @@ static inline struct netlink_sock *nlk_sk(struct sock *sk) | |||
| 54 | return container_of(sk, struct netlink_sock, sk); | 57 | return container_of(sk, struct netlink_sock, sk); |
| 55 | } | 58 | } |
| 56 | 59 | ||
| 57 | struct nl_portid_hash { | ||
| 58 | struct hlist_head *table; | ||
| 59 | unsigned long rehash_time; | ||
| 60 | |||
| 61 | unsigned int mask; | ||
| 62 | unsigned int shift; | ||
| 63 | |||
| 64 | unsigned int entries; | ||
| 65 | unsigned int max_shift; | ||
| 66 | |||
| 67 | u32 rnd; | ||
| 68 | }; | ||
| 69 | |||
| 70 | struct netlink_table { | 60 | struct netlink_table { |
| 71 | struct nl_portid_hash hash; | 61 | struct rhashtable hash; |
| 72 | struct hlist_head mc_list; | 62 | struct hlist_head mc_list; |
| 73 | struct listeners __rcu *listeners; | 63 | struct listeners __rcu *listeners; |
| 74 | unsigned int flags; | 64 | unsigned int flags; |
| @@ -83,5 +73,6 @@ struct netlink_table { | |||
| 83 | 73 | ||
| 84 | extern struct netlink_table *nl_table; | 74 | extern struct netlink_table *nl_table; |
| 85 | extern rwlock_t nl_table_lock; | 75 | extern rwlock_t nl_table_lock; |
| 76 | extern struct mutex nl_sk_hash_lock; | ||
| 86 | 77 | ||
| 87 | #endif | 78 | #endif |
diff --git a/net/netlink/diag.c b/net/netlink/diag.c index 1af29624b92f..de8c74a3c061 100644 --- a/net/netlink/diag.c +++ b/net/netlink/diag.c | |||
| @@ -4,6 +4,7 @@ | |||
| 4 | #include <linux/netlink.h> | 4 | #include <linux/netlink.h> |
| 5 | #include <linux/sock_diag.h> | 5 | #include <linux/sock_diag.h> |
| 6 | #include <linux/netlink_diag.h> | 6 | #include <linux/netlink_diag.h> |
| 7 | #include <linux/rhashtable.h> | ||
| 7 | 8 | ||
| 8 | #include "af_netlink.h" | 9 | #include "af_netlink.h" |
| 9 | 10 | ||
| @@ -101,16 +102,20 @@ static int __netlink_diag_dump(struct sk_buff *skb, struct netlink_callback *cb, | |||
| 101 | int protocol, int s_num) | 102 | int protocol, int s_num) |
| 102 | { | 103 | { |
| 103 | struct netlink_table *tbl = &nl_table[protocol]; | 104 | struct netlink_table *tbl = &nl_table[protocol]; |
| 104 | struct nl_portid_hash *hash = &tbl->hash; | 105 | struct rhashtable *ht = &tbl->hash; |
| 106 | const struct bucket_table *htbl = rht_dereference(ht->tbl, ht); | ||
| 105 | struct net *net = sock_net(skb->sk); | 107 | struct net *net = sock_net(skb->sk); |
| 106 | struct netlink_diag_req *req; | 108 | struct netlink_diag_req *req; |
| 109 | struct netlink_sock *nlsk; | ||
| 107 | struct sock *sk; | 110 | struct sock *sk; |
| 108 | int ret = 0, num = 0, i; | 111 | int ret = 0, num = 0, i; |
| 109 | 112 | ||
| 110 | req = nlmsg_data(cb->nlh); | 113 | req = nlmsg_data(cb->nlh); |
| 111 | 114 | ||
| 112 | for (i = 0; i <= hash->mask; i++) { | 115 | for (i = 0; i < htbl->size; i++) { |
| 113 | sk_for_each(sk, &hash->table[i]) { | 116 | rht_for_each_entry(nlsk, htbl->buckets[i], ht, node) { |
| 117 | sk = (struct sock *)nlsk; | ||
| 118 | |||
| 114 | if (!net_eq(sock_net(sk), net)) | 119 | if (!net_eq(sock_net(sk), net)) |
| 115 | continue; | 120 | continue; |
| 116 | if (num < s_num) { | 121 | if (num < s_num) { |
| @@ -165,6 +170,7 @@ static int netlink_diag_dump(struct sk_buff *skb, struct netlink_callback *cb) | |||
| 165 | 170 | ||
| 166 | req = nlmsg_data(cb->nlh); | 171 | req = nlmsg_data(cb->nlh); |
| 167 | 172 | ||
| 173 | mutex_lock(&nl_sk_hash_lock); | ||
| 168 | read_lock(&nl_table_lock); | 174 | read_lock(&nl_table_lock); |
| 169 | 175 | ||
| 170 | if (req->sdiag_protocol == NDIAG_PROTO_ALL) { | 176 | if (req->sdiag_protocol == NDIAG_PROTO_ALL) { |
| @@ -178,6 +184,7 @@ static int netlink_diag_dump(struct sk_buff *skb, struct netlink_callback *cb) | |||
| 178 | } else { | 184 | } else { |
| 179 | if (req->sdiag_protocol >= MAX_LINKS) { | 185 | if (req->sdiag_protocol >= MAX_LINKS) { |
| 180 | read_unlock(&nl_table_lock); | 186 | read_unlock(&nl_table_lock); |
| 187 | mutex_unlock(&nl_sk_hash_lock); | ||
| 181 | return -ENOENT; | 188 | return -ENOENT; |
| 182 | } | 189 | } |
| 183 | 190 | ||
| @@ -185,6 +192,7 @@ static int netlink_diag_dump(struct sk_buff *skb, struct netlink_callback *cb) | |||
| 185 | } | 192 | } |
| 186 | 193 | ||
| 187 | read_unlock(&nl_table_lock); | 194 | read_unlock(&nl_table_lock); |
| 195 | mutex_unlock(&nl_sk_hash_lock); | ||
| 188 | 196 | ||
| 189 | return skb->len; | 197 | return skb->len; |
| 190 | } | 198 | } |
diff --git a/net/netrom/af_netrom.c b/net/netrom/af_netrom.c index ede50d197e10..71cf1bffea06 100644 --- a/net/netrom/af_netrom.c +++ b/net/netrom/af_netrom.c | |||
| @@ -1418,7 +1418,7 @@ static int __init nr_proto_init(void) | |||
| 1418 | struct net_device *dev; | 1418 | struct net_device *dev; |
| 1419 | 1419 | ||
| 1420 | sprintf(name, "nr%d", i); | 1420 | sprintf(name, "nr%d", i); |
| 1421 | dev = alloc_netdev(0, name, nr_setup); | 1421 | dev = alloc_netdev(0, name, NET_NAME_UNKNOWN, nr_setup); |
| 1422 | if (!dev) { | 1422 | if (!dev) { |
| 1423 | printk(KERN_ERR "NET/ROM: nr_proto_init - unable to allocate device structure\n"); | 1423 | printk(KERN_ERR "NET/ROM: nr_proto_init - unable to allocate device structure\n"); |
| 1424 | goto fail; | 1424 | goto fail; |
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 @@ | |||
| 29 | #define DIGITAL_CMD_TG_SEND 1 | 29 | #define DIGITAL_CMD_TG_SEND 1 |
| 30 | #define DIGITAL_CMD_TG_LISTEN 2 | 30 | #define DIGITAL_CMD_TG_LISTEN 2 |
| 31 | #define DIGITAL_CMD_TG_LISTEN_MDAA 3 | 31 | #define DIGITAL_CMD_TG_LISTEN_MDAA 3 |
| 32 | #define DIGITAL_CMD_TG_LISTEN_MD 4 | ||
| 32 | 33 | ||
| 33 | #define DIGITAL_MAX_HEADER_LEN 7 | 34 | #define DIGITAL_MAX_HEADER_LEN 7 |
| 34 | #define DIGITAL_CRC_LEN 2 | 35 | #define DIGITAL_CRC_LEN 2 |
| @@ -121,6 +122,8 @@ int digital_tg_send_dep_res(struct nfc_digital_dev *ddev, struct sk_buff *skb); | |||
| 121 | 122 | ||
| 122 | int digital_tg_listen_nfca(struct nfc_digital_dev *ddev, u8 rf_tech); | 123 | int digital_tg_listen_nfca(struct nfc_digital_dev *ddev, u8 rf_tech); |
| 123 | int digital_tg_listen_nfcf(struct nfc_digital_dev *ddev, u8 rf_tech); | 124 | int digital_tg_listen_nfcf(struct nfc_digital_dev *ddev, u8 rf_tech); |
| 125 | void digital_tg_recv_md_req(struct nfc_digital_dev *ddev, void *arg, | ||
| 126 | struct sk_buff *resp); | ||
| 124 | 127 | ||
| 125 | typedef u16 (*crc_func_t)(u16, const u8 *, size_t); | 128 | typedef u16 (*crc_func_t)(u16, const u8 *, size_t); |
| 126 | 129 | ||
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) | |||
| 201 | digital_send_cmd_complete, cmd); | 201 | digital_send_cmd_complete, cmd); |
| 202 | break; | 202 | break; |
| 203 | 203 | ||
| 204 | case DIGITAL_CMD_TG_LISTEN_MD: | ||
| 205 | rc = ddev->ops->tg_listen_md(ddev, cmd->timeout, | ||
| 206 | digital_send_cmd_complete, cmd); | ||
| 207 | break; | ||
| 208 | |||
| 204 | default: | 209 | default: |
| 205 | pr_err("Unknown cmd type %d\n", cmd->type); | 210 | pr_err("Unknown cmd type %d\n", cmd->type); |
| 206 | return; | 211 | return; |
| @@ -293,12 +298,19 @@ static int digital_tg_listen_mdaa(struct nfc_digital_dev *ddev, u8 rf_tech) | |||
| 293 | 500, digital_tg_recv_atr_req, NULL); | 298 | 500, digital_tg_recv_atr_req, NULL); |
| 294 | } | 299 | } |
| 295 | 300 | ||
| 301 | static int digital_tg_listen_md(struct nfc_digital_dev *ddev, u8 rf_tech) | ||
| 302 | { | ||
| 303 | return digital_send_cmd(ddev, DIGITAL_CMD_TG_LISTEN_MD, NULL, NULL, 500, | ||
| 304 | digital_tg_recv_md_req, NULL); | ||
| 305 | } | ||
| 306 | |||
| 296 | int digital_target_found(struct nfc_digital_dev *ddev, | 307 | int digital_target_found(struct nfc_digital_dev *ddev, |
| 297 | struct nfc_target *target, u8 protocol) | 308 | struct nfc_target *target, u8 protocol) |
| 298 | { | 309 | { |
| 299 | int rc; | 310 | int rc; |
| 300 | u8 framing; | 311 | u8 framing; |
| 301 | u8 rf_tech; | 312 | u8 rf_tech; |
| 313 | u8 poll_tech_count; | ||
| 302 | int (*check_crc)(struct sk_buff *skb); | 314 | int (*check_crc)(struct sk_buff *skb); |
| 303 | void (*add_crc)(struct sk_buff *skb); | 315 | void (*add_crc)(struct sk_buff *skb); |
| 304 | 316 | ||
| @@ -375,12 +387,16 @@ int digital_target_found(struct nfc_digital_dev *ddev, | |||
| 375 | return rc; | 387 | return rc; |
| 376 | 388 | ||
| 377 | target->supported_protocols = (1 << protocol); | 389 | target->supported_protocols = (1 << protocol); |
| 378 | rc = nfc_targets_found(ddev->nfc_dev, target, 1); | ||
| 379 | if (rc) | ||
| 380 | return rc; | ||
| 381 | 390 | ||
| 391 | poll_tech_count = ddev->poll_tech_count; | ||
| 382 | ddev->poll_tech_count = 0; | 392 | ddev->poll_tech_count = 0; |
| 383 | 393 | ||
| 394 | rc = nfc_targets_found(ddev->nfc_dev, target, 1); | ||
| 395 | if (rc) { | ||
| 396 | ddev->poll_tech_count = poll_tech_count; | ||
| 397 | return rc; | ||
| 398 | } | ||
| 399 | |||
| 384 | return 0; | 400 | return 0; |
| 385 | } | 401 | } |
| 386 | 402 | ||
| @@ -505,6 +521,9 @@ static int digital_start_poll(struct nfc_dev *nfc_dev, __u32 im_protocols, | |||
| 505 | if (ddev->ops->tg_listen_mdaa) { | 521 | if (ddev->ops->tg_listen_mdaa) { |
| 506 | digital_add_poll_tech(ddev, 0, | 522 | digital_add_poll_tech(ddev, 0, |
| 507 | digital_tg_listen_mdaa); | 523 | digital_tg_listen_mdaa); |
| 524 | } else if (ddev->ops->tg_listen_md) { | ||
| 525 | digital_add_poll_tech(ddev, 0, | ||
| 526 | digital_tg_listen_md); | ||
| 508 | } else { | 527 | } else { |
| 509 | digital_add_poll_tech(ddev, NFC_DIGITAL_RF_TECH_106A, | 528 | digital_add_poll_tech(ddev, NFC_DIGITAL_RF_TECH_106A, |
| 510 | digital_tg_listen_nfca); | 529 | digital_tg_listen_nfca); |
| @@ -732,7 +751,7 @@ struct nfc_digital_dev *nfc_digital_allocate_device(struct nfc_digital_ops *ops, | |||
| 732 | 751 | ||
| 733 | if (!ops->in_configure_hw || !ops->in_send_cmd || !ops->tg_listen || | 752 | if (!ops->in_configure_hw || !ops->in_send_cmd || !ops->tg_listen || |
| 734 | !ops->tg_configure_hw || !ops->tg_send_cmd || !ops->abort_cmd || | 753 | !ops->tg_configure_hw || !ops->tg_send_cmd || !ops->abort_cmd || |
| 735 | !ops->switch_rf) | 754 | !ops->switch_rf || (ops->tg_listen_md && !ops->tg_get_rf_tech)) |
| 736 | return NULL; | 755 | return NULL; |
| 737 | 756 | ||
| 738 | ddev = kzalloc(sizeof(struct nfc_digital_dev), GFP_KERNEL); | 757 | ddev = kzalloc(sizeof(struct nfc_digital_dev), GFP_KERNEL); |
diff --git a/net/nfc/digital_dep.c b/net/nfc/digital_dep.c index 171cb9949ab5..e1638dab076d 100644 --- a/net/nfc/digital_dep.c +++ b/net/nfc/digital_dep.c | |||
| @@ -457,12 +457,10 @@ static void digital_tg_recv_dep_req(struct nfc_digital_dev *ddev, void *arg, | |||
| 457 | pr_err("Received a ACK/NACK PDU\n"); | 457 | pr_err("Received a ACK/NACK PDU\n"); |
| 458 | rc = -EINVAL; | 458 | rc = -EINVAL; |
| 459 | goto exit; | 459 | goto exit; |
| 460 | break; | ||
| 461 | case DIGITAL_NFC_DEP_PFB_SUPERVISOR_PDU: | 460 | case DIGITAL_NFC_DEP_PFB_SUPERVISOR_PDU: |
| 462 | pr_err("Received a SUPERVISOR PDU\n"); | 461 | pr_err("Received a SUPERVISOR PDU\n"); |
| 463 | rc = -EINVAL; | 462 | rc = -EINVAL; |
| 464 | goto exit; | 463 | goto exit; |
| 465 | break; | ||
| 466 | } | 464 | } |
| 467 | 465 | ||
| 468 | skb_pull(resp, size); | 466 | skb_pull(resp, size); |
| @@ -673,6 +671,7 @@ void digital_tg_recv_atr_req(struct nfc_digital_dev *ddev, void *arg, | |||
| 673 | int rc; | 671 | int rc; |
| 674 | struct digital_atr_req *atr_req; | 672 | struct digital_atr_req *atr_req; |
| 675 | size_t gb_len, min_size; | 673 | size_t gb_len, min_size; |
| 674 | u8 poll_tech_count; | ||
| 676 | 675 | ||
| 677 | if (IS_ERR(resp)) { | 676 | if (IS_ERR(resp)) { |
| 678 | rc = PTR_ERR(resp); | 677 | rc = PTR_ERR(resp); |
| @@ -730,12 +729,16 @@ void digital_tg_recv_atr_req(struct nfc_digital_dev *ddev, void *arg, | |||
| 730 | goto exit; | 729 | goto exit; |
| 731 | 730 | ||
| 732 | gb_len = resp->len - sizeof(struct digital_atr_req); | 731 | gb_len = resp->len - sizeof(struct digital_atr_req); |
| 732 | |||
| 733 | poll_tech_count = ddev->poll_tech_count; | ||
| 734 | ddev->poll_tech_count = 0; | ||
| 735 | |||
| 733 | rc = nfc_tm_activated(ddev->nfc_dev, NFC_PROTO_NFC_DEP_MASK, | 736 | rc = nfc_tm_activated(ddev->nfc_dev, NFC_PROTO_NFC_DEP_MASK, |
| 734 | NFC_COMM_PASSIVE, atr_req->gb, gb_len); | 737 | NFC_COMM_PASSIVE, atr_req->gb, gb_len); |
| 735 | if (rc) | 738 | if (rc) { |
| 739 | ddev->poll_tech_count = poll_tech_count; | ||
| 736 | goto exit; | 740 | goto exit; |
| 737 | 741 | } | |
| 738 | ddev->poll_tech_count = 0; | ||
| 739 | 742 | ||
| 740 | rc = 0; | 743 | rc = 0; |
| 741 | exit: | 744 | 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, | |||
| 318 | 318 | ||
| 319 | if (DIGITAL_SEL_RES_IS_T2T(sel_res)) { | 319 | if (DIGITAL_SEL_RES_IS_T2T(sel_res)) { |
| 320 | nfc_proto = NFC_PROTO_MIFARE; | 320 | nfc_proto = NFC_PROTO_MIFARE; |
| 321 | } else if (DIGITAL_SEL_RES_IS_NFC_DEP(sel_res)) { | ||
| 322 | nfc_proto = NFC_PROTO_NFC_DEP; | ||
| 321 | } else if (DIGITAL_SEL_RES_IS_T4T(sel_res)) { | 323 | } else if (DIGITAL_SEL_RES_IS_T4T(sel_res)) { |
| 322 | rc = digital_in_send_rats(ddev, target); | 324 | rc = digital_in_send_rats(ddev, target); |
| 323 | if (rc) | 325 | if (rc) |
| @@ -327,8 +329,6 @@ static void digital_in_recv_sel_res(struct nfc_digital_dev *ddev, void *arg, | |||
| 327 | * done when receiving the ATS | 329 | * done when receiving the ATS |
| 328 | */ | 330 | */ |
| 329 | goto exit_free_skb; | 331 | goto exit_free_skb; |
| 330 | } else if (DIGITAL_SEL_RES_IS_NFC_DEP(sel_res)) { | ||
| 331 | nfc_proto = NFC_PROTO_NFC_DEP; | ||
| 332 | } else { | 332 | } else { |
| 333 | rc = -EOPNOTSUPP; | 333 | rc = -EOPNOTSUPP; |
| 334 | goto exit; | 334 | goto exit; |
| @@ -944,6 +944,13 @@ static int digital_tg_send_sel_res(struct nfc_digital_dev *ddev) | |||
| 944 | if (!DIGITAL_DRV_CAPS_TG_CRC(ddev)) | 944 | if (!DIGITAL_DRV_CAPS_TG_CRC(ddev)) |
| 945 | digital_skb_add_crc_a(skb); | 945 | digital_skb_add_crc_a(skb); |
| 946 | 946 | ||
| 947 | rc = digital_tg_configure_hw(ddev, NFC_DIGITAL_CONFIG_FRAMING, | ||
| 948 | NFC_DIGITAL_FRAMING_NFCA_ANTICOL_COMPLETE); | ||
| 949 | if (rc) { | ||
| 950 | kfree_skb(skb); | ||
| 951 | return rc; | ||
| 952 | } | ||
| 953 | |||
| 947 | rc = digital_tg_send_cmd(ddev, skb, 300, digital_tg_recv_atr_req, | 954 | rc = digital_tg_send_cmd(ddev, skb, 300, digital_tg_recv_atr_req, |
| 948 | NULL); | 955 | NULL); |
| 949 | if (rc) | 956 | if (rc) |
| @@ -1002,6 +1009,13 @@ static int digital_tg_send_sdd_res(struct nfc_digital_dev *ddev) | |||
| 1002 | for (i = 0; i < 4; i++) | 1009 | for (i = 0; i < 4; i++) |
| 1003 | sdd_res->bcc ^= sdd_res->nfcid1[i]; | 1010 | sdd_res->bcc ^= sdd_res->nfcid1[i]; |
| 1004 | 1011 | ||
| 1012 | rc = digital_tg_configure_hw(ddev, NFC_DIGITAL_CONFIG_FRAMING, | ||
| 1013 | NFC_DIGITAL_FRAMING_NFCA_STANDARD_WITH_CRC_A); | ||
| 1014 | if (rc) { | ||
| 1015 | kfree_skb(skb); | ||
| 1016 | return rc; | ||
| 1017 | } | ||
| 1018 | |||
| 1005 | rc = digital_tg_send_cmd(ddev, skb, 300, digital_tg_recv_sel_req, | 1019 | rc = digital_tg_send_cmd(ddev, skb, 300, digital_tg_recv_sel_req, |
| 1006 | NULL); | 1020 | NULL); |
| 1007 | if (rc) | 1021 | if (rc) |
| @@ -1054,6 +1068,13 @@ static int digital_tg_send_sens_res(struct nfc_digital_dev *ddev) | |||
| 1054 | sens_res[0] = (DIGITAL_SENS_RES_NFC_DEP >> 8) & 0xFF; | 1068 | sens_res[0] = (DIGITAL_SENS_RES_NFC_DEP >> 8) & 0xFF; |
| 1055 | sens_res[1] = DIGITAL_SENS_RES_NFC_DEP & 0xFF; | 1069 | sens_res[1] = DIGITAL_SENS_RES_NFC_DEP & 0xFF; |
| 1056 | 1070 | ||
| 1071 | rc = digital_tg_configure_hw(ddev, NFC_DIGITAL_CONFIG_FRAMING, | ||
| 1072 | NFC_DIGITAL_FRAMING_NFCA_STANDARD); | ||
| 1073 | if (rc) { | ||
| 1074 | kfree_skb(skb); | ||
| 1075 | return rc; | ||
| 1076 | } | ||
| 1077 | |||
| 1057 | rc = digital_tg_send_cmd(ddev, skb, 300, digital_tg_recv_sdd_req, | 1078 | rc = digital_tg_send_cmd(ddev, skb, 300, digital_tg_recv_sdd_req, |
| 1058 | NULL); | 1079 | NULL); |
| 1059 | if (rc) | 1080 | if (rc) |
| @@ -1197,33 +1218,48 @@ exit: | |||
| 1197 | dev_kfree_skb(resp); | 1218 | dev_kfree_skb(resp); |
| 1198 | } | 1219 | } |
| 1199 | 1220 | ||
| 1200 | int digital_tg_listen_nfca(struct nfc_digital_dev *ddev, u8 rf_tech) | 1221 | static int digital_tg_config_nfca(struct nfc_digital_dev *ddev) |
| 1201 | { | 1222 | { |
| 1202 | int rc; | 1223 | int rc; |
| 1203 | 1224 | ||
| 1204 | rc = digital_tg_configure_hw(ddev, NFC_DIGITAL_CONFIG_RF_TECH, rf_tech); | 1225 | rc = digital_tg_configure_hw(ddev, NFC_DIGITAL_CONFIG_RF_TECH, |
| 1226 | NFC_DIGITAL_RF_TECH_106A); | ||
| 1205 | if (rc) | 1227 | if (rc) |
| 1206 | return rc; | 1228 | return rc; |
| 1207 | 1229 | ||
| 1208 | rc = digital_tg_configure_hw(ddev, NFC_DIGITAL_CONFIG_FRAMING, | 1230 | return digital_tg_configure_hw(ddev, NFC_DIGITAL_CONFIG_FRAMING, |
| 1209 | NFC_DIGITAL_FRAMING_NFCA_NFC_DEP); | 1231 | NFC_DIGITAL_FRAMING_NFCA_NFC_DEP); |
| 1232 | } | ||
| 1233 | |||
| 1234 | int digital_tg_listen_nfca(struct nfc_digital_dev *ddev, u8 rf_tech) | ||
| 1235 | { | ||
| 1236 | int rc; | ||
| 1237 | |||
| 1238 | rc = digital_tg_config_nfca(ddev); | ||
| 1210 | if (rc) | 1239 | if (rc) |
| 1211 | return rc; | 1240 | return rc; |
| 1212 | 1241 | ||
| 1213 | return digital_tg_listen(ddev, 300, digital_tg_recv_sens_req, NULL); | 1242 | return digital_tg_listen(ddev, 300, digital_tg_recv_sens_req, NULL); |
| 1214 | } | 1243 | } |
| 1215 | 1244 | ||
| 1216 | int digital_tg_listen_nfcf(struct nfc_digital_dev *ddev, u8 rf_tech) | 1245 | static int digital_tg_config_nfcf(struct nfc_digital_dev *ddev, u8 rf_tech) |
| 1217 | { | 1246 | { |
| 1218 | int rc; | 1247 | int rc; |
| 1219 | u8 *nfcid2; | ||
| 1220 | 1248 | ||
| 1221 | rc = digital_tg_configure_hw(ddev, NFC_DIGITAL_CONFIG_RF_TECH, rf_tech); | 1249 | rc = digital_tg_configure_hw(ddev, NFC_DIGITAL_CONFIG_RF_TECH, rf_tech); |
| 1222 | if (rc) | 1250 | if (rc) |
| 1223 | return rc; | 1251 | return rc; |
| 1224 | 1252 | ||
| 1225 | rc = digital_tg_configure_hw(ddev, NFC_DIGITAL_CONFIG_FRAMING, | 1253 | return digital_tg_configure_hw(ddev, NFC_DIGITAL_CONFIG_FRAMING, |
| 1226 | NFC_DIGITAL_FRAMING_NFCF_NFC_DEP); | 1254 | NFC_DIGITAL_FRAMING_NFCF_NFC_DEP); |
| 1255 | } | ||
| 1256 | |||
| 1257 | int digital_tg_listen_nfcf(struct nfc_digital_dev *ddev, u8 rf_tech) | ||
| 1258 | { | ||
| 1259 | int rc; | ||
| 1260 | u8 *nfcid2; | ||
| 1261 | |||
| 1262 | rc = digital_tg_config_nfcf(ddev, rf_tech); | ||
| 1227 | if (rc) | 1263 | if (rc) |
| 1228 | return rc; | 1264 | return rc; |
| 1229 | 1265 | ||
| @@ -1237,3 +1273,43 @@ int digital_tg_listen_nfcf(struct nfc_digital_dev *ddev, u8 rf_tech) | |||
| 1237 | 1273 | ||
| 1238 | return digital_tg_listen(ddev, 300, digital_tg_recv_sensf_req, nfcid2); | 1274 | return digital_tg_listen(ddev, 300, digital_tg_recv_sensf_req, nfcid2); |
| 1239 | } | 1275 | } |
| 1276 | |||
| 1277 | void digital_tg_recv_md_req(struct nfc_digital_dev *ddev, void *arg, | ||
| 1278 | struct sk_buff *resp) | ||
| 1279 | { | ||
| 1280 | u8 rf_tech; | ||
| 1281 | int rc; | ||
| 1282 | |||
| 1283 | if (IS_ERR(resp)) { | ||
| 1284 | resp = NULL; | ||
| 1285 | goto exit_free_skb; | ||
| 1286 | } | ||
| 1287 | |||
| 1288 | rc = ddev->ops->tg_get_rf_tech(ddev, &rf_tech); | ||
| 1289 | if (rc) | ||
| 1290 | goto exit_free_skb; | ||
| 1291 | |||
| 1292 | switch (rf_tech) { | ||
| 1293 | case NFC_DIGITAL_RF_TECH_106A: | ||
| 1294 | rc = digital_tg_config_nfca(ddev); | ||
| 1295 | if (rc) | ||
| 1296 | goto exit_free_skb; | ||
| 1297 | digital_tg_recv_sens_req(ddev, arg, resp); | ||
| 1298 | break; | ||
| 1299 | case NFC_DIGITAL_RF_TECH_212F: | ||
| 1300 | case NFC_DIGITAL_RF_TECH_424F: | ||
| 1301 | rc = digital_tg_config_nfcf(ddev, rf_tech); | ||
| 1302 | if (rc) | ||
| 1303 | goto exit_free_skb; | ||
| 1304 | digital_tg_recv_sensf_req(ddev, arg, resp); | ||
| 1305 | break; | ||
| 1306 | default: | ||
| 1307 | goto exit_free_skb; | ||
| 1308 | } | ||
| 1309 | |||
| 1310 | return; | ||
| 1311 | |||
| 1312 | exit_free_skb: | ||
| 1313 | digital_poll_next_tech(ddev); | ||
| 1314 | dev_kfree_skb(resp); | ||
| 1315 | } | ||
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) | |||
| 553 | { | 553 | { |
| 554 | struct nfc_hci_dev *hdev = nfc_get_drvdata(nfc_dev); | 554 | struct nfc_hci_dev *hdev = nfc_get_drvdata(nfc_dev); |
| 555 | 555 | ||
| 556 | nfc_hci_send_event(hdev, NFC_HCI_RF_READER_A_GATE, | 556 | if (hdev->ops->stop_poll) |
| 557 | NFC_HCI_EVT_END_OPERATION, NULL, 0); | 557 | hdev->ops->stop_poll(hdev); |
| 558 | else | ||
| 559 | nfc_hci_send_event(hdev, NFC_HCI_RF_READER_A_GATE, | ||
| 560 | NFC_HCI_EVT_END_OPERATION, NULL, 0); | ||
| 558 | } | 561 | } |
| 559 | 562 | ||
| 560 | static int hci_dep_link_up(struct nfc_dev *nfc_dev, struct nfc_target *target, | 563 | 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, | |||
| 166 | struct rf_tech_specific_params_nfcf_poll *nfcf_poll; | 166 | struct rf_tech_specific_params_nfcf_poll *nfcf_poll; |
| 167 | __u32 protocol; | 167 | __u32 protocol; |
| 168 | 168 | ||
| 169 | if (rf_protocol == NCI_RF_PROTOCOL_T2T) | 169 | if (rf_protocol == NCI_RF_PROTOCOL_T1T) |
| 170 | protocol = NFC_PROTO_JEWEL_MASK; | ||
| 171 | else if (rf_protocol == NCI_RF_PROTOCOL_T2T) | ||
| 170 | protocol = NFC_PROTO_MIFARE_MASK; | 172 | protocol = NFC_PROTO_MIFARE_MASK; |
| 171 | else if (rf_protocol == NCI_RF_PROTOCOL_ISO_DEP) | 173 | else if (rf_protocol == NCI_RF_PROTOCOL_ISO_DEP) |
| 172 | if (rf_tech_and_mode == NCI_NFC_A_PASSIVE_POLL_MODE) | 174 | if (rf_tech_and_mode == NCI_NFC_A_PASSIVE_POLL_MODE) |
diff --git a/net/openvswitch/actions.c b/net/openvswitch/actions.c index e70d8b18e962..fe5cda0deb39 100644 --- a/net/openvswitch/actions.c +++ b/net/openvswitch/actions.c | |||
| @@ -38,7 +38,7 @@ | |||
| 38 | #include "vport.h" | 38 | #include "vport.h" |
| 39 | 39 | ||
| 40 | static int do_execute_actions(struct datapath *dp, struct sk_buff *skb, | 40 | static int do_execute_actions(struct datapath *dp, struct sk_buff *skb, |
| 41 | const struct nlattr *attr, int len, bool keep_skb); | 41 | const struct nlattr *attr, int len); |
| 42 | 42 | ||
| 43 | static int make_writable(struct sk_buff *skb, int write_len) | 43 | static int make_writable(struct sk_buff *skb, int write_len) |
| 44 | { | 44 | { |
| @@ -434,11 +434,17 @@ static int output_userspace(struct datapath *dp, struct sk_buff *skb, | |||
| 434 | return ovs_dp_upcall(dp, skb, &upcall); | 434 | return ovs_dp_upcall(dp, skb, &upcall); |
| 435 | } | 435 | } |
| 436 | 436 | ||
| 437 | static bool last_action(const struct nlattr *a, int rem) | ||
| 438 | { | ||
| 439 | return a->nla_len == rem; | ||
| 440 | } | ||
| 441 | |||
| 437 | static int sample(struct datapath *dp, struct sk_buff *skb, | 442 | static int sample(struct datapath *dp, struct sk_buff *skb, |
| 438 | const struct nlattr *attr) | 443 | const struct nlattr *attr) |
| 439 | { | 444 | { |
| 440 | const struct nlattr *acts_list = NULL; | 445 | const struct nlattr *acts_list = NULL; |
| 441 | const struct nlattr *a; | 446 | const struct nlattr *a; |
| 447 | struct sk_buff *sample_skb; | ||
| 442 | int rem; | 448 | int rem; |
| 443 | 449 | ||
| 444 | for (a = nla_data(attr), rem = nla_len(attr); rem > 0; | 450 | for (a = nla_data(attr), rem = nla_len(attr); rem > 0; |
| @@ -455,8 +461,34 @@ static int sample(struct datapath *dp, struct sk_buff *skb, | |||
| 455 | } | 461 | } |
| 456 | } | 462 | } |
| 457 | 463 | ||
| 458 | return do_execute_actions(dp, skb, nla_data(acts_list), | 464 | rem = nla_len(acts_list); |
| 459 | nla_len(acts_list), true); | 465 | a = nla_data(acts_list); |
| 466 | |||
| 467 | /* Actions list is either empty or only contains a single user-space | ||
| 468 | * action, the latter being a special case as it is the only known | ||
| 469 | * usage of the sample action. | ||
| 470 | * In these special cases don't clone the skb as there are no | ||
| 471 | * side-effects in the nested actions. | ||
| 472 | * Otherwise, clone in case the nested actions have side effects. | ||
| 473 | */ | ||
| 474 | if (likely(rem == 0 || (nla_type(a) == OVS_ACTION_ATTR_USERSPACE && | ||
| 475 | last_action(a, rem)))) { | ||
| 476 | sample_skb = skb; | ||
| 477 | skb_get(skb); | ||
| 478 | } else { | ||
| 479 | sample_skb = skb_clone(skb, GFP_ATOMIC); | ||
| 480 | if (!sample_skb) /* Skip sample action when out of memory. */ | ||
| 481 | return 0; | ||
| 482 | } | ||
| 483 | |||
| 484 | /* Note that do_execute_actions() never consumes skb. | ||
| 485 | * In the case where skb has been cloned above it is the clone that | ||
| 486 | * is consumed. Otherwise the skb_get(skb) call prevents | ||
| 487 | * consumption by do_execute_actions(). Thus, it is safe to simply | ||
| 488 | * return the error code and let the caller (also | ||
| 489 | * do_execute_actions()) free skb on error. | ||
| 490 | */ | ||
| 491 | return do_execute_actions(dp, sample_skb, a, rem); | ||
| 460 | } | 492 | } |
| 461 | 493 | ||
| 462 | static int execute_set_action(struct sk_buff *skb, | 494 | static int execute_set_action(struct sk_buff *skb, |
| @@ -507,7 +539,7 @@ static int execute_set_action(struct sk_buff *skb, | |||
| 507 | 539 | ||
| 508 | /* Execute a list of actions against 'skb'. */ | 540 | /* Execute a list of actions against 'skb'. */ |
| 509 | static int do_execute_actions(struct datapath *dp, struct sk_buff *skb, | 541 | static int do_execute_actions(struct datapath *dp, struct sk_buff *skb, |
| 510 | const struct nlattr *attr, int len, bool keep_skb) | 542 | const struct nlattr *attr, int len) |
| 511 | { | 543 | { |
| 512 | /* Every output action needs a separate clone of 'skb', but the common | 544 | /* Every output action needs a separate clone of 'skb', but the common |
| 513 | * case is just a single output action, so that doing a clone and | 545 | * case is just a single output action, so that doing a clone and |
| @@ -562,12 +594,9 @@ static int do_execute_actions(struct datapath *dp, struct sk_buff *skb, | |||
| 562 | } | 594 | } |
| 563 | } | 595 | } |
| 564 | 596 | ||
| 565 | if (prev_port != -1) { | 597 | if (prev_port != -1) |
| 566 | if (keep_skb) | ||
| 567 | skb = skb_clone(skb, GFP_ATOMIC); | ||
| 568 | |||
| 569 | do_output(dp, skb, prev_port); | 598 | do_output(dp, skb, prev_port); |
| 570 | } else if (!keep_skb) | 599 | else |
| 571 | consume_skb(skb); | 600 | consume_skb(skb); |
| 572 | 601 | ||
| 573 | return 0; | 602 | return 0; |
| @@ -579,6 +608,5 @@ int ovs_execute_actions(struct datapath *dp, struct sk_buff *skb) | |||
| 579 | struct sw_flow_actions *acts = rcu_dereference(OVS_CB(skb)->flow->sf_acts); | 608 | struct sw_flow_actions *acts = rcu_dereference(OVS_CB(skb)->flow->sf_acts); |
| 580 | 609 | ||
| 581 | OVS_CB(skb)->tun_key = NULL; | 610 | OVS_CB(skb)->tun_key = NULL; |
| 582 | return do_execute_actions(dp, skb, acts->actions, | 611 | return do_execute_actions(dp, skb, acts->actions, acts->actions_len); |
| 583 | acts->actions_len, false); | ||
| 584 | } | 612 | } |
diff --git a/net/openvswitch/datapath.c b/net/openvswitch/datapath.c index 9db4bf6740d1..7228ec3faf19 100644 --- a/net/openvswitch/datapath.c +++ b/net/openvswitch/datapath.c | |||
| @@ -47,8 +47,6 @@ | |||
| 47 | #include <linux/openvswitch.h> | 47 | #include <linux/openvswitch.h> |
| 48 | #include <linux/rculist.h> | 48 | #include <linux/rculist.h> |
| 49 | #include <linux/dmi.h> | 49 | #include <linux/dmi.h> |
| 50 | #include <linux/genetlink.h> | ||
| 51 | #include <net/genetlink.h> | ||
| 52 | #include <net/genetlink.h> | 50 | #include <net/genetlink.h> |
| 53 | #include <net/net_namespace.h> | 51 | #include <net/net_namespace.h> |
| 54 | #include <net/netns/generic.h> | 52 | #include <net/netns/generic.h> |
| @@ -66,16 +64,16 @@ static struct genl_family dp_packet_genl_family; | |||
| 66 | static struct genl_family dp_flow_genl_family; | 64 | static struct genl_family dp_flow_genl_family; |
| 67 | static struct genl_family dp_datapath_genl_family; | 65 | static struct genl_family dp_datapath_genl_family; |
| 68 | 66 | ||
| 69 | static struct genl_multicast_group ovs_dp_flow_multicast_group = { | 67 | static const struct genl_multicast_group ovs_dp_flow_multicast_group = { |
| 70 | .name = OVS_FLOW_MCGROUP | 68 | .name = OVS_FLOW_MCGROUP, |
| 71 | }; | 69 | }; |
| 72 | 70 | ||
| 73 | static struct genl_multicast_group ovs_dp_datapath_multicast_group = { | 71 | static const struct genl_multicast_group ovs_dp_datapath_multicast_group = { |
| 74 | .name = OVS_DATAPATH_MCGROUP | 72 | .name = OVS_DATAPATH_MCGROUP, |
| 75 | }; | 73 | }; |
| 76 | 74 | ||
| 77 | struct genl_multicast_group ovs_dp_vport_multicast_group = { | 75 | static const struct genl_multicast_group ovs_dp_vport_multicast_group = { |
| 78 | .name = OVS_VPORT_MCGROUP | 76 | .name = OVS_VPORT_MCGROUP, |
| 79 | }; | 77 | }; |
| 80 | 78 | ||
| 81 | /* Check if need to build a reply message. | 79 | /* Check if need to build a reply message. |
| @@ -266,7 +264,7 @@ void ovs_dp_process_received_packet(struct vport *p, struct sk_buff *skb) | |||
| 266 | upcall.cmd = OVS_PACKET_CMD_MISS; | 264 | upcall.cmd = OVS_PACKET_CMD_MISS; |
| 267 | upcall.key = &key; | 265 | upcall.key = &key; |
| 268 | upcall.userdata = NULL; | 266 | upcall.userdata = NULL; |
| 269 | upcall.portid = p->upcall_portid; | 267 | upcall.portid = ovs_vport_find_upcall_portid(p, skb); |
| 270 | ovs_dp_upcall(dp, skb, &upcall); | 268 | ovs_dp_upcall(dp, skb, &upcall); |
| 271 | consume_skb(skb); | 269 | consume_skb(skb); |
| 272 | stats_counter = &stats->n_missed; | 270 | stats_counter = &stats->n_missed; |
| @@ -464,7 +462,8 @@ static int queue_userspace_packet(struct datapath *dp, struct sk_buff *skb, | |||
| 464 | upcall->dp_ifindex = dp_ifindex; | 462 | upcall->dp_ifindex = dp_ifindex; |
| 465 | 463 | ||
| 466 | nla = nla_nest_start(user_skb, OVS_PACKET_ATTR_KEY); | 464 | nla = nla_nest_start(user_skb, OVS_PACKET_ATTR_KEY); |
| 467 | ovs_nla_put_flow(upcall_info->key, upcall_info->key, user_skb); | 465 | err = ovs_nla_put_flow(upcall_info->key, upcall_info->key, user_skb); |
| 466 | BUG_ON(err); | ||
| 468 | nla_nest_end(user_skb, nla); | 467 | nla_nest_end(user_skb, nla); |
| 469 | 468 | ||
| 470 | if (upcall_info->userdata) | 469 | if (upcall_info->userdata) |
| @@ -780,7 +779,7 @@ static struct sk_buff *ovs_flow_cmd_build_info(const struct sw_flow *flow, | |||
| 780 | 779 | ||
| 781 | skb = ovs_flow_cmd_alloc_info(ovsl_dereference(flow->sf_acts), info, | 780 | skb = ovs_flow_cmd_alloc_info(ovsl_dereference(flow->sf_acts), info, |
| 782 | always); | 781 | always); |
| 783 | if (!skb || IS_ERR(skb)) | 782 | if (IS_ERR_OR_NULL(skb)) |
| 784 | return skb; | 783 | return skb; |
| 785 | 784 | ||
| 786 | retval = ovs_flow_cmd_fill_info(flow, dp_ifindex, skb, | 785 | retval = ovs_flow_cmd_fill_info(flow, dp_ifindex, skb, |
| @@ -1189,7 +1188,7 @@ static const struct nla_policy flow_policy[OVS_FLOW_ATTR_MAX + 1] = { | |||
| 1189 | [OVS_FLOW_ATTR_CLEAR] = { .type = NLA_FLAG }, | 1188 | [OVS_FLOW_ATTR_CLEAR] = { .type = NLA_FLAG }, |
| 1190 | }; | 1189 | }; |
| 1191 | 1190 | ||
| 1192 | static struct genl_ops dp_flow_genl_ops[] = { | 1191 | static const struct genl_ops dp_flow_genl_ops[] = { |
| 1193 | { .cmd = OVS_FLOW_CMD_NEW, | 1192 | { .cmd = OVS_FLOW_CMD_NEW, |
| 1194 | .flags = GENL_ADMIN_PERM, /* Requires CAP_NET_ADMIN privilege. */ | 1193 | .flags = GENL_ADMIN_PERM, /* Requires CAP_NET_ADMIN privilege. */ |
| 1195 | .policy = flow_policy, | 1194 | .policy = flow_policy, |
| @@ -1373,7 +1372,7 @@ static int ovs_dp_cmd_new(struct sk_buff *skb, struct genl_info *info) | |||
| 1373 | parms.options = NULL; | 1372 | parms.options = NULL; |
| 1374 | parms.dp = dp; | 1373 | parms.dp = dp; |
| 1375 | parms.port_no = OVSP_LOCAL; | 1374 | parms.port_no = OVSP_LOCAL; |
| 1376 | parms.upcall_portid = nla_get_u32(a[OVS_DP_ATTR_UPCALL_PID]); | 1375 | parms.upcall_portids = a[OVS_DP_ATTR_UPCALL_PID]; |
| 1377 | 1376 | ||
| 1378 | ovs_dp_change(dp, a); | 1377 | ovs_dp_change(dp, a); |
| 1379 | 1378 | ||
| @@ -1577,7 +1576,7 @@ static const struct nla_policy datapath_policy[OVS_DP_ATTR_MAX + 1] = { | |||
| 1577 | [OVS_DP_ATTR_USER_FEATURES] = { .type = NLA_U32 }, | 1576 | [OVS_DP_ATTR_USER_FEATURES] = { .type = NLA_U32 }, |
| 1578 | }; | 1577 | }; |
| 1579 | 1578 | ||
| 1580 | static struct genl_ops dp_datapath_genl_ops[] = { | 1579 | static const struct genl_ops dp_datapath_genl_ops[] = { |
| 1581 | { .cmd = OVS_DP_CMD_NEW, | 1580 | { .cmd = OVS_DP_CMD_NEW, |
| 1582 | .flags = GENL_ADMIN_PERM, /* Requires CAP_NET_ADMIN privilege. */ | 1581 | .flags = GENL_ADMIN_PERM, /* Requires CAP_NET_ADMIN privilege. */ |
| 1583 | .policy = datapath_policy, | 1582 | .policy = datapath_policy, |
| @@ -1632,8 +1631,8 @@ static int ovs_vport_cmd_fill_info(struct vport *vport, struct sk_buff *skb, | |||
| 1632 | 1631 | ||
| 1633 | if (nla_put_u32(skb, OVS_VPORT_ATTR_PORT_NO, vport->port_no) || | 1632 | if (nla_put_u32(skb, OVS_VPORT_ATTR_PORT_NO, vport->port_no) || |
| 1634 | nla_put_u32(skb, OVS_VPORT_ATTR_TYPE, vport->ops->type) || | 1633 | nla_put_u32(skb, OVS_VPORT_ATTR_TYPE, vport->ops->type) || |
| 1635 | nla_put_string(skb, OVS_VPORT_ATTR_NAME, vport->ops->get_name(vport)) || | 1634 | nla_put_string(skb, OVS_VPORT_ATTR_NAME, |
| 1636 | nla_put_u32(skb, OVS_VPORT_ATTR_UPCALL_PID, vport->upcall_portid)) | 1635 | vport->ops->get_name(vport))) |
| 1637 | goto nla_put_failure; | 1636 | goto nla_put_failure; |
| 1638 | 1637 | ||
| 1639 | ovs_vport_get_stats(vport, &vport_stats); | 1638 | ovs_vport_get_stats(vport, &vport_stats); |
| @@ -1641,6 +1640,9 @@ static int ovs_vport_cmd_fill_info(struct vport *vport, struct sk_buff *skb, | |||
| 1641 | &vport_stats)) | 1640 | &vport_stats)) |
| 1642 | goto nla_put_failure; | 1641 | goto nla_put_failure; |
| 1643 | 1642 | ||
| 1643 | if (ovs_vport_get_upcall_portids(vport, skb)) | ||
| 1644 | goto nla_put_failure; | ||
| 1645 | |||
| 1644 | err = ovs_vport_get_options(vport, skb); | 1646 | err = ovs_vport_get_options(vport, skb); |
| 1645 | if (err == -EMSGSIZE) | 1647 | if (err == -EMSGSIZE) |
| 1646 | goto error; | 1648 | goto error; |
| @@ -1762,7 +1764,7 @@ static int ovs_vport_cmd_new(struct sk_buff *skb, struct genl_info *info) | |||
| 1762 | parms.options = a[OVS_VPORT_ATTR_OPTIONS]; | 1764 | parms.options = a[OVS_VPORT_ATTR_OPTIONS]; |
| 1763 | parms.dp = dp; | 1765 | parms.dp = dp; |
| 1764 | parms.port_no = port_no; | 1766 | parms.port_no = port_no; |
| 1765 | parms.upcall_portid = nla_get_u32(a[OVS_VPORT_ATTR_UPCALL_PID]); | 1767 | parms.upcall_portids = a[OVS_VPORT_ATTR_UPCALL_PID]; |
| 1766 | 1768 | ||
| 1767 | vport = new_vport(&parms); | 1769 | vport = new_vport(&parms); |
| 1768 | err = PTR_ERR(vport); | 1770 | err = PTR_ERR(vport); |
| @@ -1812,8 +1814,14 @@ static int ovs_vport_cmd_set(struct sk_buff *skb, struct genl_info *info) | |||
| 1812 | goto exit_unlock_free; | 1814 | goto exit_unlock_free; |
| 1813 | } | 1815 | } |
| 1814 | 1816 | ||
| 1815 | if (a[OVS_VPORT_ATTR_UPCALL_PID]) | 1817 | |
| 1816 | vport->upcall_portid = nla_get_u32(a[OVS_VPORT_ATTR_UPCALL_PID]); | 1818 | if (a[OVS_VPORT_ATTR_UPCALL_PID]) { |
| 1819 | struct nlattr *ids = a[OVS_VPORT_ATTR_UPCALL_PID]; | ||
| 1820 | |||
| 1821 | err = ovs_vport_set_upcall_portids(vport, ids); | ||
| 1822 | if (err) | ||
| 1823 | goto exit_unlock_free; | ||
| 1824 | } | ||
| 1817 | 1825 | ||
| 1818 | err = ovs_vport_cmd_fill_info(vport, reply, info->snd_portid, | 1826 | err = ovs_vport_cmd_fill_info(vport, reply, info->snd_portid, |
| 1819 | info->snd_seq, 0, OVS_VPORT_CMD_NEW); | 1827 | info->snd_seq, 0, OVS_VPORT_CMD_NEW); |
| @@ -1944,7 +1952,7 @@ static const struct nla_policy vport_policy[OVS_VPORT_ATTR_MAX + 1] = { | |||
| 1944 | [OVS_VPORT_ATTR_OPTIONS] = { .type = NLA_NESTED }, | 1952 | [OVS_VPORT_ATTR_OPTIONS] = { .type = NLA_NESTED }, |
| 1945 | }; | 1953 | }; |
| 1946 | 1954 | ||
| 1947 | static struct genl_ops dp_vport_genl_ops[] = { | 1955 | static const struct genl_ops dp_vport_genl_ops[] = { |
| 1948 | { .cmd = OVS_VPORT_CMD_NEW, | 1956 | { .cmd = OVS_VPORT_CMD_NEW, |
| 1949 | .flags = GENL_ADMIN_PERM, /* Requires CAP_NET_ADMIN privilege. */ | 1957 | .flags = GENL_ADMIN_PERM, /* Requires CAP_NET_ADMIN privilege. */ |
| 1950 | .policy = vport_policy, | 1958 | .policy = vport_policy, |
| @@ -2053,10 +2061,14 @@ static int __init dp_init(void) | |||
| 2053 | 2061 | ||
| 2054 | pr_info("Open vSwitch switching datapath\n"); | 2062 | pr_info("Open vSwitch switching datapath\n"); |
| 2055 | 2063 | ||
| 2056 | err = ovs_flow_init(); | 2064 | err = ovs_internal_dev_rtnl_link_register(); |
| 2057 | if (err) | 2065 | if (err) |
| 2058 | goto error; | 2066 | goto error; |
| 2059 | 2067 | ||
| 2068 | err = ovs_flow_init(); | ||
| 2069 | if (err) | ||
| 2070 | goto error_unreg_rtnl_link; | ||
| 2071 | |||
| 2060 | err = ovs_vport_init(); | 2072 | err = ovs_vport_init(); |
| 2061 | if (err) | 2073 | if (err) |
| 2062 | goto error_flow_exit; | 2074 | goto error_flow_exit; |
| @@ -2083,6 +2095,8 @@ error_vport_exit: | |||
| 2083 | ovs_vport_exit(); | 2095 | ovs_vport_exit(); |
| 2084 | error_flow_exit: | 2096 | error_flow_exit: |
| 2085 | ovs_flow_exit(); | 2097 | ovs_flow_exit(); |
| 2098 | error_unreg_rtnl_link: | ||
| 2099 | ovs_internal_dev_rtnl_link_unregister(); | ||
| 2086 | error: | 2100 | error: |
| 2087 | return err; | 2101 | return err; |
| 2088 | } | 2102 | } |
| @@ -2095,6 +2109,7 @@ static void dp_cleanup(void) | |||
| 2095 | rcu_barrier(); | 2109 | rcu_barrier(); |
| 2096 | ovs_vport_exit(); | 2110 | ovs_vport_exit(); |
| 2097 | ovs_flow_exit(); | 2111 | ovs_flow_exit(); |
| 2112 | ovs_internal_dev_rtnl_link_unregister(); | ||
| 2098 | } | 2113 | } |
| 2099 | 2114 | ||
| 2100 | module_init(dp_init); | 2115 | module_init(dp_init); |
diff --git a/net/openvswitch/datapath.h b/net/openvswitch/datapath.h index 7ede507500d7..701b5738c38a 100644 --- a/net/openvswitch/datapath.h +++ b/net/openvswitch/datapath.h | |||
| @@ -144,7 +144,7 @@ int lockdep_ovsl_is_held(void); | |||
| 144 | #define lockdep_ovsl_is_held() 1 | 144 | #define lockdep_ovsl_is_held() 1 |
| 145 | #endif | 145 | #endif |
| 146 | 146 | ||
| 147 | #define ASSERT_OVSL() WARN_ON(unlikely(!lockdep_ovsl_is_held())) | 147 | #define ASSERT_OVSL() WARN_ON(!lockdep_ovsl_is_held()) |
| 148 | #define ovsl_dereference(p) \ | 148 | #define ovsl_dereference(p) \ |
| 149 | rcu_dereference_protected(p, lockdep_ovsl_is_held()) | 149 | rcu_dereference_protected(p, lockdep_ovsl_is_held()) |
| 150 | #define rcu_dereference_ovsl(p) \ | 150 | #define rcu_dereference_ovsl(p) \ |
diff --git a/net/openvswitch/vport-internal_dev.c b/net/openvswitch/vport-internal_dev.c index 789af9280e77..84516126e5f3 100644 --- a/net/openvswitch/vport-internal_dev.c +++ b/net/openvswitch/vport-internal_dev.c | |||
| @@ -26,6 +26,7 @@ | |||
| 26 | 26 | ||
| 27 | #include <net/dst.h> | 27 | #include <net/dst.h> |
| 28 | #include <net/xfrm.h> | 28 | #include <net/xfrm.h> |
| 29 | #include <net/rtnetlink.h> | ||
| 29 | 30 | ||
| 30 | #include "datapath.h" | 31 | #include "datapath.h" |
| 31 | #include "vport-internal_dev.h" | 32 | #include "vport-internal_dev.h" |
| @@ -121,6 +122,10 @@ static const struct net_device_ops internal_dev_netdev_ops = { | |||
| 121 | .ndo_get_stats64 = internal_dev_get_stats, | 122 | .ndo_get_stats64 = internal_dev_get_stats, |
| 122 | }; | 123 | }; |
| 123 | 124 | ||
| 125 | static struct rtnl_link_ops internal_dev_link_ops __read_mostly = { | ||
| 126 | .kind = "openvswitch", | ||
| 127 | }; | ||
| 128 | |||
| 124 | static void do_setup(struct net_device *netdev) | 129 | static void do_setup(struct net_device *netdev) |
| 125 | { | 130 | { |
| 126 | ether_setup(netdev); | 131 | ether_setup(netdev); |
| @@ -131,14 +136,18 @@ static void do_setup(struct net_device *netdev) | |||
| 131 | netdev->priv_flags |= IFF_LIVE_ADDR_CHANGE; | 136 | netdev->priv_flags |= IFF_LIVE_ADDR_CHANGE; |
| 132 | netdev->destructor = internal_dev_destructor; | 137 | netdev->destructor = internal_dev_destructor; |
| 133 | netdev->ethtool_ops = &internal_dev_ethtool_ops; | 138 | netdev->ethtool_ops = &internal_dev_ethtool_ops; |
| 139 | netdev->rtnl_link_ops = &internal_dev_link_ops; | ||
| 134 | netdev->tx_queue_len = 0; | 140 | netdev->tx_queue_len = 0; |
| 135 | 141 | ||
| 136 | netdev->features = NETIF_F_LLTX | NETIF_F_SG | NETIF_F_FRAGLIST | | 142 | netdev->features = NETIF_F_LLTX | NETIF_F_SG | NETIF_F_FRAGLIST | |
| 137 | NETIF_F_HIGHDMA | NETIF_F_HW_CSUM | NETIF_F_GSO_SOFTWARE; | 143 | NETIF_F_HIGHDMA | NETIF_F_HW_CSUM | |
| 144 | NETIF_F_GSO_SOFTWARE | NETIF_F_GSO_ENCAP_ALL; | ||
| 138 | 145 | ||
| 139 | netdev->vlan_features = netdev->features; | 146 | netdev->vlan_features = netdev->features; |
| 147 | netdev->hw_enc_features = netdev->features; | ||
| 140 | netdev->features |= NETIF_F_HW_VLAN_CTAG_TX; | 148 | netdev->features |= NETIF_F_HW_VLAN_CTAG_TX; |
| 141 | netdev->hw_features = netdev->features & ~NETIF_F_LLTX; | 149 | netdev->hw_features = netdev->features & ~NETIF_F_LLTX; |
| 150 | |||
| 142 | eth_hw_addr_random(netdev); | 151 | eth_hw_addr_random(netdev); |
| 143 | } | 152 | } |
| 144 | 153 | ||
| @@ -159,7 +168,8 @@ static struct vport *internal_dev_create(const struct vport_parms *parms) | |||
| 159 | netdev_vport = netdev_vport_priv(vport); | 168 | netdev_vport = netdev_vport_priv(vport); |
| 160 | 169 | ||
| 161 | netdev_vport->dev = alloc_netdev(sizeof(struct internal_dev), | 170 | netdev_vport->dev = alloc_netdev(sizeof(struct internal_dev), |
| 162 | parms->name, do_setup); | 171 | parms->name, NET_NAME_UNKNOWN, |
| 172 | do_setup); | ||
| 163 | if (!netdev_vport->dev) { | 173 | if (!netdev_vport->dev) { |
| 164 | err = -ENOMEM; | 174 | err = -ENOMEM; |
| 165 | goto error_free_vport; | 175 | goto error_free_vport; |
| @@ -248,3 +258,13 @@ struct vport *ovs_internal_dev_get_vport(struct net_device *netdev) | |||
| 248 | 258 | ||
| 249 | return internal_dev_priv(netdev)->vport; | 259 | return internal_dev_priv(netdev)->vport; |
| 250 | } | 260 | } |
| 261 | |||
| 262 | int ovs_internal_dev_rtnl_link_register(void) | ||
| 263 | { | ||
| 264 | return rtnl_link_register(&internal_dev_link_ops); | ||
| 265 | } | ||
| 266 | |||
| 267 | void ovs_internal_dev_rtnl_link_unregister(void) | ||
| 268 | { | ||
| 269 | rtnl_link_unregister(&internal_dev_link_ops); | ||
| 270 | } | ||
diff --git a/net/openvswitch/vport-internal_dev.h b/net/openvswitch/vport-internal_dev.h index 9a7d30ecc6a2..1b179a190cff 100644 --- a/net/openvswitch/vport-internal_dev.h +++ b/net/openvswitch/vport-internal_dev.h | |||
| @@ -24,5 +24,7 @@ | |||
| 24 | 24 | ||
| 25 | int ovs_is_internal_dev(const struct net_device *); | 25 | int ovs_is_internal_dev(const struct net_device *); |
| 26 | struct vport *ovs_internal_dev_get_vport(struct net_device *); | 26 | struct vport *ovs_internal_dev_get_vport(struct net_device *); |
| 27 | int ovs_internal_dev_rtnl_link_register(void); | ||
| 28 | void ovs_internal_dev_rtnl_link_unregister(void); | ||
| 27 | 29 | ||
| 28 | #endif /* vport-internal_dev.h */ | 30 | #endif /* vport-internal_dev.h */ |
diff --git a/net/openvswitch/vport-vxlan.c b/net/openvswitch/vport-vxlan.c index 0edbd95c60e7..d8b7e247bebf 100644 --- a/net/openvswitch/vport-vxlan.c +++ b/net/openvswitch/vport-vxlan.c | |||
| @@ -143,8 +143,6 @@ static int vxlan_tnl_send(struct vport *vport, struct sk_buff *skb) | |||
| 143 | struct rtable *rt; | 143 | struct rtable *rt; |
| 144 | struct flowi4 fl; | 144 | struct flowi4 fl; |
| 145 | __be16 src_port; | 145 | __be16 src_port; |
| 146 | int port_min; | ||
| 147 | int port_max; | ||
| 148 | __be16 df; | 146 | __be16 df; |
| 149 | int err; | 147 | int err; |
| 150 | 148 | ||
| @@ -172,8 +170,7 @@ static int vxlan_tnl_send(struct vport *vport, struct sk_buff *skb) | |||
| 172 | 170 | ||
| 173 | skb->ignore_df = 1; | 171 | skb->ignore_df = 1; |
| 174 | 172 | ||
| 175 | inet_get_local_port_range(net, &port_min, &port_max); | 173 | src_port = udp_flow_src_port(net, skb, 0, 0, true); |
| 176 | src_port = vxlan_src_port(port_min, port_max, skb); | ||
| 177 | 174 | ||
| 178 | err = vxlan_xmit_skb(vxlan_port->vs, rt, skb, | 175 | err = vxlan_xmit_skb(vxlan_port->vs, rt, skb, |
| 179 | fl.saddr, OVS_CB(skb)->tun_key->ipv4_dst, | 176 | fl.saddr, OVS_CB(skb)->tun_key->ipv4_dst, |
diff --git a/net/openvswitch/vport.c b/net/openvswitch/vport.c index 42c0f4a0b78c..6d8f2ec481d9 100644 --- a/net/openvswitch/vport.c +++ b/net/openvswitch/vport.c | |||
| @@ -134,10 +134,14 @@ struct vport *ovs_vport_alloc(int priv_size, const struct vport_ops *ops, | |||
| 134 | 134 | ||
| 135 | vport->dp = parms->dp; | 135 | vport->dp = parms->dp; |
| 136 | vport->port_no = parms->port_no; | 136 | vport->port_no = parms->port_no; |
| 137 | vport->upcall_portid = parms->upcall_portid; | ||
| 138 | vport->ops = ops; | 137 | vport->ops = ops; |
| 139 | INIT_HLIST_NODE(&vport->dp_hash_node); | 138 | INIT_HLIST_NODE(&vport->dp_hash_node); |
| 140 | 139 | ||
| 140 | if (ovs_vport_set_upcall_portids(vport, parms->upcall_portids)) { | ||
| 141 | kfree(vport); | ||
| 142 | return ERR_PTR(-EINVAL); | ||
| 143 | } | ||
| 144 | |||
| 141 | vport->percpu_stats = netdev_alloc_pcpu_stats(struct pcpu_sw_netstats); | 145 | vport->percpu_stats = netdev_alloc_pcpu_stats(struct pcpu_sw_netstats); |
| 142 | if (!vport->percpu_stats) { | 146 | if (!vport->percpu_stats) { |
| 143 | kfree(vport); | 147 | kfree(vport); |
| @@ -161,6 +165,10 @@ struct vport *ovs_vport_alloc(int priv_size, const struct vport_ops *ops, | |||
| 161 | */ | 165 | */ |
| 162 | void ovs_vport_free(struct vport *vport) | 166 | void ovs_vport_free(struct vport *vport) |
| 163 | { | 167 | { |
| 168 | /* vport is freed from RCU callback or error path, Therefore | ||
| 169 | * it is safe to use raw dereference. | ||
| 170 | */ | ||
| 171 | kfree(rcu_dereference_raw(vport->upcall_portids)); | ||
| 164 | free_percpu(vport->percpu_stats); | 172 | free_percpu(vport->percpu_stats); |
| 165 | kfree(vport); | 173 | kfree(vport); |
| 166 | } | 174 | } |
| @@ -327,6 +335,99 @@ int ovs_vport_get_options(const struct vport *vport, struct sk_buff *skb) | |||
| 327 | } | 335 | } |
| 328 | 336 | ||
| 329 | /** | 337 | /** |
| 338 | * ovs_vport_set_upcall_portids - set upcall portids of @vport. | ||
| 339 | * | ||
| 340 | * @vport: vport to modify. | ||
| 341 | * @ids: new configuration, an array of port ids. | ||
| 342 | * | ||
| 343 | * Sets the vport's upcall_portids to @ids. | ||
| 344 | * | ||
| 345 | * Returns 0 if successful, -EINVAL if @ids is zero length or cannot be parsed | ||
| 346 | * as an array of U32. | ||
| 347 | * | ||
| 348 | * Must be called with ovs_mutex. | ||
| 349 | */ | ||
| 350 | int ovs_vport_set_upcall_portids(struct vport *vport, struct nlattr *ids) | ||
| 351 | { | ||
| 352 | struct vport_portids *old, *vport_portids; | ||
| 353 | |||
| 354 | if (!nla_len(ids) || nla_len(ids) % sizeof(u32)) | ||
| 355 | return -EINVAL; | ||
| 356 | |||
| 357 | old = ovsl_dereference(vport->upcall_portids); | ||
| 358 | |||
| 359 | vport_portids = kmalloc(sizeof(*vport_portids) + nla_len(ids), | ||
| 360 | GFP_KERNEL); | ||
| 361 | if (!vport_portids) | ||
| 362 | return -ENOMEM; | ||
| 363 | |||
| 364 | vport_portids->n_ids = nla_len(ids) / sizeof(u32); | ||
| 365 | vport_portids->rn_ids = reciprocal_value(vport_portids->n_ids); | ||
| 366 | nla_memcpy(vport_portids->ids, ids, nla_len(ids)); | ||
| 367 | |||
| 368 | rcu_assign_pointer(vport->upcall_portids, vport_portids); | ||
| 369 | |||
| 370 | if (old) | ||
| 371 | kfree_rcu(old, rcu); | ||
| 372 | return 0; | ||
| 373 | } | ||
| 374 | |||
| 375 | /** | ||
| 376 | * ovs_vport_get_upcall_portids - get the upcall_portids of @vport. | ||
| 377 | * | ||
| 378 | * @vport: vport from which to retrieve the portids. | ||
| 379 | * @skb: sk_buff where portids should be appended. | ||
| 380 | * | ||
| 381 | * Retrieves the configuration of the given vport, appending the | ||
| 382 | * %OVS_VPORT_ATTR_UPCALL_PID attribute which is the array of upcall | ||
| 383 | * portids to @skb. | ||
| 384 | * | ||
| 385 | * Returns 0 if successful, -EMSGSIZE if @skb has insufficient room. | ||
| 386 | * If an error occurs, @skb is left unmodified. Must be called with | ||
| 387 | * ovs_mutex or rcu_read_lock. | ||
| 388 | */ | ||
| 389 | int ovs_vport_get_upcall_portids(const struct vport *vport, | ||
| 390 | struct sk_buff *skb) | ||
| 391 | { | ||
| 392 | struct vport_portids *ids; | ||
| 393 | |||
| 394 | ids = rcu_dereference_ovsl(vport->upcall_portids); | ||
| 395 | |||
| 396 | if (vport->dp->user_features & OVS_DP_F_VPORT_PIDS) | ||
| 397 | return nla_put(skb, OVS_VPORT_ATTR_UPCALL_PID, | ||
| 398 | ids->n_ids * sizeof(u32), (void *)ids->ids); | ||
| 399 | else | ||
| 400 | return nla_put_u32(skb, OVS_VPORT_ATTR_UPCALL_PID, ids->ids[0]); | ||
| 401 | } | ||
| 402 | |||
| 403 | /** | ||
| 404 | * ovs_vport_find_upcall_portid - find the upcall portid to send upcall. | ||
| 405 | * | ||
| 406 | * @vport: vport from which the missed packet is received. | ||
| 407 | * @skb: skb that the missed packet was received. | ||
| 408 | * | ||
| 409 | * Uses the skb_get_hash() to select the upcall portid to send the | ||
| 410 | * upcall. | ||
| 411 | * | ||
| 412 | * Returns the portid of the target socket. Must be called with rcu_read_lock. | ||
| 413 | */ | ||
| 414 | u32 ovs_vport_find_upcall_portid(const struct vport *p, struct sk_buff *skb) | ||
| 415 | { | ||
| 416 | struct vport_portids *ids; | ||
| 417 | u32 ids_index; | ||
| 418 | u32 hash; | ||
| 419 | |||
| 420 | ids = rcu_dereference(p->upcall_portids); | ||
| 421 | |||
| 422 | if (ids->n_ids == 1 && ids->ids[0] == 0) | ||
| 423 | return 0; | ||
| 424 | |||
| 425 | hash = skb_get_hash(skb); | ||
| 426 | ids_index = hash - ids->n_ids * reciprocal_divide(hash, ids->rn_ids); | ||
| 427 | return ids->ids[ids_index]; | ||
| 428 | } | ||
| 429 | |||
| 430 | /** | ||
| 330 | * ovs_vport_receive - pass up received packet to the datapath for processing | 431 | * ovs_vport_receive - pass up received packet to the datapath for processing |
| 331 | * | 432 | * |
| 332 | * @vport: vport that received the packet | 433 | * @vport: vport that received the packet |
diff --git a/net/openvswitch/vport.h b/net/openvswitch/vport.h index 8d721e62f388..35f89d84b45e 100644 --- a/net/openvswitch/vport.h +++ b/net/openvswitch/vport.h | |||
| @@ -23,6 +23,7 @@ | |||
| 23 | #include <linux/list.h> | 23 | #include <linux/list.h> |
| 24 | #include <linux/netlink.h> | 24 | #include <linux/netlink.h> |
| 25 | #include <linux/openvswitch.h> | 25 | #include <linux/openvswitch.h> |
| 26 | #include <linux/reciprocal_div.h> | ||
| 26 | #include <linux/skbuff.h> | 27 | #include <linux/skbuff.h> |
| 27 | #include <linux/spinlock.h> | 28 | #include <linux/spinlock.h> |
| 28 | #include <linux/u64_stats_sync.h> | 29 | #include <linux/u64_stats_sync.h> |
| @@ -52,6 +53,10 @@ void ovs_vport_get_stats(struct vport *, struct ovs_vport_stats *); | |||
| 52 | int ovs_vport_set_options(struct vport *, struct nlattr *options); | 53 | int ovs_vport_set_options(struct vport *, struct nlattr *options); |
| 53 | int ovs_vport_get_options(const struct vport *, struct sk_buff *); | 54 | int ovs_vport_get_options(const struct vport *, struct sk_buff *); |
| 54 | 55 | ||
| 56 | int ovs_vport_set_upcall_portids(struct vport *, struct nlattr *pids); | ||
| 57 | int ovs_vport_get_upcall_portids(const struct vport *, struct sk_buff *); | ||
| 58 | u32 ovs_vport_find_upcall_portid(const struct vport *, struct sk_buff *); | ||
| 59 | |||
| 55 | int ovs_vport_send(struct vport *, struct sk_buff *); | 60 | int ovs_vport_send(struct vport *, struct sk_buff *); |
| 56 | 61 | ||
| 57 | /* The following definitions are for implementers of vport devices: */ | 62 | /* The following definitions are for implementers of vport devices: */ |
| @@ -62,13 +67,27 @@ struct vport_err_stats { | |||
| 62 | u64 tx_dropped; | 67 | u64 tx_dropped; |
| 63 | u64 tx_errors; | 68 | u64 tx_errors; |
| 64 | }; | 69 | }; |
| 70 | /** | ||
| 71 | * struct vport_portids - array of netlink portids of a vport. | ||
| 72 | * must be protected by rcu. | ||
| 73 | * @rn_ids: The reciprocal value of @n_ids. | ||
| 74 | * @rcu: RCU callback head for deferred destruction. | ||
| 75 | * @n_ids: Size of @ids array. | ||
| 76 | * @ids: Array storing the Netlink socket pids to be used for packets received | ||
| 77 | * on this port that miss the flow table. | ||
| 78 | */ | ||
| 79 | struct vport_portids { | ||
| 80 | struct reciprocal_value rn_ids; | ||
| 81 | struct rcu_head rcu; | ||
| 82 | u32 n_ids; | ||
| 83 | u32 ids[]; | ||
| 84 | }; | ||
| 65 | 85 | ||
| 66 | /** | 86 | /** |
| 67 | * struct vport - one port within a datapath | 87 | * struct vport - one port within a datapath |
| 68 | * @rcu: RCU callback head for deferred destruction. | 88 | * @rcu: RCU callback head for deferred destruction. |
| 69 | * @dp: Datapath to which this port belongs. | 89 | * @dp: Datapath to which this port belongs. |
| 70 | * @upcall_portid: The Netlink port to use for packets received on this port that | 90 | * @upcall_portids: RCU protected 'struct vport_portids'. |
| 71 | * miss the flow table. | ||
| 72 | * @port_no: Index into @dp's @ports array. | 91 | * @port_no: Index into @dp's @ports array. |
| 73 | * @hash_node: Element in @dev_table hash table in vport.c. | 92 | * @hash_node: Element in @dev_table hash table in vport.c. |
| 74 | * @dp_hash_node: Element in @datapath->ports hash table in datapath.c. | 93 | * @dp_hash_node: Element in @datapath->ports hash table in datapath.c. |
| @@ -80,7 +99,7 @@ struct vport_err_stats { | |||
| 80 | struct vport { | 99 | struct vport { |
| 81 | struct rcu_head rcu; | 100 | struct rcu_head rcu; |
| 82 | struct datapath *dp; | 101 | struct datapath *dp; |
| 83 | u32 upcall_portid; | 102 | struct vport_portids __rcu *upcall_portids; |
| 84 | u16 port_no; | 103 | u16 port_no; |
| 85 | 104 | ||
| 86 | struct hlist_node hash_node; | 105 | struct hlist_node hash_node; |
| @@ -111,7 +130,7 @@ struct vport_parms { | |||
| 111 | /* For ovs_vport_alloc(). */ | 130 | /* For ovs_vport_alloc(). */ |
| 112 | struct datapath *dp; | 131 | struct datapath *dp; |
| 113 | u16 port_no; | 132 | u16 port_no; |
| 114 | u32 upcall_portid; | 133 | struct nlattr *upcall_portids; |
| 115 | }; | 134 | }; |
| 116 | 135 | ||
| 117 | /** | 136 | /** |
diff --git a/net/packet/af_packet.c b/net/packet/af_packet.c index b85c67ccb797..8d9f8042705a 100644 --- a/net/packet/af_packet.c +++ b/net/packet/af_packet.c | |||
| @@ -441,14 +441,10 @@ static __u32 tpacket_get_timestamp(struct sk_buff *skb, struct timespec *ts, | |||
| 441 | { | 441 | { |
| 442 | struct skb_shared_hwtstamps *shhwtstamps = skb_hwtstamps(skb); | 442 | struct skb_shared_hwtstamps *shhwtstamps = skb_hwtstamps(skb); |
| 443 | 443 | ||
| 444 | if (shhwtstamps) { | 444 | if (shhwtstamps && |
| 445 | if ((flags & SOF_TIMESTAMPING_SYS_HARDWARE) && | 445 | (flags & SOF_TIMESTAMPING_RAW_HARDWARE) && |
| 446 | ktime_to_timespec_cond(shhwtstamps->syststamp, ts)) | 446 | ktime_to_timespec_cond(shhwtstamps->hwtstamp, ts)) |
| 447 | return TP_STATUS_TS_SYS_HARDWARE; | 447 | return TP_STATUS_TS_RAW_HARDWARE; |
| 448 | if ((flags & SOF_TIMESTAMPING_RAW_HARDWARE) && | ||
| 449 | ktime_to_timespec_cond(shhwtstamps->hwtstamp, ts)) | ||
| 450 | return TP_STATUS_TS_RAW_HARDWARE; | ||
| 451 | } | ||
| 452 | 448 | ||
| 453 | if (ktime_to_timespec_cond(skb->tstamp, ts)) | 449 | if (ktime_to_timespec_cond(skb->tstamp, ts)) |
| 454 | return TP_STATUS_TS_SOFTWARE; | 450 | return TP_STATUS_TS_SOFTWARE; |
| @@ -3071,10 +3067,8 @@ static int packet_dev_mc(struct net_device *dev, struct packet_mclist *i, | |||
| 3071 | break; | 3067 | break; |
| 3072 | case PACKET_MR_PROMISC: | 3068 | case PACKET_MR_PROMISC: |
| 3073 | return dev_set_promiscuity(dev, what); | 3069 | return dev_set_promiscuity(dev, what); |
| 3074 | break; | ||
| 3075 | case PACKET_MR_ALLMULTI: | 3070 | case PACKET_MR_ALLMULTI: |
| 3076 | return dev_set_allmulti(dev, what); | 3071 | return dev_set_allmulti(dev, what); |
| 3077 | break; | ||
| 3078 | case PACKET_MR_UNICAST: | 3072 | case PACKET_MR_UNICAST: |
| 3079 | if (i->alen != dev->addr_len) | 3073 | if (i->alen != dev->addr_len) |
| 3080 | return -EINVAL; | 3074 | return -EINVAL; |
diff --git a/net/phonet/pep-gprs.c b/net/phonet/pep-gprs.c index 66dc65e7c6a1..e9a83a637185 100644 --- a/net/phonet/pep-gprs.c +++ b/net/phonet/pep-gprs.c | |||
| @@ -267,7 +267,7 @@ int gprs_attach(struct sock *sk) | |||
| 267 | return -EINVAL; /* need packet boundaries */ | 267 | return -EINVAL; /* need packet boundaries */ |
| 268 | 268 | ||
| 269 | /* Create net device */ | 269 | /* Create net device */ |
| 270 | dev = alloc_netdev(sizeof(*gp), ifname, gprs_setup); | 270 | dev = alloc_netdev(sizeof(*gp), ifname, NET_NAME_UNKNOWN, gprs_setup); |
| 271 | if (!dev) | 271 | if (!dev) |
| 272 | return -ENOMEM; | 272 | return -ENOMEM; |
| 273 | gp = netdev_priv(dev); | 273 | gp = netdev_priv(dev); |
diff --git a/net/rose/af_rose.c b/net/rose/af_rose.c index 8451c8cdc9de..a85c1a086ae4 100644 --- a/net/rose/af_rose.c +++ b/net/rose/af_rose.c | |||
| @@ -1538,7 +1538,7 @@ static int __init rose_proto_init(void) | |||
| 1538 | char name[IFNAMSIZ]; | 1538 | char name[IFNAMSIZ]; |
| 1539 | 1539 | ||
| 1540 | sprintf(name, "rose%d", i); | 1540 | sprintf(name, "rose%d", i); |
| 1541 | dev = alloc_netdev(0, name, rose_setup); | 1541 | dev = alloc_netdev(0, name, NET_NAME_UNKNOWN, rose_setup); |
| 1542 | if (!dev) { | 1542 | if (!dev) { |
| 1543 | printk(KERN_ERR "ROSE: rose_proto_init - unable to allocate memory\n"); | 1543 | printk(KERN_ERR "ROSE: rose_proto_init - unable to allocate memory\n"); |
| 1544 | rc = -ENOMEM; | 1544 | rc = -ENOMEM; |
diff --git a/net/rxrpc/ar-key.c b/net/rxrpc/ar-key.c index 0ad080790a32..b45d080e64a7 100644 --- a/net/rxrpc/ar-key.c +++ b/net/rxrpc/ar-key.c | |||
| @@ -26,8 +26,10 @@ | |||
| 26 | #include "ar-internal.h" | 26 | #include "ar-internal.h" |
| 27 | 27 | ||
| 28 | static int rxrpc_vet_description_s(const char *); | 28 | static int rxrpc_vet_description_s(const char *); |
| 29 | static int rxrpc_instantiate(struct key *, struct key_preparsed_payload *); | 29 | static int rxrpc_preparse(struct key_preparsed_payload *); |
| 30 | static int rxrpc_instantiate_s(struct key *, struct key_preparsed_payload *); | 30 | static int rxrpc_preparse_s(struct key_preparsed_payload *); |
| 31 | static void rxrpc_free_preparse(struct key_preparsed_payload *); | ||
| 32 | static void rxrpc_free_preparse_s(struct key_preparsed_payload *); | ||
| 31 | static void rxrpc_destroy(struct key *); | 33 | static void rxrpc_destroy(struct key *); |
| 32 | static void rxrpc_destroy_s(struct key *); | 34 | static void rxrpc_destroy_s(struct key *); |
| 33 | static void rxrpc_describe(const struct key *, struct seq_file *); | 35 | static void rxrpc_describe(const struct key *, struct seq_file *); |
| @@ -39,7 +41,9 @@ static long rxrpc_read(const struct key *, char __user *, size_t); | |||
| 39 | */ | 41 | */ |
| 40 | struct key_type key_type_rxrpc = { | 42 | struct key_type key_type_rxrpc = { |
| 41 | .name = "rxrpc", | 43 | .name = "rxrpc", |
| 42 | .instantiate = rxrpc_instantiate, | 44 | .preparse = rxrpc_preparse, |
| 45 | .free_preparse = rxrpc_free_preparse, | ||
| 46 | .instantiate = generic_key_instantiate, | ||
| 43 | .match = user_match, | 47 | .match = user_match, |
| 44 | .destroy = rxrpc_destroy, | 48 | .destroy = rxrpc_destroy, |
| 45 | .describe = rxrpc_describe, | 49 | .describe = rxrpc_describe, |
| @@ -54,7 +58,9 @@ EXPORT_SYMBOL(key_type_rxrpc); | |||
| 54 | struct key_type key_type_rxrpc_s = { | 58 | struct key_type key_type_rxrpc_s = { |
| 55 | .name = "rxrpc_s", | 59 | .name = "rxrpc_s", |
| 56 | .vet_description = rxrpc_vet_description_s, | 60 | .vet_description = rxrpc_vet_description_s, |
| 57 | .instantiate = rxrpc_instantiate_s, | 61 | .preparse = rxrpc_preparse_s, |
| 62 | .free_preparse = rxrpc_free_preparse_s, | ||
| 63 | .instantiate = generic_key_instantiate, | ||
| 58 | .match = user_match, | 64 | .match = user_match, |
| 59 | .destroy = rxrpc_destroy_s, | 65 | .destroy = rxrpc_destroy_s, |
| 60 | .describe = rxrpc_describe, | 66 | .describe = rxrpc_describe, |
| @@ -81,13 +87,13 @@ static int rxrpc_vet_description_s(const char *desc) | |||
| 81 | * parse an RxKAD type XDR format token | 87 | * parse an RxKAD type XDR format token |
| 82 | * - the caller guarantees we have at least 4 words | 88 | * - the caller guarantees we have at least 4 words |
| 83 | */ | 89 | */ |
| 84 | static int rxrpc_instantiate_xdr_rxkad(struct key *key, const __be32 *xdr, | 90 | static int rxrpc_preparse_xdr_rxkad(struct key_preparsed_payload *prep, |
| 85 | unsigned int toklen) | 91 | size_t datalen, |
| 92 | const __be32 *xdr, unsigned int toklen) | ||
| 86 | { | 93 | { |
| 87 | struct rxrpc_key_token *token, **pptoken; | 94 | struct rxrpc_key_token *token, **pptoken; |
| 88 | size_t plen; | 95 | size_t plen; |
| 89 | u32 tktlen; | 96 | u32 tktlen; |
| 90 | int ret; | ||
| 91 | 97 | ||
| 92 | _enter(",{%x,%x,%x,%x},%u", | 98 | _enter(",{%x,%x,%x,%x},%u", |
| 93 | ntohl(xdr[0]), ntohl(xdr[1]), ntohl(xdr[2]), ntohl(xdr[3]), | 99 | ntohl(xdr[0]), ntohl(xdr[1]), ntohl(xdr[2]), ntohl(xdr[3]), |
| @@ -103,9 +109,7 @@ static int rxrpc_instantiate_xdr_rxkad(struct key *key, const __be32 *xdr, | |||
| 103 | return -EKEYREJECTED; | 109 | return -EKEYREJECTED; |
| 104 | 110 | ||
| 105 | plen = sizeof(*token) + sizeof(*token->kad) + tktlen; | 111 | plen = sizeof(*token) + sizeof(*token->kad) + tktlen; |
| 106 | ret = key_payload_reserve(key, key->datalen + plen); | 112 | prep->quotalen = datalen + plen; |
| 107 | if (ret < 0) | ||
| 108 | return ret; | ||
| 109 | 113 | ||
| 110 | plen -= sizeof(*token); | 114 | plen -= sizeof(*token); |
| 111 | token = kzalloc(sizeof(*token), GFP_KERNEL); | 115 | token = kzalloc(sizeof(*token), GFP_KERNEL); |
| @@ -146,16 +150,16 @@ static int rxrpc_instantiate_xdr_rxkad(struct key *key, const __be32 *xdr, | |||
| 146 | token->kad->ticket[6], token->kad->ticket[7]); | 150 | token->kad->ticket[6], token->kad->ticket[7]); |
| 147 | 151 | ||
| 148 | /* count the number of tokens attached */ | 152 | /* count the number of tokens attached */ |
| 149 | key->type_data.x[0]++; | 153 | prep->type_data[0] = (void *)((unsigned long)prep->type_data[0] + 1); |
| 150 | 154 | ||
| 151 | /* attach the data */ | 155 | /* attach the data */ |
| 152 | for (pptoken = (struct rxrpc_key_token **)&key->payload.data; | 156 | for (pptoken = (struct rxrpc_key_token **)&prep->payload[0]; |
| 153 | *pptoken; | 157 | *pptoken; |
| 154 | pptoken = &(*pptoken)->next) | 158 | pptoken = &(*pptoken)->next) |
| 155 | continue; | 159 | continue; |
| 156 | *pptoken = token; | 160 | *pptoken = token; |
| 157 | if (token->kad->expiry < key->expiry) | 161 | if (token->kad->expiry < prep->expiry) |
| 158 | key->expiry = token->kad->expiry; | 162 | prep->expiry = token->kad->expiry; |
| 159 | 163 | ||
| 160 | _leave(" = 0"); | 164 | _leave(" = 0"); |
| 161 | return 0; | 165 | return 0; |
| @@ -346,7 +350,7 @@ static int rxrpc_krb5_decode_tagged_array(struct krb5_tagged_data **_td, | |||
| 346 | 350 | ||
| 347 | n_elem = ntohl(*xdr++); | 351 | n_elem = ntohl(*xdr++); |
| 348 | toklen -= 4; | 352 | toklen -= 4; |
| 349 | if (n_elem < 0 || n_elem > max_n_elem) | 353 | if (n_elem > max_n_elem) |
| 350 | return -EINVAL; | 354 | return -EINVAL; |
| 351 | *_n_elem = n_elem; | 355 | *_n_elem = n_elem; |
| 352 | if (n_elem > 0) { | 356 | if (n_elem > 0) { |
| @@ -418,8 +422,9 @@ static int rxrpc_krb5_decode_ticket(u8 **_ticket, u16 *_tktlen, | |||
| 418 | * parse an RxK5 type XDR format token | 422 | * parse an RxK5 type XDR format token |
| 419 | * - the caller guarantees we have at least 4 words | 423 | * - the caller guarantees we have at least 4 words |
| 420 | */ | 424 | */ |
| 421 | static int rxrpc_instantiate_xdr_rxk5(struct key *key, const __be32 *xdr, | 425 | static int rxrpc_preparse_xdr_rxk5(struct key_preparsed_payload *prep, |
| 422 | unsigned int toklen) | 426 | size_t datalen, |
| 427 | const __be32 *xdr, unsigned int toklen) | ||
| 423 | { | 428 | { |
| 424 | struct rxrpc_key_token *token, **pptoken; | 429 | struct rxrpc_key_token *token, **pptoken; |
| 425 | struct rxk5_key *rxk5; | 430 | struct rxk5_key *rxk5; |
| @@ -432,9 +437,7 @@ static int rxrpc_instantiate_xdr_rxk5(struct key *key, const __be32 *xdr, | |||
| 432 | 437 | ||
| 433 | /* reserve some payload space for this subkey - the length of the token | 438 | /* reserve some payload space for this subkey - the length of the token |
| 434 | * is a reasonable approximation */ | 439 | * is a reasonable approximation */ |
| 435 | ret = key_payload_reserve(key, key->datalen + toklen); | 440 | prep->quotalen = datalen + toklen; |
| 436 | if (ret < 0) | ||
| 437 | return ret; | ||
| 438 | 441 | ||
| 439 | token = kzalloc(sizeof(*token), GFP_KERNEL); | 442 | token = kzalloc(sizeof(*token), GFP_KERNEL); |
| 440 | if (!token) | 443 | if (!token) |
| @@ -520,14 +523,14 @@ static int rxrpc_instantiate_xdr_rxk5(struct key *key, const __be32 *xdr, | |||
| 520 | if (toklen != 0) | 523 | if (toklen != 0) |
| 521 | goto inval; | 524 | goto inval; |
| 522 | 525 | ||
| 523 | /* attach the payload to the key */ | 526 | /* attach the payload */ |
| 524 | for (pptoken = (struct rxrpc_key_token **)&key->payload.data; | 527 | for (pptoken = (struct rxrpc_key_token **)&prep->payload[0]; |
| 525 | *pptoken; | 528 | *pptoken; |
| 526 | pptoken = &(*pptoken)->next) | 529 | pptoken = &(*pptoken)->next) |
| 527 | continue; | 530 | continue; |
| 528 | *pptoken = token; | 531 | *pptoken = token; |
| 529 | if (token->kad->expiry < key->expiry) | 532 | if (token->kad->expiry < prep->expiry) |
| 530 | key->expiry = token->kad->expiry; | 533 | prep->expiry = token->kad->expiry; |
| 531 | 534 | ||
| 532 | _leave(" = 0"); | 535 | _leave(" = 0"); |
| 533 | return 0; | 536 | return 0; |
| @@ -545,16 +548,17 @@ error: | |||
| 545 | * attempt to parse the data as the XDR format | 548 | * attempt to parse the data as the XDR format |
| 546 | * - the caller guarantees we have more than 7 words | 549 | * - the caller guarantees we have more than 7 words |
| 547 | */ | 550 | */ |
| 548 | static int rxrpc_instantiate_xdr(struct key *key, const void *data, size_t datalen) | 551 | static int rxrpc_preparse_xdr(struct key_preparsed_payload *prep) |
| 549 | { | 552 | { |
| 550 | const __be32 *xdr = data, *token; | 553 | const __be32 *xdr = prep->data, *token; |
| 551 | const char *cp; | 554 | const char *cp; |
| 552 | unsigned int len, tmp, loop, ntoken, toklen, sec_ix; | 555 | unsigned int len, tmp, loop, ntoken, toklen, sec_ix; |
| 556 | size_t datalen = prep->datalen; | ||
| 553 | int ret; | 557 | int ret; |
| 554 | 558 | ||
| 555 | _enter(",{%x,%x,%x,%x},%zu", | 559 | _enter(",{%x,%x,%x,%x},%zu", |
| 556 | ntohl(xdr[0]), ntohl(xdr[1]), ntohl(xdr[2]), ntohl(xdr[3]), | 560 | ntohl(xdr[0]), ntohl(xdr[1]), ntohl(xdr[2]), ntohl(xdr[3]), |
| 557 | datalen); | 561 | prep->datalen); |
| 558 | 562 | ||
| 559 | if (datalen > AFSTOKEN_LENGTH_MAX) | 563 | if (datalen > AFSTOKEN_LENGTH_MAX) |
| 560 | goto not_xdr; | 564 | goto not_xdr; |
| @@ -635,13 +639,13 @@ static int rxrpc_instantiate_xdr(struct key *key, const void *data, size_t datal | |||
| 635 | 639 | ||
| 636 | switch (sec_ix) { | 640 | switch (sec_ix) { |
| 637 | case RXRPC_SECURITY_RXKAD: | 641 | case RXRPC_SECURITY_RXKAD: |
| 638 | ret = rxrpc_instantiate_xdr_rxkad(key, xdr, toklen); | 642 | ret = rxrpc_preparse_xdr_rxkad(prep, datalen, xdr, toklen); |
| 639 | if (ret != 0) | 643 | if (ret != 0) |
| 640 | goto error; | 644 | goto error; |
| 641 | break; | 645 | break; |
| 642 | 646 | ||
| 643 | case RXRPC_SECURITY_RXK5: | 647 | case RXRPC_SECURITY_RXK5: |
| 644 | ret = rxrpc_instantiate_xdr_rxk5(key, xdr, toklen); | 648 | ret = rxrpc_preparse_xdr_rxk5(prep, datalen, xdr, toklen); |
| 645 | if (ret != 0) | 649 | if (ret != 0) |
| 646 | goto error; | 650 | goto error; |
| 647 | break; | 651 | break; |
| @@ -665,8 +669,9 @@ error: | |||
| 665 | } | 669 | } |
| 666 | 670 | ||
| 667 | /* | 671 | /* |
| 668 | * instantiate an rxrpc defined key | 672 | * Preparse an rxrpc defined key. |
| 669 | * data should be of the form: | 673 | * |
| 674 | * Data should be of the form: | ||
| 670 | * OFFSET LEN CONTENT | 675 | * OFFSET LEN CONTENT |
| 671 | * 0 4 key interface version number | 676 | * 0 4 key interface version number |
| 672 | * 4 2 security index (type) | 677 | * 4 2 security index (type) |
| @@ -678,7 +683,7 @@ error: | |||
| 678 | * | 683 | * |
| 679 | * if no data is provided, then a no-security key is made | 684 | * if no data is provided, then a no-security key is made |
| 680 | */ | 685 | */ |
| 681 | static int rxrpc_instantiate(struct key *key, struct key_preparsed_payload *prep) | 686 | static int rxrpc_preparse(struct key_preparsed_payload *prep) |
| 682 | { | 687 | { |
| 683 | const struct rxrpc_key_data_v1 *v1; | 688 | const struct rxrpc_key_data_v1 *v1; |
| 684 | struct rxrpc_key_token *token, **pp; | 689 | struct rxrpc_key_token *token, **pp; |
| @@ -686,7 +691,7 @@ static int rxrpc_instantiate(struct key *key, struct key_preparsed_payload *prep | |||
| 686 | u32 kver; | 691 | u32 kver; |
| 687 | int ret; | 692 | int ret; |
| 688 | 693 | ||
| 689 | _enter("{%x},,%zu", key_serial(key), prep->datalen); | 694 | _enter("%zu", prep->datalen); |
| 690 | 695 | ||
| 691 | /* handle a no-security key */ | 696 | /* handle a no-security key */ |
| 692 | if (!prep->data && prep->datalen == 0) | 697 | if (!prep->data && prep->datalen == 0) |
| @@ -694,7 +699,7 @@ static int rxrpc_instantiate(struct key *key, struct key_preparsed_payload *prep | |||
| 694 | 699 | ||
| 695 | /* determine if the XDR payload format is being used */ | 700 | /* determine if the XDR payload format is being used */ |
| 696 | if (prep->datalen > 7 * 4) { | 701 | if (prep->datalen > 7 * 4) { |
| 697 | ret = rxrpc_instantiate_xdr(key, prep->data, prep->datalen); | 702 | ret = rxrpc_preparse_xdr(prep); |
| 698 | if (ret != -EPROTO) | 703 | if (ret != -EPROTO) |
| 699 | return ret; | 704 | return ret; |
| 700 | } | 705 | } |
| @@ -743,9 +748,7 @@ static int rxrpc_instantiate(struct key *key, struct key_preparsed_payload *prep | |||
| 743 | goto error; | 748 | goto error; |
| 744 | 749 | ||
| 745 | plen = sizeof(*token->kad) + v1->ticket_length; | 750 | plen = sizeof(*token->kad) + v1->ticket_length; |
| 746 | ret = key_payload_reserve(key, plen + sizeof(*token)); | 751 | prep->quotalen = plen + sizeof(*token); |
| 747 | if (ret < 0) | ||
| 748 | goto error; | ||
| 749 | 752 | ||
| 750 | ret = -ENOMEM; | 753 | ret = -ENOMEM; |
| 751 | token = kzalloc(sizeof(*token), GFP_KERNEL); | 754 | token = kzalloc(sizeof(*token), GFP_KERNEL); |
| @@ -762,15 +765,16 @@ static int rxrpc_instantiate(struct key *key, struct key_preparsed_payload *prep | |||
| 762 | memcpy(&token->kad->session_key, &v1->session_key, 8); | 765 | memcpy(&token->kad->session_key, &v1->session_key, 8); |
| 763 | memcpy(&token->kad->ticket, v1->ticket, v1->ticket_length); | 766 | memcpy(&token->kad->ticket, v1->ticket, v1->ticket_length); |
| 764 | 767 | ||
| 765 | /* attach the data */ | 768 | /* count the number of tokens attached */ |
| 766 | key->type_data.x[0]++; | 769 | prep->type_data[0] = (void *)((unsigned long)prep->type_data[0] + 1); |
| 767 | 770 | ||
| 768 | pp = (struct rxrpc_key_token **)&key->payload.data; | 771 | /* attach the data */ |
| 772 | pp = (struct rxrpc_key_token **)&prep->payload[0]; | ||
| 769 | while (*pp) | 773 | while (*pp) |
| 770 | pp = &(*pp)->next; | 774 | pp = &(*pp)->next; |
| 771 | *pp = token; | 775 | *pp = token; |
| 772 | if (token->kad->expiry < key->expiry) | 776 | if (token->kad->expiry < prep->expiry) |
| 773 | key->expiry = token->kad->expiry; | 777 | prep->expiry = token->kad->expiry; |
| 774 | token = NULL; | 778 | token = NULL; |
| 775 | ret = 0; | 779 | ret = 0; |
| 776 | 780 | ||
| @@ -781,20 +785,55 @@ error: | |||
| 781 | } | 785 | } |
| 782 | 786 | ||
| 783 | /* | 787 | /* |
| 784 | * instantiate a server secret key | 788 | * Free token list. |
| 785 | * data should be a pointer to the 8-byte secret key | ||
| 786 | */ | 789 | */ |
| 787 | static int rxrpc_instantiate_s(struct key *key, | 790 | static void rxrpc_free_token_list(struct rxrpc_key_token *token) |
| 788 | struct key_preparsed_payload *prep) | 791 | { |
| 792 | struct rxrpc_key_token *next; | ||
| 793 | |||
| 794 | for (; token; token = next) { | ||
| 795 | next = token->next; | ||
| 796 | switch (token->security_index) { | ||
| 797 | case RXRPC_SECURITY_RXKAD: | ||
| 798 | kfree(token->kad); | ||
| 799 | break; | ||
| 800 | case RXRPC_SECURITY_RXK5: | ||
| 801 | if (token->k5) | ||
| 802 | rxrpc_rxk5_free(token->k5); | ||
| 803 | break; | ||
| 804 | default: | ||
| 805 | printk(KERN_ERR "Unknown token type %x on rxrpc key\n", | ||
| 806 | token->security_index); | ||
| 807 | BUG(); | ||
| 808 | } | ||
| 809 | |||
| 810 | kfree(token); | ||
| 811 | } | ||
| 812 | } | ||
| 813 | |||
| 814 | /* | ||
| 815 | * Clean up preparse data. | ||
| 816 | */ | ||
| 817 | static void rxrpc_free_preparse(struct key_preparsed_payload *prep) | ||
| 818 | { | ||
| 819 | rxrpc_free_token_list(prep->payload[0]); | ||
| 820 | } | ||
| 821 | |||
| 822 | /* | ||
| 823 | * Preparse a server secret key. | ||
| 824 | * | ||
| 825 | * The data should be the 8-byte secret key. | ||
| 826 | */ | ||
| 827 | static int rxrpc_preparse_s(struct key_preparsed_payload *prep) | ||
| 789 | { | 828 | { |
| 790 | struct crypto_blkcipher *ci; | 829 | struct crypto_blkcipher *ci; |
| 791 | 830 | ||
| 792 | _enter("{%x},,%zu", key_serial(key), prep->datalen); | 831 | _enter("%zu", prep->datalen); |
| 793 | 832 | ||
| 794 | if (prep->datalen != 8) | 833 | if (prep->datalen != 8) |
| 795 | return -EINVAL; | 834 | return -EINVAL; |
| 796 | 835 | ||
| 797 | memcpy(&key->type_data, prep->data, 8); | 836 | memcpy(&prep->type_data, prep->data, 8); |
| 798 | 837 | ||
| 799 | ci = crypto_alloc_blkcipher("pcbc(des)", 0, CRYPTO_ALG_ASYNC); | 838 | ci = crypto_alloc_blkcipher("pcbc(des)", 0, CRYPTO_ALG_ASYNC); |
| 800 | if (IS_ERR(ci)) { | 839 | if (IS_ERR(ci)) { |
| @@ -805,36 +844,26 @@ static int rxrpc_instantiate_s(struct key *key, | |||
| 805 | if (crypto_blkcipher_setkey(ci, prep->data, 8) < 0) | 844 | if (crypto_blkcipher_setkey(ci, prep->data, 8) < 0) |
| 806 | BUG(); | 845 | BUG(); |
| 807 | 846 | ||
| 808 | key->payload.data = ci; | 847 | prep->payload[0] = ci; |
| 809 | _leave(" = 0"); | 848 | _leave(" = 0"); |
| 810 | return 0; | 849 | return 0; |
| 811 | } | 850 | } |
| 812 | 851 | ||
| 813 | /* | 852 | /* |
| 853 | * Clean up preparse data. | ||
| 854 | */ | ||
| 855 | static void rxrpc_free_preparse_s(struct key_preparsed_payload *prep) | ||
| 856 | { | ||
| 857 | if (prep->payload[0]) | ||
| 858 | crypto_free_blkcipher(prep->payload[0]); | ||
| 859 | } | ||
| 860 | |||
| 861 | /* | ||
| 814 | * dispose of the data dangling from the corpse of a rxrpc key | 862 | * dispose of the data dangling from the corpse of a rxrpc key |
| 815 | */ | 863 | */ |
| 816 | static void rxrpc_destroy(struct key *key) | 864 | static void rxrpc_destroy(struct key *key) |
| 817 | { | 865 | { |
| 818 | struct rxrpc_key_token *token; | 866 | rxrpc_free_token_list(key->payload.data); |
| 819 | |||
| 820 | while ((token = key->payload.data)) { | ||
| 821 | key->payload.data = token->next; | ||
| 822 | switch (token->security_index) { | ||
| 823 | case RXRPC_SECURITY_RXKAD: | ||
| 824 | kfree(token->kad); | ||
| 825 | break; | ||
| 826 | case RXRPC_SECURITY_RXK5: | ||
| 827 | if (token->k5) | ||
| 828 | rxrpc_rxk5_free(token->k5); | ||
| 829 | break; | ||
| 830 | default: | ||
| 831 | printk(KERN_ERR "Unknown token type %x on rxrpc key\n", | ||
| 832 | token->security_index); | ||
| 833 | BUG(); | ||
| 834 | } | ||
| 835 | |||
| 836 | kfree(token); | ||
| 837 | } | ||
| 838 | } | 867 | } |
| 839 | 868 | ||
| 840 | /* | 869 | /* |
diff --git a/net/sched/act_mirred.c b/net/sched/act_mirred.c index 4f912c0e225b..eb48306033d9 100644 --- a/net/sched/act_mirred.c +++ b/net/sched/act_mirred.c | |||
| @@ -218,10 +218,12 @@ static int mirred_device_event(struct notifier_block *unused, | |||
| 218 | 218 | ||
| 219 | if (event == NETDEV_UNREGISTER) | 219 | if (event == NETDEV_UNREGISTER) |
| 220 | list_for_each_entry(m, &mirred_list, tcfm_list) { | 220 | list_for_each_entry(m, &mirred_list, tcfm_list) { |
| 221 | spin_lock_bh(&m->tcf_lock); | ||
| 221 | if (m->tcfm_dev == dev) { | 222 | if (m->tcfm_dev == dev) { |
| 222 | dev_put(dev); | 223 | dev_put(dev); |
| 223 | m->tcfm_dev = NULL; | 224 | m->tcfm_dev = NULL; |
| 224 | } | 225 | } |
| 226 | spin_unlock_bh(&m->tcf_lock); | ||
| 225 | } | 227 | } |
| 226 | 228 | ||
| 227 | return NOTIFY_DONE; | 229 | return NOTIFY_DONE; |
diff --git a/net/sched/cls_api.c b/net/sched/cls_api.c index 45527e6b52db..c28b0d327b12 100644 --- a/net/sched/cls_api.c +++ b/net/sched/cls_api.c | |||
| @@ -561,13 +561,14 @@ EXPORT_SYMBOL(tcf_exts_change); | |||
| 561 | int tcf_exts_dump(struct sk_buff *skb, struct tcf_exts *exts) | 561 | int tcf_exts_dump(struct sk_buff *skb, struct tcf_exts *exts) |
| 562 | { | 562 | { |
| 563 | #ifdef CONFIG_NET_CLS_ACT | 563 | #ifdef CONFIG_NET_CLS_ACT |
| 564 | struct nlattr *nest; | ||
| 565 | |||
| 564 | if (exts->action && !list_empty(&exts->actions)) { | 566 | if (exts->action && !list_empty(&exts->actions)) { |
| 565 | /* | 567 | /* |
| 566 | * again for backward compatible mode - we want | 568 | * again for backward compatible mode - we want |
| 567 | * to work with both old and new modes of entering | 569 | * to work with both old and new modes of entering |
| 568 | * tc data even if iproute2 was newer - jhs | 570 | * tc data even if iproute2 was newer - jhs |
| 569 | */ | 571 | */ |
| 570 | struct nlattr *nest; | ||
| 571 | if (exts->type != TCA_OLD_COMPAT) { | 572 | if (exts->type != TCA_OLD_COMPAT) { |
| 572 | nest = nla_nest_start(skb, exts->action); | 573 | nest = nla_nest_start(skb, exts->action); |
| 573 | if (nest == NULL) | 574 | if (nest == NULL) |
| @@ -585,10 +586,14 @@ int tcf_exts_dump(struct sk_buff *skb, struct tcf_exts *exts) | |||
| 585 | nla_nest_end(skb, nest); | 586 | nla_nest_end(skb, nest); |
| 586 | } | 587 | } |
| 587 | } | 588 | } |
| 588 | #endif | ||
| 589 | return 0; | 589 | return 0; |
| 590 | nla_put_failure: __attribute__ ((unused)) | 590 | |
| 591 | nla_put_failure: | ||
| 592 | nla_nest_cancel(skb, nest); | ||
| 591 | return -1; | 593 | return -1; |
| 594 | #else | ||
| 595 | return 0; | ||
| 596 | #endif | ||
| 592 | } | 597 | } |
| 593 | EXPORT_SYMBOL(tcf_exts_dump); | 598 | EXPORT_SYMBOL(tcf_exts_dump); |
| 594 | 599 | ||
diff --git a/net/sched/cls_bpf.c b/net/sched/cls_bpf.c index 13f64df2c710..0e30d58149da 100644 --- a/net/sched/cls_bpf.c +++ b/net/sched/cls_bpf.c | |||
| @@ -30,7 +30,7 @@ struct cls_bpf_head { | |||
| 30 | }; | 30 | }; |
| 31 | 31 | ||
| 32 | struct cls_bpf_prog { | 32 | struct cls_bpf_prog { |
| 33 | struct sk_filter *filter; | 33 | struct bpf_prog *filter; |
| 34 | struct sock_filter *bpf_ops; | 34 | struct sock_filter *bpf_ops; |
| 35 | struct tcf_exts exts; | 35 | struct tcf_exts exts; |
| 36 | struct tcf_result res; | 36 | struct tcf_result res; |
| @@ -54,7 +54,7 @@ static int cls_bpf_classify(struct sk_buff *skb, const struct tcf_proto *tp, | |||
| 54 | int ret; | 54 | int ret; |
| 55 | 55 | ||
| 56 | list_for_each_entry(prog, &head->plist, link) { | 56 | list_for_each_entry(prog, &head->plist, link) { |
| 57 | int filter_res = SK_RUN_FILTER(prog->filter, skb); | 57 | int filter_res = BPF_PROG_RUN(prog->filter, skb); |
| 58 | 58 | ||
| 59 | if (filter_res == 0) | 59 | if (filter_res == 0) |
| 60 | continue; | 60 | continue; |
| @@ -92,7 +92,7 @@ static void cls_bpf_delete_prog(struct tcf_proto *tp, struct cls_bpf_prog *prog) | |||
| 92 | tcf_unbind_filter(tp, &prog->res); | 92 | tcf_unbind_filter(tp, &prog->res); |
| 93 | tcf_exts_destroy(tp, &prog->exts); | 93 | tcf_exts_destroy(tp, &prog->exts); |
| 94 | 94 | ||
| 95 | sk_unattached_filter_destroy(prog->filter); | 95 | bpf_prog_destroy(prog->filter); |
| 96 | 96 | ||
| 97 | kfree(prog->bpf_ops); | 97 | kfree(prog->bpf_ops); |
| 98 | kfree(prog); | 98 | kfree(prog); |
| @@ -161,7 +161,7 @@ static int cls_bpf_modify_existing(struct net *net, struct tcf_proto *tp, | |||
| 161 | struct sock_filter *bpf_ops, *bpf_old; | 161 | struct sock_filter *bpf_ops, *bpf_old; |
| 162 | struct tcf_exts exts; | 162 | struct tcf_exts exts; |
| 163 | struct sock_fprog_kern tmp; | 163 | struct sock_fprog_kern tmp; |
| 164 | struct sk_filter *fp, *fp_old; | 164 | struct bpf_prog *fp, *fp_old; |
| 165 | u16 bpf_size, bpf_len; | 165 | u16 bpf_size, bpf_len; |
| 166 | u32 classid; | 166 | u32 classid; |
| 167 | int ret; | 167 | int ret; |
| @@ -193,7 +193,7 @@ static int cls_bpf_modify_existing(struct net *net, struct tcf_proto *tp, | |||
| 193 | tmp.len = bpf_len; | 193 | tmp.len = bpf_len; |
| 194 | tmp.filter = bpf_ops; | 194 | tmp.filter = bpf_ops; |
| 195 | 195 | ||
| 196 | ret = sk_unattached_filter_create(&fp, &tmp); | 196 | ret = bpf_prog_create(&fp, &tmp); |
| 197 | if (ret) | 197 | if (ret) |
| 198 | goto errout_free; | 198 | goto errout_free; |
| 199 | 199 | ||
| @@ -211,7 +211,7 @@ static int cls_bpf_modify_existing(struct net *net, struct tcf_proto *tp, | |||
| 211 | tcf_exts_change(tp, &prog->exts, &exts); | 211 | tcf_exts_change(tp, &prog->exts, &exts); |
| 212 | 212 | ||
| 213 | if (fp_old) | 213 | if (fp_old) |
| 214 | sk_unattached_filter_destroy(fp_old); | 214 | bpf_prog_destroy(fp_old); |
| 215 | if (bpf_old) | 215 | if (bpf_old) |
| 216 | kfree(bpf_old); | 216 | kfree(bpf_old); |
| 217 | 217 | ||
diff --git a/net/sched/cls_tcindex.c b/net/sched/cls_tcindex.c index c721cd4a469f..3e9f76413b3b 100644 --- a/net/sched/cls_tcindex.c +++ b/net/sched/cls_tcindex.c | |||
| @@ -420,7 +420,7 @@ static void tcindex_destroy(struct tcf_proto *tp) | |||
| 420 | pr_debug("tcindex_destroy(tp %p),p %p\n", tp, p); | 420 | pr_debug("tcindex_destroy(tp %p),p %p\n", tp, p); |
| 421 | walker.count = 0; | 421 | walker.count = 0; |
| 422 | walker.skip = 0; | 422 | walker.skip = 0; |
| 423 | walker.fn = &tcindex_destroy_element; | 423 | walker.fn = tcindex_destroy_element; |
| 424 | tcindex_walk(tp, &walker); | 424 | tcindex_walk(tp, &walker); |
| 425 | kfree(p->perfect); | 425 | kfree(p->perfect); |
| 426 | kfree(p->h); | 426 | kfree(p->h); |
diff --git a/net/sched/em_canid.c b/net/sched/em_canid.c index bfd34e4c1afc..7c292d474f47 100644 --- a/net/sched/em_canid.c +++ b/net/sched/em_canid.c | |||
| @@ -125,7 +125,6 @@ static int em_canid_change(struct tcf_proto *tp, void *data, int len, | |||
| 125 | { | 125 | { |
| 126 | struct can_filter *conf = data; /* Array with rules */ | 126 | struct can_filter *conf = data; /* Array with rules */ |
| 127 | struct canid_match *cm; | 127 | struct canid_match *cm; |
| 128 | struct canid_match *cm_old = (struct canid_match *)m->data; | ||
| 129 | int i; | 128 | int i; |
| 130 | 129 | ||
| 131 | if (!len) | 130 | if (!len) |
| @@ -181,12 +180,6 @@ static int em_canid_change(struct tcf_proto *tp, void *data, int len, | |||
| 181 | 180 | ||
| 182 | m->datalen = sizeof(struct canid_match) + len; | 181 | m->datalen = sizeof(struct canid_match) + len; |
| 183 | m->data = (unsigned long)cm; | 182 | m->data = (unsigned long)cm; |
| 184 | |||
| 185 | if (cm_old != NULL) { | ||
| 186 | pr_err("canid: Configuring an existing ematch!\n"); | ||
| 187 | kfree(cm_old); | ||
| 188 | } | ||
| 189 | |||
| 190 | return 0; | 183 | return 0; |
| 191 | } | 184 | } |
| 192 | 185 | ||
diff --git a/net/sched/sch_generic.c b/net/sched/sch_generic.c index e1543b03e39d..fc04fe93c2da 100644 --- a/net/sched/sch_generic.c +++ b/net/sched/sch_generic.c | |||
| @@ -108,7 +108,7 @@ static inline int handle_dev_cpu_collision(struct sk_buff *skb, | |||
| 108 | 108 | ||
| 109 | /* | 109 | /* |
| 110 | * Transmit one skb, and handle the return status as required. Holding the | 110 | * Transmit one skb, and handle the return status as required. Holding the |
| 111 | * __QDISC_STATE_RUNNING bit guarantees that only one CPU can execute this | 111 | * __QDISC___STATE_RUNNING bit guarantees that only one CPU can execute this |
| 112 | * function. | 112 | * function. |
| 113 | * | 113 | * |
| 114 | * Returns to the caller: | 114 | * Returns to the caller: |
| @@ -156,7 +156,7 @@ int sch_direct_xmit(struct sk_buff *skb, struct Qdisc *q, | |||
| 156 | /* | 156 | /* |
| 157 | * NOTE: Called under qdisc_lock(q) with locally disabled BH. | 157 | * NOTE: Called under qdisc_lock(q) with locally disabled BH. |
| 158 | * | 158 | * |
| 159 | * __QDISC_STATE_RUNNING guarantees only one CPU can process | 159 | * __QDISC___STATE_RUNNING guarantees only one CPU can process |
| 160 | * this qdisc at a time. qdisc_lock(q) serializes queue accesses for | 160 | * this qdisc at a time. qdisc_lock(q) serializes queue accesses for |
| 161 | * this queue. | 161 | * this queue. |
| 162 | * | 162 | * |
diff --git a/net/sched/sch_teql.c b/net/sched/sch_teql.c index 474167162947..bd33793b527e 100644 --- a/net/sched/sch_teql.c +++ b/net/sched/sch_teql.c | |||
| @@ -485,8 +485,8 @@ static int __init teql_init(void) | |||
| 485 | struct net_device *dev; | 485 | struct net_device *dev; |
| 486 | struct teql_master *master; | 486 | struct teql_master *master; |
| 487 | 487 | ||
| 488 | dev = alloc_netdev(sizeof(struct teql_master), | 488 | dev = alloc_netdev(sizeof(struct teql_master), "teql%d", |
| 489 | "teql%d", teql_master_setup); | 489 | NET_NAME_UNKNOWN, teql_master_setup); |
| 490 | if (!dev) { | 490 | if (!dev) { |
| 491 | err = -ENOMEM; | 491 | err = -ENOMEM; |
| 492 | break; | 492 | break; |
diff --git a/net/sctp/Makefile b/net/sctp/Makefile index 5c30b7a873df..3b4ffb021cf1 100644 --- a/net/sctp/Makefile +++ b/net/sctp/Makefile | |||
| @@ -8,7 +8,7 @@ obj-$(CONFIG_NET_SCTPPROBE) += sctp_probe.o | |||
| 8 | sctp-y := sm_statetable.o sm_statefuns.o sm_sideeffect.o \ | 8 | sctp-y := sm_statetable.o sm_statefuns.o sm_sideeffect.o \ |
| 9 | protocol.o endpointola.o associola.o \ | 9 | protocol.o endpointola.o associola.o \ |
| 10 | transport.o chunk.o sm_make_chunk.o ulpevent.o \ | 10 | transport.o chunk.o sm_make_chunk.o ulpevent.o \ |
| 11 | inqueue.o outqueue.o ulpqueue.o command.o \ | 11 | inqueue.o outqueue.o ulpqueue.o \ |
| 12 | tsnmap.o bind_addr.o socket.o primitive.o \ | 12 | tsnmap.o bind_addr.o socket.o primitive.o \ |
| 13 | output.o input.o debug.o ssnmap.o auth.o | 13 | output.o input.o debug.o ssnmap.o auth.o |
| 14 | 14 | ||
diff --git a/net/sctp/command.c b/net/sctp/command.c deleted file mode 100644 index dd7375851618..000000000000 --- a/net/sctp/command.c +++ /dev/null | |||
| @@ -1,68 +0,0 @@ | |||
| 1 | /* SCTP kernel implementation Copyright (C) 1999-2001 | ||
| 2 | * Cisco, Motorola, and IBM | ||
| 3 | * Copyright 2001 La Monte H.P. Yarroll | ||
| 4 | * | ||
| 5 | * This file is part of the SCTP kernel implementation | ||
| 6 | * | ||
| 7 | * These functions manipulate sctp command sequences. | ||
| 8 | * | ||
| 9 | * This SCTP implementation is free software; | ||
| 10 | * you can redistribute it and/or modify it under the terms of | ||
| 11 | * the GNU General Public License as published by | ||
| 12 | * the Free Software Foundation; either version 2, or (at your option) | ||
| 13 | * any later version. | ||
| 14 | * | ||
| 15 | * This SCTP implementation is distributed in the hope that it | ||
| 16 | * will be useful, but WITHOUT ANY WARRANTY; without even the implied | ||
| 17 | * ************************ | ||
| 18 | * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. | ||
| 19 | * See the GNU General Public License for more details. | ||
| 20 | * | ||
| 21 | * You should have received a copy of the GNU General Public License | ||
| 22 | * along with GNU CC; see the file COPYING. If not, see | ||
| 23 | * <http://www.gnu.org/licenses/>. | ||
| 24 | * | ||
| 25 | * Please send any bug reports or fixes you make to the | ||
| 26 | * email address(es): | ||
| 27 | * lksctp developers <linux-sctp@vger.kernel.org> | ||
| 28 | * | ||
| 29 | * Written or modified by: | ||
| 30 | * La Monte H.P. Yarroll <piggy@acm.org> | ||
| 31 | * Karl Knutson <karl@athena.chicago.il.us> | ||
| 32 | */ | ||
| 33 | |||
| 34 | #include <linux/types.h> | ||
| 35 | #include <net/sctp/sctp.h> | ||
| 36 | #include <net/sctp/sm.h> | ||
| 37 | |||
| 38 | /* Initialize a block of memory as a command sequence. */ | ||
| 39 | int sctp_init_cmd_seq(sctp_cmd_seq_t *seq) | ||
| 40 | { | ||
| 41 | memset(seq, 0, sizeof(sctp_cmd_seq_t)); | ||
| 42 | return 1; /* We always succeed. */ | ||
| 43 | } | ||
| 44 | |||
| 45 | /* Add a command to a sctp_cmd_seq_t. | ||
| 46 | * Return 0 if the command sequence is full. | ||
| 47 | */ | ||
| 48 | void sctp_add_cmd_sf(sctp_cmd_seq_t *seq, sctp_verb_t verb, sctp_arg_t obj) | ||
| 49 | { | ||
| 50 | BUG_ON(seq->next_free_slot >= SCTP_MAX_NUM_COMMANDS); | ||
| 51 | |||
| 52 | seq->cmds[seq->next_free_slot].verb = verb; | ||
| 53 | seq->cmds[seq->next_free_slot++].obj = obj; | ||
| 54 | } | ||
| 55 | |||
| 56 | /* Return the next command structure in a sctp_cmd_seq. | ||
| 57 | * Returns NULL at the end of the sequence. | ||
| 58 | */ | ||
| 59 | sctp_cmd_t *sctp_next_cmd(sctp_cmd_seq_t *seq) | ||
| 60 | { | ||
| 61 | sctp_cmd_t *retval = NULL; | ||
| 62 | |||
| 63 | if (seq->next_cmd < seq->next_free_slot) | ||
| 64 | retval = &seq->cmds[seq->next_cmd++]; | ||
| 65 | |||
| 66 | return retval; | ||
| 67 | } | ||
| 68 | |||
diff --git a/net/sctp/input.c b/net/sctp/input.c index f2e2cbd2d750..c1b991294516 100644 --- a/net/sctp/input.c +++ b/net/sctp/input.c | |||
| @@ -575,11 +575,6 @@ void sctp_v4_err(struct sk_buff *skb, __u32 info) | |||
| 575 | int err; | 575 | int err; |
| 576 | struct net *net = dev_net(skb->dev); | 576 | struct net *net = dev_net(skb->dev); |
| 577 | 577 | ||
| 578 | if (skb->len < ihlen + 8) { | ||
| 579 | ICMP_INC_STATS_BH(net, ICMP_MIB_INERRORS); | ||
| 580 | return; | ||
| 581 | } | ||
| 582 | |||
| 583 | /* Fix up skb to look at the embedded net header. */ | 578 | /* Fix up skb to look at the embedded net header. */ |
| 584 | saveip = skb->network_header; | 579 | saveip = skb->network_header; |
| 585 | savesctp = skb->transport_header; | 580 | savesctp = skb->transport_header; |
diff --git a/net/sctp/ipv6.c b/net/sctp/ipv6.c index 1999592ba88c..0e4198ee2370 100644 --- a/net/sctp/ipv6.c +++ b/net/sctp/ipv6.c | |||
| @@ -434,7 +434,7 @@ static void sctp_v6_from_sk(union sctp_addr *addr, struct sock *sk) | |||
| 434 | /* Initialize sk->sk_rcv_saddr from sctp_addr. */ | 434 | /* Initialize sk->sk_rcv_saddr from sctp_addr. */ |
| 435 | static void sctp_v6_to_sk_saddr(union sctp_addr *addr, struct sock *sk) | 435 | static void sctp_v6_to_sk_saddr(union sctp_addr *addr, struct sock *sk) |
| 436 | { | 436 | { |
| 437 | if (addr->sa.sa_family == AF_INET && sctp_sk(sk)->v4mapped) { | 437 | if (addr->sa.sa_family == AF_INET) { |
| 438 | sk->sk_v6_rcv_saddr.s6_addr32[0] = 0; | 438 | sk->sk_v6_rcv_saddr.s6_addr32[0] = 0; |
| 439 | sk->sk_v6_rcv_saddr.s6_addr32[1] = 0; | 439 | sk->sk_v6_rcv_saddr.s6_addr32[1] = 0; |
| 440 | sk->sk_v6_rcv_saddr.s6_addr32[2] = htonl(0x0000ffff); | 440 | sk->sk_v6_rcv_saddr.s6_addr32[2] = htonl(0x0000ffff); |
| @@ -448,7 +448,7 @@ static void sctp_v6_to_sk_saddr(union sctp_addr *addr, struct sock *sk) | |||
| 448 | /* Initialize sk->sk_daddr from sctp_addr. */ | 448 | /* Initialize sk->sk_daddr from sctp_addr. */ |
| 449 | static void sctp_v6_to_sk_daddr(union sctp_addr *addr, struct sock *sk) | 449 | static void sctp_v6_to_sk_daddr(union sctp_addr *addr, struct sock *sk) |
| 450 | { | 450 | { |
| 451 | if (addr->sa.sa_family == AF_INET && sctp_sk(sk)->v4mapped) { | 451 | if (addr->sa.sa_family == AF_INET) { |
| 452 | sk->sk_v6_daddr.s6_addr32[0] = 0; | 452 | sk->sk_v6_daddr.s6_addr32[0] = 0; |
| 453 | sk->sk_v6_daddr.s6_addr32[1] = 0; | 453 | sk->sk_v6_daddr.s6_addr32[1] = 0; |
| 454 | sk->sk_v6_daddr.s6_addr32[2] = htonl(0x0000ffff); | 454 | sk->sk_v6_daddr.s6_addr32[2] = htonl(0x0000ffff); |
| @@ -556,8 +556,6 @@ static int sctp_v6_available(union sctp_addr *addr, struct sctp_sock *sp) | |||
| 556 | if (IPV6_ADDR_ANY == type) | 556 | if (IPV6_ADDR_ANY == type) |
| 557 | return 1; | 557 | return 1; |
| 558 | if (type == IPV6_ADDR_MAPPED) { | 558 | if (type == IPV6_ADDR_MAPPED) { |
| 559 | if (sp && !sp->v4mapped) | ||
| 560 | return 0; | ||
| 561 | if (sp && ipv6_only_sock(sctp_opt2sk(sp))) | 559 | if (sp && ipv6_only_sock(sctp_opt2sk(sp))) |
| 562 | return 0; | 560 | return 0; |
| 563 | sctp_v6_map_v4(addr); | 561 | sctp_v6_map_v4(addr); |
| @@ -587,8 +585,6 @@ static int sctp_v6_addr_valid(union sctp_addr *addr, | |||
| 587 | /* Note: This routine is used in input, so v4-mapped-v6 | 585 | /* Note: This routine is used in input, so v4-mapped-v6 |
| 588 | * are disallowed here when there is no sctp_sock. | 586 | * are disallowed here when there is no sctp_sock. |
| 589 | */ | 587 | */ |
| 590 | if (!sp || !sp->v4mapped) | ||
| 591 | return 0; | ||
| 592 | if (sp && ipv6_only_sock(sctp_opt2sk(sp))) | 588 | if (sp && ipv6_only_sock(sctp_opt2sk(sp))) |
| 593 | return 0; | 589 | return 0; |
| 594 | sctp_v6_map_v4(addr); | 590 | sctp_v6_map_v4(addr); |
| @@ -675,11 +671,23 @@ out: | |||
| 675 | return newsk; | 671 | return newsk; |
| 676 | } | 672 | } |
| 677 | 673 | ||
| 678 | /* Map v4 address to mapped v6 address */ | 674 | /* Format a sockaddr for return to user space. This makes sure the return is |
| 679 | static void sctp_v6_addr_v4map(struct sctp_sock *sp, union sctp_addr *addr) | 675 | * AF_INET or AF_INET6 depending on the SCTP_I_WANT_MAPPED_V4_ADDR option. |
| 676 | */ | ||
| 677 | static int sctp_v6_addr_to_user(struct sctp_sock *sp, union sctp_addr *addr) | ||
| 680 | { | 678 | { |
| 681 | if (sp->v4mapped && AF_INET == addr->sa.sa_family) | 679 | if (sp->v4mapped) { |
| 682 | sctp_v4_map_v6(addr); | 680 | if (addr->sa.sa_family == AF_INET) |
| 681 | sctp_v4_map_v6(addr); | ||
| 682 | } else { | ||
| 683 | if (addr->sa.sa_family == AF_INET6 && | ||
| 684 | ipv6_addr_v4mapped(&addr->v6.sin6_addr)) | ||
| 685 | sctp_v6_map_v4(addr); | ||
| 686 | } | ||
| 687 | |||
| 688 | if (addr->sa.sa_family == AF_INET) | ||
| 689 | return sizeof(struct sockaddr_in); | ||
| 690 | return sizeof(struct sockaddr_in6); | ||
| 683 | } | 691 | } |
| 684 | 692 | ||
| 685 | /* Where did this skb come from? */ | 693 | /* Where did this skb come from? */ |
| @@ -706,82 +714,68 @@ static void sctp_v6_ecn_capable(struct sock *sk) | |||
| 706 | inet6_sk(sk)->tclass |= INET_ECN_ECT_0; | 714 | inet6_sk(sk)->tclass |= INET_ECN_ECT_0; |
| 707 | } | 715 | } |
| 708 | 716 | ||
| 709 | /* Initialize a PF_INET6 socket msg_name. */ | ||
| 710 | static void sctp_inet6_msgname(char *msgname, int *addr_len) | ||
| 711 | { | ||
| 712 | struct sockaddr_in6 *sin6; | ||
| 713 | |||
| 714 | sin6 = (struct sockaddr_in6 *)msgname; | ||
| 715 | sin6->sin6_family = AF_INET6; | ||
| 716 | sin6->sin6_flowinfo = 0; | ||
| 717 | sin6->sin6_scope_id = 0; /*FIXME */ | ||
| 718 | *addr_len = sizeof(struct sockaddr_in6); | ||
| 719 | } | ||
| 720 | |||
| 721 | /* Initialize a PF_INET msgname from a ulpevent. */ | 717 | /* Initialize a PF_INET msgname from a ulpevent. */ |
| 722 | static void sctp_inet6_event_msgname(struct sctp_ulpevent *event, | 718 | static void sctp_inet6_event_msgname(struct sctp_ulpevent *event, |
| 723 | char *msgname, int *addrlen) | 719 | char *msgname, int *addrlen) |
| 724 | { | 720 | { |
| 725 | struct sockaddr_in6 *sin6, *sin6from; | 721 | union sctp_addr *addr; |
| 726 | 722 | struct sctp_association *asoc; | |
| 727 | if (msgname) { | 723 | union sctp_addr *paddr; |
| 728 | union sctp_addr *addr; | ||
| 729 | struct sctp_association *asoc; | ||
| 730 | |||
| 731 | asoc = event->asoc; | ||
| 732 | sctp_inet6_msgname(msgname, addrlen); | ||
| 733 | sin6 = (struct sockaddr_in6 *)msgname; | ||
| 734 | sin6->sin6_port = htons(asoc->peer.port); | ||
| 735 | addr = &asoc->peer.primary_addr; | ||
| 736 | 724 | ||
| 737 | /* Note: If we go to a common v6 format, this code | 725 | if (!msgname) |
| 738 | * will change. | 726 | return; |
| 739 | */ | ||
| 740 | 727 | ||
| 741 | /* Map ipv4 address into v4-mapped-on-v6 address. */ | 728 | addr = (union sctp_addr *)msgname; |
| 742 | if (sctp_sk(asoc->base.sk)->v4mapped && | 729 | asoc = event->asoc; |
| 743 | AF_INET == addr->sa.sa_family) { | 730 | paddr = &asoc->peer.primary_addr; |
| 744 | sctp_v4_map_v6((union sctp_addr *)sin6); | ||
| 745 | sin6->sin6_addr.s6_addr32[3] = | ||
| 746 | addr->v4.sin_addr.s_addr; | ||
| 747 | return; | ||
| 748 | } | ||
| 749 | 731 | ||
| 750 | sin6from = &asoc->peer.primary_addr.v6; | 732 | if (paddr->sa.sa_family == AF_INET) { |
| 751 | sin6->sin6_addr = sin6from->sin6_addr; | 733 | addr->v4.sin_family = AF_INET; |
| 752 | if (ipv6_addr_type(&sin6->sin6_addr) & IPV6_ADDR_LINKLOCAL) | 734 | addr->v4.sin_port = htons(asoc->peer.port); |
| 753 | sin6->sin6_scope_id = sin6from->sin6_scope_id; | 735 | addr->v4.sin_addr = paddr->v4.sin_addr; |
| 736 | } else { | ||
| 737 | addr->v6.sin6_family = AF_INET6; | ||
| 738 | addr->v6.sin6_flowinfo = 0; | ||
| 739 | if (ipv6_addr_type(&paddr->v6.sin6_addr) & IPV6_ADDR_LINKLOCAL) | ||
| 740 | addr->v6.sin6_scope_id = paddr->v6.sin6_scope_id; | ||
| 741 | else | ||
| 742 | addr->v6.sin6_scope_id = 0; | ||
| 743 | addr->v6.sin6_port = htons(asoc->peer.port); | ||
| 744 | addr->v6.sin6_addr = paddr->v6.sin6_addr; | ||
| 754 | } | 745 | } |
| 746 | |||
| 747 | *addrlen = sctp_v6_addr_to_user(sctp_sk(asoc->base.sk), addr); | ||
| 755 | } | 748 | } |
| 756 | 749 | ||
| 757 | /* Initialize a msg_name from an inbound skb. */ | 750 | /* Initialize a msg_name from an inbound skb. */ |
| 758 | static void sctp_inet6_skb_msgname(struct sk_buff *skb, char *msgname, | 751 | static void sctp_inet6_skb_msgname(struct sk_buff *skb, char *msgname, |
| 759 | int *addr_len) | 752 | int *addr_len) |
| 760 | { | 753 | { |
| 754 | union sctp_addr *addr; | ||
| 761 | struct sctphdr *sh; | 755 | struct sctphdr *sh; |
| 762 | struct sockaddr_in6 *sin6; | ||
| 763 | |||
| 764 | if (msgname) { | ||
| 765 | sctp_inet6_msgname(msgname, addr_len); | ||
| 766 | sin6 = (struct sockaddr_in6 *)msgname; | ||
| 767 | sh = sctp_hdr(skb); | ||
| 768 | sin6->sin6_port = sh->source; | ||
| 769 | |||
| 770 | /* Map ipv4 address into v4-mapped-on-v6 address. */ | ||
| 771 | if (sctp_sk(skb->sk)->v4mapped && | ||
| 772 | ip_hdr(skb)->version == 4) { | ||
| 773 | sctp_v4_map_v6((union sctp_addr *)sin6); | ||
| 774 | sin6->sin6_addr.s6_addr32[3] = ip_hdr(skb)->saddr; | ||
| 775 | return; | ||
| 776 | } | ||
| 777 | 756 | ||
| 778 | /* Otherwise, just copy the v6 address. */ | 757 | if (!msgname) |
| 779 | sin6->sin6_addr = ipv6_hdr(skb)->saddr; | 758 | return; |
| 780 | if (ipv6_addr_type(&sin6->sin6_addr) & IPV6_ADDR_LINKLOCAL) { | 759 | |
| 760 | addr = (union sctp_addr *)msgname; | ||
| 761 | sh = sctp_hdr(skb); | ||
| 762 | |||
| 763 | if (ip_hdr(skb)->version == 4) { | ||
| 764 | addr->v4.sin_family = AF_INET; | ||
| 765 | addr->v4.sin_port = sh->source; | ||
| 766 | addr->v4.sin_addr.s_addr = ip_hdr(skb)->saddr; | ||
| 767 | } else { | ||
| 768 | addr->v6.sin6_family = AF_INET6; | ||
| 769 | addr->v6.sin6_flowinfo = 0; | ||
| 770 | addr->v6.sin6_port = sh->source; | ||
| 771 | addr->v6.sin6_addr = ipv6_hdr(skb)->saddr; | ||
| 772 | if (ipv6_addr_type(&addr->v6.sin6_addr) & IPV6_ADDR_LINKLOCAL) { | ||
| 781 | struct sctp_ulpevent *ev = sctp_skb2event(skb); | 773 | struct sctp_ulpevent *ev = sctp_skb2event(skb); |
| 782 | sin6->sin6_scope_id = ev->iif; | 774 | addr->v6.sin6_scope_id = ev->iif; |
| 783 | } | 775 | } |
| 784 | } | 776 | } |
| 777 | |||
| 778 | *addr_len = sctp_v6_addr_to_user(sctp_sk(skb->sk), addr); | ||
| 785 | } | 779 | } |
| 786 | 780 | ||
| 787 | /* Do we support this AF? */ | 781 | /* Do we support this AF? */ |
| @@ -857,9 +851,6 @@ static int sctp_inet6_bind_verify(struct sctp_sock *opt, union sctp_addr *addr) | |||
| 857 | return 0; | 851 | return 0; |
| 858 | } | 852 | } |
| 859 | rcu_read_unlock(); | 853 | rcu_read_unlock(); |
| 860 | } else if (type == IPV6_ADDR_MAPPED) { | ||
| 861 | if (!opt->v4mapped) | ||
| 862 | return 0; | ||
| 863 | } | 854 | } |
| 864 | 855 | ||
| 865 | af = opt->pf->af; | 856 | af = opt->pf->af; |
| @@ -914,6 +905,23 @@ static int sctp_inet6_supported_addrs(const struct sctp_sock *opt, | |||
| 914 | return 1; | 905 | return 1; |
| 915 | } | 906 | } |
| 916 | 907 | ||
| 908 | /* Handle SCTP_I_WANT_MAPPED_V4_ADDR for getpeername() and getsockname() */ | ||
| 909 | static int sctp_getname(struct socket *sock, struct sockaddr *uaddr, | ||
| 910 | int *uaddr_len, int peer) | ||
| 911 | { | ||
| 912 | int rc; | ||
| 913 | |||
| 914 | rc = inet6_getname(sock, uaddr, uaddr_len, peer); | ||
| 915 | |||
| 916 | if (rc != 0) | ||
| 917 | return rc; | ||
| 918 | |||
| 919 | *uaddr_len = sctp_v6_addr_to_user(sctp_sk(sock->sk), | ||
| 920 | (union sctp_addr *)uaddr); | ||
| 921 | |||
| 922 | return rc; | ||
| 923 | } | ||
| 924 | |||
| 917 | static const struct proto_ops inet6_seqpacket_ops = { | 925 | static const struct proto_ops inet6_seqpacket_ops = { |
| 918 | .family = PF_INET6, | 926 | .family = PF_INET6, |
| 919 | .owner = THIS_MODULE, | 927 | .owner = THIS_MODULE, |
| @@ -922,7 +930,7 @@ static const struct proto_ops inet6_seqpacket_ops = { | |||
| 922 | .connect = inet_dgram_connect, | 930 | .connect = inet_dgram_connect, |
| 923 | .socketpair = sock_no_socketpair, | 931 | .socketpair = sock_no_socketpair, |
| 924 | .accept = inet_accept, | 932 | .accept = inet_accept, |
| 925 | .getname = inet6_getname, | 933 | .getname = sctp_getname, |
| 926 | .poll = sctp_poll, | 934 | .poll = sctp_poll, |
| 927 | .ioctl = inet6_ioctl, | 935 | .ioctl = inet6_ioctl, |
| 928 | .listen = sctp_inet_listen, | 936 | .listen = sctp_inet_listen, |
| @@ -974,8 +982,6 @@ static struct sctp_af sctp_af_inet6 = { | |||
| 974 | .copy_addrlist = sctp_v6_copy_addrlist, | 982 | .copy_addrlist = sctp_v6_copy_addrlist, |
| 975 | .from_skb = sctp_v6_from_skb, | 983 | .from_skb = sctp_v6_from_skb, |
| 976 | .from_sk = sctp_v6_from_sk, | 984 | .from_sk = sctp_v6_from_sk, |
| 977 | .to_sk_saddr = sctp_v6_to_sk_saddr, | ||
| 978 | .to_sk_daddr = sctp_v6_to_sk_daddr, | ||
| 979 | .from_addr_param = sctp_v6_from_addr_param, | 985 | .from_addr_param = sctp_v6_from_addr_param, |
| 980 | .to_addr_param = sctp_v6_to_addr_param, | 986 | .to_addr_param = sctp_v6_to_addr_param, |
| 981 | .cmp_addr = sctp_v6_cmp_addr, | 987 | .cmp_addr = sctp_v6_cmp_addr, |
| @@ -1005,7 +1011,9 @@ static struct sctp_pf sctp_pf_inet6 = { | |||
| 1005 | .send_verify = sctp_inet6_send_verify, | 1011 | .send_verify = sctp_inet6_send_verify, |
| 1006 | .supported_addrs = sctp_inet6_supported_addrs, | 1012 | .supported_addrs = sctp_inet6_supported_addrs, |
| 1007 | .create_accept_sk = sctp_v6_create_accept_sk, | 1013 | .create_accept_sk = sctp_v6_create_accept_sk, |
| 1008 | .addr_v4map = sctp_v6_addr_v4map, | 1014 | .addr_to_user = sctp_v6_addr_to_user, |
| 1015 | .to_sk_saddr = sctp_v6_to_sk_saddr, | ||
| 1016 | .to_sk_daddr = sctp_v6_to_sk_daddr, | ||
| 1009 | .af = &sctp_af_inet6, | 1017 | .af = &sctp_af_inet6, |
| 1010 | }; | 1018 | }; |
| 1011 | 1019 | ||
diff --git a/net/sctp/output.c b/net/sctp/output.c index 01ab8e0723f0..42dffd428389 100644 --- a/net/sctp/output.c +++ b/net/sctp/output.c | |||
| @@ -178,7 +178,7 @@ sctp_xmit_t sctp_packet_transmit_chunk(struct sctp_packet *packet, | |||
| 178 | 178 | ||
| 179 | case SCTP_XMIT_RWND_FULL: | 179 | case SCTP_XMIT_RWND_FULL: |
| 180 | case SCTP_XMIT_OK: | 180 | case SCTP_XMIT_OK: |
| 181 | case SCTP_XMIT_NAGLE_DELAY: | 181 | case SCTP_XMIT_DELAY: |
| 182 | break; | 182 | break; |
| 183 | } | 183 | } |
| 184 | 184 | ||
| @@ -599,7 +599,7 @@ out: | |||
| 599 | return err; | 599 | return err; |
| 600 | no_route: | 600 | no_route: |
| 601 | kfree_skb(nskb); | 601 | kfree_skb(nskb); |
| 602 | IP_INC_STATS_BH(sock_net(asoc->base.sk), IPSTATS_MIB_OUTNOROUTES); | 602 | IP_INC_STATS(sock_net(asoc->base.sk), IPSTATS_MIB_OUTNOROUTES); |
| 603 | 603 | ||
| 604 | /* FIXME: Returning the 'err' will effect all the associations | 604 | /* FIXME: Returning the 'err' will effect all the associations |
| 605 | * associated with a socket, although only one of the paths of the | 605 | * associated with a socket, although only one of the paths of the |
| @@ -633,7 +633,6 @@ nomem: | |||
| 633 | static sctp_xmit_t sctp_packet_can_append_data(struct sctp_packet *packet, | 633 | static sctp_xmit_t sctp_packet_can_append_data(struct sctp_packet *packet, |
| 634 | struct sctp_chunk *chunk) | 634 | struct sctp_chunk *chunk) |
| 635 | { | 635 | { |
| 636 | sctp_xmit_t retval = SCTP_XMIT_OK; | ||
| 637 | size_t datasize, rwnd, inflight, flight_size; | 636 | size_t datasize, rwnd, inflight, flight_size; |
| 638 | struct sctp_transport *transport = packet->transport; | 637 | struct sctp_transport *transport = packet->transport; |
| 639 | struct sctp_association *asoc = transport->asoc; | 638 | struct sctp_association *asoc = transport->asoc; |
| @@ -658,15 +657,11 @@ static sctp_xmit_t sctp_packet_can_append_data(struct sctp_packet *packet, | |||
| 658 | 657 | ||
| 659 | datasize = sctp_data_size(chunk); | 658 | datasize = sctp_data_size(chunk); |
| 660 | 659 | ||
| 661 | if (datasize > rwnd) { | 660 | if (datasize > rwnd && inflight > 0) |
| 662 | if (inflight > 0) { | 661 | /* We have (at least) one data chunk in flight, |
| 663 | /* We have (at least) one data chunk in flight, | 662 | * so we can't fall back to rule 6.1 B). |
| 664 | * so we can't fall back to rule 6.1 B). | 663 | */ |
| 665 | */ | 664 | return SCTP_XMIT_RWND_FULL; |
| 666 | retval = SCTP_XMIT_RWND_FULL; | ||
| 667 | goto finish; | ||
| 668 | } | ||
| 669 | } | ||
| 670 | 665 | ||
| 671 | /* RFC 2960 6.1 Transmission of DATA Chunks | 666 | /* RFC 2960 6.1 Transmission of DATA Chunks |
| 672 | * | 667 | * |
| @@ -680,36 +675,44 @@ static sctp_xmit_t sctp_packet_can_append_data(struct sctp_packet *packet, | |||
| 680 | * When a Fast Retransmit is being performed the sender SHOULD | 675 | * When a Fast Retransmit is being performed the sender SHOULD |
| 681 | * ignore the value of cwnd and SHOULD NOT delay retransmission. | 676 | * ignore the value of cwnd and SHOULD NOT delay retransmission. |
| 682 | */ | 677 | */ |
| 683 | if (chunk->fast_retransmit != SCTP_NEED_FRTX) | 678 | if (chunk->fast_retransmit != SCTP_NEED_FRTX && |
| 684 | if (flight_size >= transport->cwnd) { | 679 | flight_size >= transport->cwnd) |
| 685 | retval = SCTP_XMIT_RWND_FULL; | 680 | return SCTP_XMIT_RWND_FULL; |
| 686 | goto finish; | ||
| 687 | } | ||
| 688 | 681 | ||
| 689 | /* Nagle's algorithm to solve small-packet problem: | 682 | /* Nagle's algorithm to solve small-packet problem: |
| 690 | * Inhibit the sending of new chunks when new outgoing data arrives | 683 | * Inhibit the sending of new chunks when new outgoing data arrives |
| 691 | * if any previously transmitted data on the connection remains | 684 | * if any previously transmitted data on the connection remains |
| 692 | * unacknowledged. | 685 | * unacknowledged. |
| 693 | */ | 686 | */ |
| 694 | if (!sctp_sk(asoc->base.sk)->nodelay && sctp_packet_empty(packet) && | ||
| 695 | inflight && sctp_state(asoc, ESTABLISHED)) { | ||
| 696 | unsigned int max = transport->pathmtu - packet->overhead; | ||
| 697 | unsigned int len = chunk->skb->len + q->out_qlen; | ||
| 698 | |||
| 699 | /* Check whether this chunk and all the rest of pending | ||
| 700 | * data will fit or delay in hopes of bundling a full | ||
| 701 | * sized packet. | ||
| 702 | * Don't delay large message writes that may have been | ||
| 703 | * fragmeneted into small peices. | ||
| 704 | */ | ||
| 705 | if ((len < max) && chunk->msg->can_delay) { | ||
| 706 | retval = SCTP_XMIT_NAGLE_DELAY; | ||
| 707 | goto finish; | ||
| 708 | } | ||
| 709 | } | ||
| 710 | 687 | ||
| 711 | finish: | 688 | if (sctp_sk(asoc->base.sk)->nodelay) |
| 712 | return retval; | 689 | /* Nagle disabled */ |
| 690 | return SCTP_XMIT_OK; | ||
| 691 | |||
| 692 | if (!sctp_packet_empty(packet)) | ||
| 693 | /* Append to packet */ | ||
| 694 | return SCTP_XMIT_OK; | ||
| 695 | |||
| 696 | if (inflight == 0) | ||
| 697 | /* Nothing unacked */ | ||
| 698 | return SCTP_XMIT_OK; | ||
| 699 | |||
| 700 | if (!sctp_state(asoc, ESTABLISHED)) | ||
| 701 | return SCTP_XMIT_OK; | ||
| 702 | |||
| 703 | /* Check whether this chunk and all the rest of pending data will fit | ||
| 704 | * or delay in hopes of bundling a full sized packet. | ||
| 705 | */ | ||
| 706 | if (chunk->skb->len + q->out_qlen >= transport->pathmtu - packet->overhead) | ||
| 707 | /* Enough data queued to fill a packet */ | ||
| 708 | return SCTP_XMIT_OK; | ||
| 709 | |||
| 710 | /* Don't delay large message writes that may have been fragmented */ | ||
| 711 | if (!chunk->msg->can_delay) | ||
| 712 | return SCTP_XMIT_OK; | ||
| 713 | |||
| 714 | /* Defer until all data acked or packet full */ | ||
| 715 | return SCTP_XMIT_DELAY; | ||
| 713 | } | 716 | } |
| 714 | 717 | ||
| 715 | /* This private function does management things when adding DATA chunk */ | 718 | /* This private function does management things when adding DATA chunk */ |
diff --git a/net/sctp/outqueue.c b/net/sctp/outqueue.c index 9c77947c0597..7e8f0a117106 100644 --- a/net/sctp/outqueue.c +++ b/net/sctp/outqueue.c | |||
| @@ -629,7 +629,7 @@ redo: | |||
| 629 | done = 1; | 629 | done = 1; |
| 630 | break; | 630 | break; |
| 631 | 631 | ||
| 632 | case SCTP_XMIT_NAGLE_DELAY: | 632 | case SCTP_XMIT_DELAY: |
| 633 | /* Send this packet. */ | 633 | /* Send this packet. */ |
| 634 | error = sctp_packet_transmit(pkt); | 634 | error = sctp_packet_transmit(pkt); |
| 635 | 635 | ||
| @@ -1015,7 +1015,7 @@ static int sctp_outq_flush(struct sctp_outq *q, int rtx_timeout) | |||
| 1015 | switch (status) { | 1015 | switch (status) { |
| 1016 | case SCTP_XMIT_PMTU_FULL: | 1016 | case SCTP_XMIT_PMTU_FULL: |
| 1017 | case SCTP_XMIT_RWND_FULL: | 1017 | case SCTP_XMIT_RWND_FULL: |
| 1018 | case SCTP_XMIT_NAGLE_DELAY: | 1018 | case SCTP_XMIT_DELAY: |
| 1019 | /* We could not append this chunk, so put | 1019 | /* We could not append this chunk, so put |
| 1020 | * the chunk back on the output queue. | 1020 | * the chunk back on the output queue. |
| 1021 | */ | 1021 | */ |
| @@ -1025,7 +1025,6 @@ static int sctp_outq_flush(struct sctp_outq *q, int rtx_timeout) | |||
| 1025 | 1025 | ||
| 1026 | sctp_outq_head_data(q, chunk); | 1026 | sctp_outq_head_data(q, chunk); |
| 1027 | goto sctp_flush_out; | 1027 | goto sctp_flush_out; |
| 1028 | break; | ||
| 1029 | 1028 | ||
| 1030 | case SCTP_XMIT_OK: | 1029 | case SCTP_XMIT_OK: |
| 1031 | /* The sender is in the SHUTDOWN-PENDING state, | 1030 | /* The sender is in the SHUTDOWN-PENDING state, |
diff --git a/net/sctp/protocol.c b/net/sctp/protocol.c index 6789d785e698..6240834f4b95 100644 --- a/net/sctp/protocol.c +++ b/net/sctp/protocol.c | |||
| @@ -576,10 +576,10 @@ out: | |||
| 576 | return newsk; | 576 | return newsk; |
| 577 | } | 577 | } |
| 578 | 578 | ||
| 579 | /* Map address, empty for v4 family */ | 579 | static int sctp_v4_addr_to_user(struct sctp_sock *sp, union sctp_addr *addr) |
| 580 | static void sctp_v4_addr_v4map(struct sctp_sock *sp, union sctp_addr *addr) | ||
| 581 | { | 580 | { |
| 582 | /* Empty */ | 581 | /* No address mapping for V4 sockets */ |
| 582 | return sizeof(struct sockaddr_in); | ||
| 583 | } | 583 | } |
| 584 | 584 | ||
| 585 | /* Dump the v4 addr to the seq file. */ | 585 | /* Dump the v4 addr to the seq file. */ |
| @@ -976,7 +976,9 @@ static struct sctp_pf sctp_pf_inet = { | |||
| 976 | .send_verify = sctp_inet_send_verify, | 976 | .send_verify = sctp_inet_send_verify, |
| 977 | .supported_addrs = sctp_inet_supported_addrs, | 977 | .supported_addrs = sctp_inet_supported_addrs, |
| 978 | .create_accept_sk = sctp_v4_create_accept_sk, | 978 | .create_accept_sk = sctp_v4_create_accept_sk, |
| 979 | .addr_v4map = sctp_v4_addr_v4map, | 979 | .addr_to_user = sctp_v4_addr_to_user, |
| 980 | .to_sk_saddr = sctp_v4_to_sk_saddr, | ||
| 981 | .to_sk_daddr = sctp_v4_to_sk_daddr, | ||
| 980 | .af = &sctp_af_inet | 982 | .af = &sctp_af_inet |
| 981 | }; | 983 | }; |
| 982 | 984 | ||
| @@ -1047,8 +1049,6 @@ static struct sctp_af sctp_af_inet = { | |||
| 1047 | .copy_addrlist = sctp_v4_copy_addrlist, | 1049 | .copy_addrlist = sctp_v4_copy_addrlist, |
| 1048 | .from_skb = sctp_v4_from_skb, | 1050 | .from_skb = sctp_v4_from_skb, |
| 1049 | .from_sk = sctp_v4_from_sk, | 1051 | .from_sk = sctp_v4_from_sk, |
| 1050 | .to_sk_saddr = sctp_v4_to_sk_saddr, | ||
| 1051 | .to_sk_daddr = sctp_v4_to_sk_daddr, | ||
| 1052 | .from_addr_param = sctp_v4_from_addr_param, | 1052 | .from_addr_param = sctp_v4_from_addr_param, |
| 1053 | .to_addr_param = sctp_v4_to_addr_param, | 1053 | .to_addr_param = sctp_v4_to_addr_param, |
| 1054 | .cmp_addr = sctp_v4_cmp_addr, | 1054 | .cmp_addr = sctp_v4_cmp_addr, |
diff --git a/net/sctp/sm_statefuns.c b/net/sctp/sm_statefuns.c index 5170a1ff95a1..d3f1ea460c50 100644 --- a/net/sctp/sm_statefuns.c +++ b/net/sctp/sm_statefuns.c | |||
| @@ -4182,7 +4182,6 @@ sctp_disposition_t sctp_sf_unk_chunk(struct net *net, | |||
| 4182 | case SCTP_CID_ACTION_DISCARD: | 4182 | case SCTP_CID_ACTION_DISCARD: |
| 4183 | /* Discard the packet. */ | 4183 | /* Discard the packet. */ |
| 4184 | return sctp_sf_pdiscard(net, ep, asoc, type, arg, commands); | 4184 | return sctp_sf_pdiscard(net, ep, asoc, type, arg, commands); |
| 4185 | break; | ||
| 4186 | case SCTP_CID_ACTION_DISCARD_ERR: | 4185 | case SCTP_CID_ACTION_DISCARD_ERR: |
| 4187 | /* Generate an ERROR chunk as response. */ | 4186 | /* Generate an ERROR chunk as response. */ |
| 4188 | hdr = unk_chunk->chunk_hdr; | 4187 | hdr = unk_chunk->chunk_hdr; |
| @@ -4198,11 +4197,9 @@ sctp_disposition_t sctp_sf_unk_chunk(struct net *net, | |||
| 4198 | /* Discard the packet. */ | 4197 | /* Discard the packet. */ |
| 4199 | sctp_sf_pdiscard(net, ep, asoc, type, arg, commands); | 4198 | sctp_sf_pdiscard(net, ep, asoc, type, arg, commands); |
| 4200 | return SCTP_DISPOSITION_CONSUME; | 4199 | return SCTP_DISPOSITION_CONSUME; |
| 4201 | break; | ||
| 4202 | case SCTP_CID_ACTION_SKIP: | 4200 | case SCTP_CID_ACTION_SKIP: |
| 4203 | /* Skip the chunk. */ | 4201 | /* Skip the chunk. */ |
| 4204 | return SCTP_DISPOSITION_DISCARD; | 4202 | return SCTP_DISPOSITION_DISCARD; |
| 4205 | break; | ||
| 4206 | case SCTP_CID_ACTION_SKIP_ERR: | 4203 | case SCTP_CID_ACTION_SKIP_ERR: |
| 4207 | /* Generate an ERROR chunk as response. */ | 4204 | /* Generate an ERROR chunk as response. */ |
| 4208 | hdr = unk_chunk->chunk_hdr; | 4205 | hdr = unk_chunk->chunk_hdr; |
| @@ -4216,7 +4213,6 @@ sctp_disposition_t sctp_sf_unk_chunk(struct net *net, | |||
| 4216 | } | 4213 | } |
| 4217 | /* Skip the chunk. */ | 4214 | /* Skip the chunk. */ |
| 4218 | return SCTP_DISPOSITION_CONSUME; | 4215 | return SCTP_DISPOSITION_CONSUME; |
| 4219 | break; | ||
| 4220 | default: | 4216 | default: |
| 4221 | break; | 4217 | break; |
| 4222 | } | 4218 | } |
diff --git a/net/sctp/socket.c b/net/sctp/socket.c index 429899689408..eb71d49e7653 100644 --- a/net/sctp/socket.c +++ b/net/sctp/socket.c | |||
| @@ -254,7 +254,7 @@ static struct sctp_transport *sctp_addr_id2transport(struct sock *sk, | |||
| 254 | if (id_asoc && (id_asoc != addr_asoc)) | 254 | if (id_asoc && (id_asoc != addr_asoc)) |
| 255 | return NULL; | 255 | return NULL; |
| 256 | 256 | ||
| 257 | sctp_get_pf_specific(sk->sk_family)->addr_v4map(sctp_sk(sk), | 257 | sctp_get_pf_specific(sk->sk_family)->addr_to_user(sctp_sk(sk), |
| 258 | (union sctp_addr *)addr); | 258 | (union sctp_addr *)addr); |
| 259 | 259 | ||
| 260 | return transport; | 260 | return transport; |
| @@ -396,7 +396,7 @@ static int sctp_do_bind(struct sock *sk, union sctp_addr *addr, int len) | |||
| 396 | /* Copy back into socket for getsockname() use. */ | 396 | /* Copy back into socket for getsockname() use. */ |
| 397 | if (!ret) { | 397 | if (!ret) { |
| 398 | inet_sk(sk)->inet_sport = htons(inet_sk(sk)->inet_num); | 398 | inet_sk(sk)->inet_sport = htons(inet_sk(sk)->inet_num); |
| 399 | af->to_sk_saddr(addr, sk); | 399 | sp->pf->to_sk_saddr(addr, sk); |
| 400 | } | 400 | } |
| 401 | 401 | ||
| 402 | return ret; | 402 | return ret; |
| @@ -1053,7 +1053,6 @@ static int __sctp_connect(struct sock *sk, | |||
| 1053 | struct sctp_association *asoc2; | 1053 | struct sctp_association *asoc2; |
| 1054 | struct sctp_transport *transport; | 1054 | struct sctp_transport *transport; |
| 1055 | union sctp_addr to; | 1055 | union sctp_addr to; |
| 1056 | struct sctp_af *af; | ||
| 1057 | sctp_scope_t scope; | 1056 | sctp_scope_t scope; |
| 1058 | long timeo; | 1057 | long timeo; |
| 1059 | int err = 0; | 1058 | int err = 0; |
| @@ -1081,6 +1080,8 @@ static int __sctp_connect(struct sock *sk, | |||
| 1081 | /* Walk through the addrs buffer and count the number of addresses. */ | 1080 | /* Walk through the addrs buffer and count the number of addresses. */ |
| 1082 | addr_buf = kaddrs; | 1081 | addr_buf = kaddrs; |
| 1083 | while (walk_size < addrs_size) { | 1082 | while (walk_size < addrs_size) { |
| 1083 | struct sctp_af *af; | ||
| 1084 | |||
| 1084 | if (walk_size + sizeof(sa_family_t) > addrs_size) { | 1085 | if (walk_size + sizeof(sa_family_t) > addrs_size) { |
| 1085 | err = -EINVAL; | 1086 | err = -EINVAL; |
| 1086 | goto out_free; | 1087 | goto out_free; |
| @@ -1205,8 +1206,7 @@ static int __sctp_connect(struct sock *sk, | |||
| 1205 | 1206 | ||
| 1206 | /* Initialize sk's dport and daddr for getpeername() */ | 1207 | /* Initialize sk's dport and daddr for getpeername() */ |
| 1207 | inet_sk(sk)->inet_dport = htons(asoc->peer.port); | 1208 | inet_sk(sk)->inet_dport = htons(asoc->peer.port); |
| 1208 | af = sctp_get_af_specific(sa_addr->sa.sa_family); | 1209 | sp->pf->to_sk_daddr(sa_addr, sk); |
| 1209 | af->to_sk_daddr(sa_addr, sk); | ||
| 1210 | sk->sk_err = 0; | 1210 | sk->sk_err = 0; |
| 1211 | 1211 | ||
| 1212 | /* in-kernel sockets don't generally have a file allocated to them | 1212 | /* in-kernel sockets don't generally have a file allocated to them |
| @@ -1602,12 +1602,13 @@ static int sctp_sendmsg(struct kiocb *iocb, struct sock *sk, | |||
| 1602 | struct sctp_initmsg *sinit; | 1602 | struct sctp_initmsg *sinit; |
| 1603 | sctp_assoc_t associd = 0; | 1603 | sctp_assoc_t associd = 0; |
| 1604 | sctp_cmsgs_t cmsgs = { NULL }; | 1604 | sctp_cmsgs_t cmsgs = { NULL }; |
| 1605 | int err; | ||
| 1606 | sctp_scope_t scope; | 1605 | sctp_scope_t scope; |
| 1607 | long timeo; | 1606 | bool fill_sinfo_ttl = false; |
| 1608 | __u16 sinfo_flags = 0; | ||
| 1609 | struct sctp_datamsg *datamsg; | 1607 | struct sctp_datamsg *datamsg; |
| 1610 | int msg_flags = msg->msg_flags; | 1608 | int msg_flags = msg->msg_flags; |
| 1609 | __u16 sinfo_flags = 0; | ||
| 1610 | long timeo; | ||
| 1611 | int err; | ||
| 1611 | 1612 | ||
| 1612 | err = 0; | 1613 | err = 0; |
| 1613 | sp = sctp_sk(sk); | 1614 | sp = sctp_sk(sk); |
| @@ -1648,10 +1649,21 @@ static int sctp_sendmsg(struct kiocb *iocb, struct sock *sk, | |||
| 1648 | msg_name = msg->msg_name; | 1649 | msg_name = msg->msg_name; |
| 1649 | } | 1650 | } |
| 1650 | 1651 | ||
| 1651 | sinfo = cmsgs.info; | ||
| 1652 | sinit = cmsgs.init; | 1652 | sinit = cmsgs.init; |
| 1653 | if (cmsgs.sinfo != NULL) { | ||
| 1654 | memset(&default_sinfo, 0, sizeof(default_sinfo)); | ||
| 1655 | default_sinfo.sinfo_stream = cmsgs.sinfo->snd_sid; | ||
| 1656 | default_sinfo.sinfo_flags = cmsgs.sinfo->snd_flags; | ||
| 1657 | default_sinfo.sinfo_ppid = cmsgs.sinfo->snd_ppid; | ||
| 1658 | default_sinfo.sinfo_context = cmsgs.sinfo->snd_context; | ||
| 1659 | default_sinfo.sinfo_assoc_id = cmsgs.sinfo->snd_assoc_id; | ||
| 1653 | 1660 | ||
| 1654 | /* Did the user specify SNDRCVINFO? */ | 1661 | sinfo = &default_sinfo; |
| 1662 | fill_sinfo_ttl = true; | ||
| 1663 | } else { | ||
| 1664 | sinfo = cmsgs.srinfo; | ||
| 1665 | } | ||
| 1666 | /* Did the user specify SNDINFO/SNDRCVINFO? */ | ||
| 1655 | if (sinfo) { | 1667 | if (sinfo) { |
| 1656 | sinfo_flags = sinfo->sinfo_flags; | 1668 | sinfo_flags = sinfo->sinfo_flags; |
| 1657 | associd = sinfo->sinfo_assoc_id; | 1669 | associd = sinfo->sinfo_assoc_id; |
| @@ -1858,8 +1870,8 @@ static int sctp_sendmsg(struct kiocb *iocb, struct sock *sk, | |||
| 1858 | pr_debug("%s: we have a valid association\n", __func__); | 1870 | pr_debug("%s: we have a valid association\n", __func__); |
| 1859 | 1871 | ||
| 1860 | if (!sinfo) { | 1872 | if (!sinfo) { |
| 1861 | /* If the user didn't specify SNDRCVINFO, make up one with | 1873 | /* If the user didn't specify SNDINFO/SNDRCVINFO, make up |
| 1862 | * some defaults. | 1874 | * one with some defaults. |
| 1863 | */ | 1875 | */ |
| 1864 | memset(&default_sinfo, 0, sizeof(default_sinfo)); | 1876 | memset(&default_sinfo, 0, sizeof(default_sinfo)); |
| 1865 | default_sinfo.sinfo_stream = asoc->default_stream; | 1877 | default_sinfo.sinfo_stream = asoc->default_stream; |
| @@ -1868,7 +1880,13 @@ static int sctp_sendmsg(struct kiocb *iocb, struct sock *sk, | |||
| 1868 | default_sinfo.sinfo_context = asoc->default_context; | 1880 | default_sinfo.sinfo_context = asoc->default_context; |
| 1869 | default_sinfo.sinfo_timetolive = asoc->default_timetolive; | 1881 | default_sinfo.sinfo_timetolive = asoc->default_timetolive; |
| 1870 | default_sinfo.sinfo_assoc_id = sctp_assoc2id(asoc); | 1882 | default_sinfo.sinfo_assoc_id = sctp_assoc2id(asoc); |
| 1883 | |||
| 1871 | sinfo = &default_sinfo; | 1884 | sinfo = &default_sinfo; |
| 1885 | } else if (fill_sinfo_ttl) { | ||
| 1886 | /* In case SNDINFO was specified, we still need to fill | ||
| 1887 | * it with a default ttl from the assoc here. | ||
| 1888 | */ | ||
| 1889 | sinfo->sinfo_timetolive = asoc->default_timetolive; | ||
| 1872 | } | 1890 | } |
| 1873 | 1891 | ||
| 1874 | /* API 7.1.7, the sndbuf size per association bounds the | 1892 | /* API 7.1.7, the sndbuf size per association bounds the |
| @@ -2042,8 +2060,6 @@ static int sctp_skb_pull(struct sk_buff *skb, int len) | |||
| 2042 | * flags - flags sent or received with the user message, see Section | 2060 | * flags - flags sent or received with the user message, see Section |
| 2043 | * 5 for complete description of the flags. | 2061 | * 5 for complete description of the flags. |
| 2044 | */ | 2062 | */ |
| 2045 | static struct sk_buff *sctp_skb_recv_datagram(struct sock *, int, int, int *); | ||
| 2046 | |||
| 2047 | static int sctp_recvmsg(struct kiocb *iocb, struct sock *sk, | 2063 | static int sctp_recvmsg(struct kiocb *iocb, struct sock *sk, |
| 2048 | struct msghdr *msg, size_t len, int noblock, | 2064 | struct msghdr *msg, size_t len, int noblock, |
| 2049 | int flags, int *addr_len) | 2065 | int flags, int *addr_len) |
| @@ -2094,9 +2110,16 @@ static int sctp_recvmsg(struct kiocb *iocb, struct sock *sk, | |||
| 2094 | sp->pf->skb_msgname(skb, msg->msg_name, addr_len); | 2110 | sp->pf->skb_msgname(skb, msg->msg_name, addr_len); |
| 2095 | } | 2111 | } |
| 2096 | 2112 | ||
| 2113 | /* Check if we allow SCTP_NXTINFO. */ | ||
| 2114 | if (sp->recvnxtinfo) | ||
| 2115 | sctp_ulpevent_read_nxtinfo(event, msg, sk); | ||
| 2116 | /* Check if we allow SCTP_RCVINFO. */ | ||
| 2117 | if (sp->recvrcvinfo) | ||
| 2118 | sctp_ulpevent_read_rcvinfo(event, msg); | ||
| 2097 | /* Check if we allow SCTP_SNDRCVINFO. */ | 2119 | /* Check if we allow SCTP_SNDRCVINFO. */ |
| 2098 | if (sp->subscribe.sctp_data_io_event) | 2120 | if (sp->subscribe.sctp_data_io_event) |
| 2099 | sctp_ulpevent_read_sndrcvinfo(event, msg); | 2121 | sctp_ulpevent_read_sndrcvinfo(event, msg); |
| 2122 | |||
| 2100 | #if 0 | 2123 | #if 0 |
| 2101 | /* FIXME: we should be calling IP/IPv6 layers. */ | 2124 | /* FIXME: we should be calling IP/IPv6 layers. */ |
| 2102 | if (sk->sk_protinfo.af_inet.cmsg_flags) | 2125 | if (sk->sk_protinfo.af_inet.cmsg_flags) |
| @@ -2182,8 +2205,13 @@ static int sctp_setsockopt_events(struct sock *sk, char __user *optval, | |||
| 2182 | if (copy_from_user(&sctp_sk(sk)->subscribe, optval, optlen)) | 2205 | if (copy_from_user(&sctp_sk(sk)->subscribe, optval, optlen)) |
| 2183 | return -EFAULT; | 2206 | return -EFAULT; |
| 2184 | 2207 | ||
| 2185 | /* | 2208 | if (sctp_sk(sk)->subscribe.sctp_data_io_event) |
| 2186 | * At the time when a user app subscribes to SCTP_SENDER_DRY_EVENT, | 2209 | pr_warn_ratelimited(DEPRECATED "%s (pid %d) " |
| 2210 | "Requested SCTP_SNDRCVINFO event.\n" | ||
| 2211 | "Use SCTP_RCVINFO through SCTP_RECVRCVINFO option instead.\n", | ||
| 2212 | current->comm, task_pid_nr(current)); | ||
| 2213 | |||
| 2214 | /* At the time when a user app subscribes to SCTP_SENDER_DRY_EVENT, | ||
| 2187 | * if there is no data to be sent or retransmit, the stack will | 2215 | * if there is no data to be sent or retransmit, the stack will |
| 2188 | * immediately send up this notification. | 2216 | * immediately send up this notification. |
| 2189 | */ | 2217 | */ |
| @@ -2747,19 +2775,22 @@ static int sctp_setsockopt_default_send_param(struct sock *sk, | |||
| 2747 | char __user *optval, | 2775 | char __user *optval, |
| 2748 | unsigned int optlen) | 2776 | unsigned int optlen) |
| 2749 | { | 2777 | { |
| 2750 | struct sctp_sndrcvinfo info; | ||
| 2751 | struct sctp_association *asoc; | ||
| 2752 | struct sctp_sock *sp = sctp_sk(sk); | 2778 | struct sctp_sock *sp = sctp_sk(sk); |
| 2779 | struct sctp_association *asoc; | ||
| 2780 | struct sctp_sndrcvinfo info; | ||
| 2753 | 2781 | ||
| 2754 | if (optlen != sizeof(struct sctp_sndrcvinfo)) | 2782 | if (optlen != sizeof(info)) |
| 2755 | return -EINVAL; | 2783 | return -EINVAL; |
| 2756 | if (copy_from_user(&info, optval, optlen)) | 2784 | if (copy_from_user(&info, optval, optlen)) |
| 2757 | return -EFAULT; | 2785 | return -EFAULT; |
| 2786 | if (info.sinfo_flags & | ||
| 2787 | ~(SCTP_UNORDERED | SCTP_ADDR_OVER | | ||
| 2788 | SCTP_ABORT | SCTP_EOF)) | ||
| 2789 | return -EINVAL; | ||
| 2758 | 2790 | ||
| 2759 | asoc = sctp_id2assoc(sk, info.sinfo_assoc_id); | 2791 | asoc = sctp_id2assoc(sk, info.sinfo_assoc_id); |
| 2760 | if (!asoc && info.sinfo_assoc_id && sctp_style(sk, UDP)) | 2792 | if (!asoc && info.sinfo_assoc_id && sctp_style(sk, UDP)) |
| 2761 | return -EINVAL; | 2793 | return -EINVAL; |
| 2762 | |||
| 2763 | if (asoc) { | 2794 | if (asoc) { |
| 2764 | asoc->default_stream = info.sinfo_stream; | 2795 | asoc->default_stream = info.sinfo_stream; |
| 2765 | asoc->default_flags = info.sinfo_flags; | 2796 | asoc->default_flags = info.sinfo_flags; |
| @@ -2777,6 +2808,44 @@ static int sctp_setsockopt_default_send_param(struct sock *sk, | |||
| 2777 | return 0; | 2808 | return 0; |
| 2778 | } | 2809 | } |
| 2779 | 2810 | ||
| 2811 | /* RFC6458, Section 8.1.31. Set/get Default Send Parameters | ||
| 2812 | * (SCTP_DEFAULT_SNDINFO) | ||
| 2813 | */ | ||
| 2814 | static int sctp_setsockopt_default_sndinfo(struct sock *sk, | ||
| 2815 | char __user *optval, | ||
| 2816 | unsigned int optlen) | ||
| 2817 | { | ||
| 2818 | struct sctp_sock *sp = sctp_sk(sk); | ||
| 2819 | struct sctp_association *asoc; | ||
| 2820 | struct sctp_sndinfo info; | ||
| 2821 | |||
| 2822 | if (optlen != sizeof(info)) | ||
| 2823 | return -EINVAL; | ||
| 2824 | if (copy_from_user(&info, optval, optlen)) | ||
| 2825 | return -EFAULT; | ||
| 2826 | if (info.snd_flags & | ||
| 2827 | ~(SCTP_UNORDERED | SCTP_ADDR_OVER | | ||
| 2828 | SCTP_ABORT | SCTP_EOF)) | ||
| 2829 | return -EINVAL; | ||
| 2830 | |||
| 2831 | asoc = sctp_id2assoc(sk, info.snd_assoc_id); | ||
| 2832 | if (!asoc && info.snd_assoc_id && sctp_style(sk, UDP)) | ||
| 2833 | return -EINVAL; | ||
| 2834 | if (asoc) { | ||
| 2835 | asoc->default_stream = info.snd_sid; | ||
| 2836 | asoc->default_flags = info.snd_flags; | ||
| 2837 | asoc->default_ppid = info.snd_ppid; | ||
| 2838 | asoc->default_context = info.snd_context; | ||
| 2839 | } else { | ||
| 2840 | sp->default_stream = info.snd_sid; | ||
| 2841 | sp->default_flags = info.snd_flags; | ||
| 2842 | sp->default_ppid = info.snd_ppid; | ||
| 2843 | sp->default_context = info.snd_context; | ||
| 2844 | } | ||
| 2845 | |||
| 2846 | return 0; | ||
| 2847 | } | ||
| 2848 | |||
| 2780 | /* 7.1.10 Set Primary Address (SCTP_PRIMARY_ADDR) | 2849 | /* 7.1.10 Set Primary Address (SCTP_PRIMARY_ADDR) |
| 2781 | * | 2850 | * |
| 2782 | * Requests that the local SCTP stack use the enclosed peer address as | 2851 | * Requests that the local SCTP stack use the enclosed peer address as |
| @@ -3523,7 +3592,6 @@ static int sctp_setsockopt_auto_asconf(struct sock *sk, char __user *optval, | |||
| 3523 | return 0; | 3592 | return 0; |
| 3524 | } | 3593 | } |
| 3525 | 3594 | ||
| 3526 | |||
| 3527 | /* | 3595 | /* |
| 3528 | * SCTP_PEER_ADDR_THLDS | 3596 | * SCTP_PEER_ADDR_THLDS |
| 3529 | * | 3597 | * |
| @@ -3574,6 +3642,38 @@ static int sctp_setsockopt_paddr_thresholds(struct sock *sk, | |||
| 3574 | return 0; | 3642 | return 0; |
| 3575 | } | 3643 | } |
| 3576 | 3644 | ||
| 3645 | static int sctp_setsockopt_recvrcvinfo(struct sock *sk, | ||
| 3646 | char __user *optval, | ||
| 3647 | unsigned int optlen) | ||
| 3648 | { | ||
| 3649 | int val; | ||
| 3650 | |||
| 3651 | if (optlen < sizeof(int)) | ||
| 3652 | return -EINVAL; | ||
| 3653 | if (get_user(val, (int __user *) optval)) | ||
| 3654 | return -EFAULT; | ||
| 3655 | |||
| 3656 | sctp_sk(sk)->recvrcvinfo = (val == 0) ? 0 : 1; | ||
| 3657 | |||
| 3658 | return 0; | ||
| 3659 | } | ||
| 3660 | |||
| 3661 | static int sctp_setsockopt_recvnxtinfo(struct sock *sk, | ||
| 3662 | char __user *optval, | ||
| 3663 | unsigned int optlen) | ||
| 3664 | { | ||
| 3665 | int val; | ||
| 3666 | |||
| 3667 | if (optlen < sizeof(int)) | ||
| 3668 | return -EINVAL; | ||
| 3669 | if (get_user(val, (int __user *) optval)) | ||
| 3670 | return -EFAULT; | ||
| 3671 | |||
| 3672 | sctp_sk(sk)->recvnxtinfo = (val == 0) ? 0 : 1; | ||
| 3673 | |||
| 3674 | return 0; | ||
| 3675 | } | ||
| 3676 | |||
| 3577 | /* API 6.2 setsockopt(), getsockopt() | 3677 | /* API 6.2 setsockopt(), getsockopt() |
| 3578 | * | 3678 | * |
| 3579 | * Applications use setsockopt() and getsockopt() to set or retrieve | 3679 | * Applications use setsockopt() and getsockopt() to set or retrieve |
| @@ -3671,6 +3771,9 @@ static int sctp_setsockopt(struct sock *sk, int level, int optname, | |||
| 3671 | retval = sctp_setsockopt_default_send_param(sk, optval, | 3771 | retval = sctp_setsockopt_default_send_param(sk, optval, |
| 3672 | optlen); | 3772 | optlen); |
| 3673 | break; | 3773 | break; |
| 3774 | case SCTP_DEFAULT_SNDINFO: | ||
| 3775 | retval = sctp_setsockopt_default_sndinfo(sk, optval, optlen); | ||
| 3776 | break; | ||
| 3674 | case SCTP_PRIMARY_ADDR: | 3777 | case SCTP_PRIMARY_ADDR: |
| 3675 | retval = sctp_setsockopt_primary_addr(sk, optval, optlen); | 3778 | retval = sctp_setsockopt_primary_addr(sk, optval, optlen); |
| 3676 | break; | 3779 | break; |
| @@ -3725,6 +3828,12 @@ static int sctp_setsockopt(struct sock *sk, int level, int optname, | |||
| 3725 | case SCTP_PEER_ADDR_THLDS: | 3828 | case SCTP_PEER_ADDR_THLDS: |
| 3726 | retval = sctp_setsockopt_paddr_thresholds(sk, optval, optlen); | 3829 | retval = sctp_setsockopt_paddr_thresholds(sk, optval, optlen); |
| 3727 | break; | 3830 | break; |
| 3831 | case SCTP_RECVRCVINFO: | ||
| 3832 | retval = sctp_setsockopt_recvrcvinfo(sk, optval, optlen); | ||
| 3833 | break; | ||
| 3834 | case SCTP_RECVNXTINFO: | ||
| 3835 | retval = sctp_setsockopt_recvnxtinfo(sk, optval, optlen); | ||
| 3836 | break; | ||
| 3728 | default: | 3837 | default: |
| 3729 | retval = -ENOPROTOOPT; | 3838 | retval = -ENOPROTOOPT; |
| 3730 | break; | 3839 | break; |
| @@ -3971,6 +4080,9 @@ static int sctp_init_sock(struct sock *sk) | |||
| 3971 | /* Enable Nagle algorithm by default. */ | 4080 | /* Enable Nagle algorithm by default. */ |
| 3972 | sp->nodelay = 0; | 4081 | sp->nodelay = 0; |
| 3973 | 4082 | ||
| 4083 | sp->recvrcvinfo = 0; | ||
| 4084 | sp->recvnxtinfo = 0; | ||
| 4085 | |||
| 3974 | /* Enable by default. */ | 4086 | /* Enable by default. */ |
| 3975 | sp->v4mapped = 1; | 4087 | sp->v4mapped = 1; |
| 3976 | 4088 | ||
| @@ -4143,7 +4255,7 @@ static int sctp_getsockopt_sctp_status(struct sock *sk, int len, | |||
| 4143 | memcpy(&status.sstat_primary.spinfo_address, &transport->ipaddr, | 4255 | memcpy(&status.sstat_primary.spinfo_address, &transport->ipaddr, |
| 4144 | transport->af_specific->sockaddr_len); | 4256 | transport->af_specific->sockaddr_len); |
| 4145 | /* Map ipv4 address into v4-mapped-on-v6 address. */ | 4257 | /* Map ipv4 address into v4-mapped-on-v6 address. */ |
| 4146 | sctp_get_pf_specific(sk->sk_family)->addr_v4map(sctp_sk(sk), | 4258 | sctp_get_pf_specific(sk->sk_family)->addr_to_user(sctp_sk(sk), |
| 4147 | (union sctp_addr *)&status.sstat_primary.spinfo_address); | 4259 | (union sctp_addr *)&status.sstat_primary.spinfo_address); |
| 4148 | status.sstat_primary.spinfo_state = transport->state; | 4260 | status.sstat_primary.spinfo_state = transport->state; |
| 4149 | status.sstat_primary.spinfo_cwnd = transport->cwnd; | 4261 | status.sstat_primary.spinfo_cwnd = transport->cwnd; |
| @@ -4301,8 +4413,8 @@ static int sctp_getsockopt_autoclose(struct sock *sk, int len, char __user *optv | |||
| 4301 | int sctp_do_peeloff(struct sock *sk, sctp_assoc_t id, struct socket **sockp) | 4413 | int sctp_do_peeloff(struct sock *sk, sctp_assoc_t id, struct socket **sockp) |
| 4302 | { | 4414 | { |
| 4303 | struct sctp_association *asoc = sctp_id2assoc(sk, id); | 4415 | struct sctp_association *asoc = sctp_id2assoc(sk, id); |
| 4416 | struct sctp_sock *sp = sctp_sk(sk); | ||
| 4304 | struct socket *sock; | 4417 | struct socket *sock; |
| 4305 | struct sctp_af *af; | ||
| 4306 | int err = 0; | 4418 | int err = 0; |
| 4307 | 4419 | ||
| 4308 | if (!asoc) | 4420 | if (!asoc) |
| @@ -4324,8 +4436,7 @@ int sctp_do_peeloff(struct sock *sk, sctp_assoc_t id, struct socket **sockp) | |||
| 4324 | /* Make peeled-off sockets more like 1-1 accepted sockets. | 4436 | /* Make peeled-off sockets more like 1-1 accepted sockets. |
| 4325 | * Set the daddr and initialize id to something more random | 4437 | * Set the daddr and initialize id to something more random |
| 4326 | */ | 4438 | */ |
| 4327 | af = sctp_get_af_specific(asoc->peer.primary_addr.sa.sa_family); | 4439 | sp->pf->to_sk_daddr(&asoc->peer.primary_addr, sk); |
| 4328 | af->to_sk_daddr(&asoc->peer.primary_addr, sk); | ||
| 4329 | 4440 | ||
| 4330 | /* Populate the fields of the newsk from the oldsk and migrate the | 4441 | /* Populate the fields of the newsk from the oldsk and migrate the |
| 4331 | * asoc to the newsk. | 4442 | * asoc to the newsk. |
| @@ -4709,8 +4820,8 @@ static int sctp_getsockopt_peer_addrs(struct sock *sk, int len, | |||
| 4709 | list_for_each_entry(from, &asoc->peer.transport_addr_list, | 4820 | list_for_each_entry(from, &asoc->peer.transport_addr_list, |
| 4710 | transports) { | 4821 | transports) { |
| 4711 | memcpy(&temp, &from->ipaddr, sizeof(temp)); | 4822 | memcpy(&temp, &from->ipaddr, sizeof(temp)); |
| 4712 | sctp_get_pf_specific(sk->sk_family)->addr_v4map(sp, &temp); | 4823 | addrlen = sctp_get_pf_specific(sk->sk_family) |
| 4713 | addrlen = sctp_get_af_specific(temp.sa.sa_family)->sockaddr_len; | 4824 | ->addr_to_user(sp, &temp); |
| 4714 | if (space_left < addrlen) | 4825 | if (space_left < addrlen) |
| 4715 | return -ENOMEM; | 4826 | return -ENOMEM; |
| 4716 | if (copy_to_user(to, &temp, addrlen)) | 4827 | if (copy_to_user(to, &temp, addrlen)) |
| @@ -4754,9 +4865,9 @@ static int sctp_copy_laddrs(struct sock *sk, __u16 port, void *to, | |||
| 4754 | if (!temp.v4.sin_port) | 4865 | if (!temp.v4.sin_port) |
| 4755 | temp.v4.sin_port = htons(port); | 4866 | temp.v4.sin_port = htons(port); |
| 4756 | 4867 | ||
| 4757 | sctp_get_pf_specific(sk->sk_family)->addr_v4map(sctp_sk(sk), | 4868 | addrlen = sctp_get_pf_specific(sk->sk_family) |
| 4758 | &temp); | 4869 | ->addr_to_user(sctp_sk(sk), &temp); |
| 4759 | addrlen = sctp_get_af_specific(temp.sa.sa_family)->sockaddr_len; | 4870 | |
| 4760 | if (space_left < addrlen) { | 4871 | if (space_left < addrlen) { |
| 4761 | cnt = -ENOMEM; | 4872 | cnt = -ENOMEM; |
| 4762 | break; | 4873 | break; |
| @@ -4844,8 +4955,8 @@ static int sctp_getsockopt_local_addrs(struct sock *sk, int len, | |||
| 4844 | */ | 4955 | */ |
| 4845 | list_for_each_entry(addr, &bp->address_list, list) { | 4956 | list_for_each_entry(addr, &bp->address_list, list) { |
| 4846 | memcpy(&temp, &addr->a, sizeof(temp)); | 4957 | memcpy(&temp, &addr->a, sizeof(temp)); |
| 4847 | sctp_get_pf_specific(sk->sk_family)->addr_v4map(sp, &temp); | 4958 | addrlen = sctp_get_pf_specific(sk->sk_family) |
| 4848 | addrlen = sctp_get_af_specific(temp.sa.sa_family)->sockaddr_len; | 4959 | ->addr_to_user(sp, &temp); |
| 4849 | if (space_left < addrlen) { | 4960 | if (space_left < addrlen) { |
| 4850 | err = -ENOMEM; /*fixme: right error?*/ | 4961 | err = -ENOMEM; /*fixme: right error?*/ |
| 4851 | goto out; | 4962 | goto out; |
| @@ -4904,7 +5015,7 @@ static int sctp_getsockopt_primary_addr(struct sock *sk, int len, | |||
| 4904 | memcpy(&prim.ssp_addr, &asoc->peer.primary_path->ipaddr, | 5015 | memcpy(&prim.ssp_addr, &asoc->peer.primary_path->ipaddr, |
| 4905 | asoc->peer.primary_path->af_specific->sockaddr_len); | 5016 | asoc->peer.primary_path->af_specific->sockaddr_len); |
| 4906 | 5017 | ||
| 4907 | sctp_get_pf_specific(sk->sk_family)->addr_v4map(sp, | 5018 | sctp_get_pf_specific(sk->sk_family)->addr_to_user(sp, |
| 4908 | (union sctp_addr *)&prim.ssp_addr); | 5019 | (union sctp_addr *)&prim.ssp_addr); |
| 4909 | 5020 | ||
| 4910 | if (put_user(len, optlen)) | 5021 | if (put_user(len, optlen)) |
| @@ -4964,14 +5075,14 @@ static int sctp_getsockopt_default_send_param(struct sock *sk, | |||
| 4964 | int len, char __user *optval, | 5075 | int len, char __user *optval, |
| 4965 | int __user *optlen) | 5076 | int __user *optlen) |
| 4966 | { | 5077 | { |
| 4967 | struct sctp_sndrcvinfo info; | ||
| 4968 | struct sctp_association *asoc; | ||
| 4969 | struct sctp_sock *sp = sctp_sk(sk); | 5078 | struct sctp_sock *sp = sctp_sk(sk); |
| 5079 | struct sctp_association *asoc; | ||
| 5080 | struct sctp_sndrcvinfo info; | ||
| 4970 | 5081 | ||
| 4971 | if (len < sizeof(struct sctp_sndrcvinfo)) | 5082 | if (len < sizeof(info)) |
| 4972 | return -EINVAL; | 5083 | return -EINVAL; |
| 4973 | 5084 | ||
| 4974 | len = sizeof(struct sctp_sndrcvinfo); | 5085 | len = sizeof(info); |
| 4975 | 5086 | ||
| 4976 | if (copy_from_user(&info, optval, len)) | 5087 | if (copy_from_user(&info, optval, len)) |
| 4977 | return -EFAULT; | 5088 | return -EFAULT; |
| @@ -4979,7 +5090,6 @@ static int sctp_getsockopt_default_send_param(struct sock *sk, | |||
| 4979 | asoc = sctp_id2assoc(sk, info.sinfo_assoc_id); | 5090 | asoc = sctp_id2assoc(sk, info.sinfo_assoc_id); |
| 4980 | if (!asoc && info.sinfo_assoc_id && sctp_style(sk, UDP)) | 5091 | if (!asoc && info.sinfo_assoc_id && sctp_style(sk, UDP)) |
| 4981 | return -EINVAL; | 5092 | return -EINVAL; |
| 4982 | |||
| 4983 | if (asoc) { | 5093 | if (asoc) { |
| 4984 | info.sinfo_stream = asoc->default_stream; | 5094 | info.sinfo_stream = asoc->default_stream; |
| 4985 | info.sinfo_flags = asoc->default_flags; | 5095 | info.sinfo_flags = asoc->default_flags; |
| @@ -5002,6 +5112,48 @@ static int sctp_getsockopt_default_send_param(struct sock *sk, | |||
| 5002 | return 0; | 5112 | return 0; |
| 5003 | } | 5113 | } |
| 5004 | 5114 | ||
| 5115 | /* RFC6458, Section 8.1.31. Set/get Default Send Parameters | ||
| 5116 | * (SCTP_DEFAULT_SNDINFO) | ||
| 5117 | */ | ||
| 5118 | static int sctp_getsockopt_default_sndinfo(struct sock *sk, int len, | ||
| 5119 | char __user *optval, | ||
| 5120 | int __user *optlen) | ||
| 5121 | { | ||
| 5122 | struct sctp_sock *sp = sctp_sk(sk); | ||
| 5123 | struct sctp_association *asoc; | ||
| 5124 | struct sctp_sndinfo info; | ||
| 5125 | |||
| 5126 | if (len < sizeof(info)) | ||
| 5127 | return -EINVAL; | ||
| 5128 | |||
| 5129 | len = sizeof(info); | ||
| 5130 | |||
| 5131 | if (copy_from_user(&info, optval, len)) | ||
| 5132 | return -EFAULT; | ||
| 5133 | |||
| 5134 | asoc = sctp_id2assoc(sk, info.snd_assoc_id); | ||
| 5135 | if (!asoc && info.snd_assoc_id && sctp_style(sk, UDP)) | ||
| 5136 | return -EINVAL; | ||
| 5137 | if (asoc) { | ||
| 5138 | info.snd_sid = asoc->default_stream; | ||
| 5139 | info.snd_flags = asoc->default_flags; | ||
| 5140 | info.snd_ppid = asoc->default_ppid; | ||
| 5141 | info.snd_context = asoc->default_context; | ||
| 5142 | } else { | ||
| 5143 | info.snd_sid = sp->default_stream; | ||
| 5144 | info.snd_flags = sp->default_flags; | ||
| 5145 | info.snd_ppid = sp->default_ppid; | ||
| 5146 | info.snd_context = sp->default_context; | ||
| 5147 | } | ||
| 5148 | |||
| 5149 | if (put_user(len, optlen)) | ||
| 5150 | return -EFAULT; | ||
| 5151 | if (copy_to_user(optval, &info, len)) | ||
| 5152 | return -EFAULT; | ||
| 5153 | |||
| 5154 | return 0; | ||
| 5155 | } | ||
| 5156 | |||
| 5005 | /* | 5157 | /* |
| 5006 | * | 5158 | * |
| 5007 | * 7.1.5 SCTP_NODELAY | 5159 | * 7.1.5 SCTP_NODELAY |
| @@ -5752,6 +5904,46 @@ static int sctp_getsockopt_assoc_stats(struct sock *sk, int len, | |||
| 5752 | return 0; | 5904 | return 0; |
| 5753 | } | 5905 | } |
| 5754 | 5906 | ||
| 5907 | static int sctp_getsockopt_recvrcvinfo(struct sock *sk, int len, | ||
| 5908 | char __user *optval, | ||
| 5909 | int __user *optlen) | ||
| 5910 | { | ||
| 5911 | int val = 0; | ||
| 5912 | |||
| 5913 | if (len < sizeof(int)) | ||
| 5914 | return -EINVAL; | ||
| 5915 | |||
| 5916 | len = sizeof(int); | ||
| 5917 | if (sctp_sk(sk)->recvrcvinfo) | ||
| 5918 | val = 1; | ||
| 5919 | if (put_user(len, optlen)) | ||
| 5920 | return -EFAULT; | ||
| 5921 | if (copy_to_user(optval, &val, len)) | ||
| 5922 | return -EFAULT; | ||
| 5923 | |||
| 5924 | return 0; | ||
| 5925 | } | ||
| 5926 | |||
| 5927 | static int sctp_getsockopt_recvnxtinfo(struct sock *sk, int len, | ||
| 5928 | char __user *optval, | ||
| 5929 | int __user *optlen) | ||
| 5930 | { | ||
| 5931 | int val = 0; | ||
| 5932 | |||
| 5933 | if (len < sizeof(int)) | ||
| 5934 | return -EINVAL; | ||
| 5935 | |||
| 5936 | len = sizeof(int); | ||
| 5937 | if (sctp_sk(sk)->recvnxtinfo) | ||
| 5938 | val = 1; | ||
| 5939 | if (put_user(len, optlen)) | ||
| 5940 | return -EFAULT; | ||
| 5941 | if (copy_to_user(optval, &val, len)) | ||
| 5942 | return -EFAULT; | ||
| 5943 | |||
| 5944 | return 0; | ||
| 5945 | } | ||
| 5946 | |||
| 5755 | static int sctp_getsockopt(struct sock *sk, int level, int optname, | 5947 | static int sctp_getsockopt(struct sock *sk, int level, int optname, |
| 5756 | char __user *optval, int __user *optlen) | 5948 | char __user *optval, int __user *optlen) |
| 5757 | { | 5949 | { |
| @@ -5821,6 +6013,10 @@ static int sctp_getsockopt(struct sock *sk, int level, int optname, | |||
| 5821 | retval = sctp_getsockopt_default_send_param(sk, len, | 6013 | retval = sctp_getsockopt_default_send_param(sk, len, |
| 5822 | optval, optlen); | 6014 | optval, optlen); |
| 5823 | break; | 6015 | break; |
| 6016 | case SCTP_DEFAULT_SNDINFO: | ||
| 6017 | retval = sctp_getsockopt_default_sndinfo(sk, len, | ||
| 6018 | optval, optlen); | ||
| 6019 | break; | ||
| 5824 | case SCTP_PRIMARY_ADDR: | 6020 | case SCTP_PRIMARY_ADDR: |
| 5825 | retval = sctp_getsockopt_primary_addr(sk, len, optval, optlen); | 6021 | retval = sctp_getsockopt_primary_addr(sk, len, optval, optlen); |
| 5826 | break; | 6022 | break; |
| @@ -5895,6 +6091,12 @@ static int sctp_getsockopt(struct sock *sk, int level, int optname, | |||
| 5895 | case SCTP_GET_ASSOC_STATS: | 6091 | case SCTP_GET_ASSOC_STATS: |
| 5896 | retval = sctp_getsockopt_assoc_stats(sk, len, optval, optlen); | 6092 | retval = sctp_getsockopt_assoc_stats(sk, len, optval, optlen); |
| 5897 | break; | 6093 | break; |
| 6094 | case SCTP_RECVRCVINFO: | ||
| 6095 | retval = sctp_getsockopt_recvrcvinfo(sk, len, optval, optlen); | ||
| 6096 | break; | ||
| 6097 | case SCTP_RECVNXTINFO: | ||
| 6098 | retval = sctp_getsockopt_recvnxtinfo(sk, len, optval, optlen); | ||
| 6099 | break; | ||
| 5898 | default: | 6100 | default: |
| 5899 | retval = -ENOPROTOOPT; | 6101 | retval = -ENOPROTOOPT; |
| 5900 | break; | 6102 | break; |
| @@ -6390,8 +6592,7 @@ static int sctp_msghdr_parse(const struct msghdr *msg, sctp_cmsgs_t *cmsgs) | |||
| 6390 | struct cmsghdr *cmsg; | 6592 | struct cmsghdr *cmsg; |
| 6391 | struct msghdr *my_msg = (struct msghdr *)msg; | 6593 | struct msghdr *my_msg = (struct msghdr *)msg; |
| 6392 | 6594 | ||
| 6393 | for (cmsg = CMSG_FIRSTHDR(msg); | 6595 | for (cmsg = CMSG_FIRSTHDR(msg); cmsg != NULL; |
| 6394 | cmsg != NULL; | ||
| 6395 | cmsg = CMSG_NXTHDR(my_msg, cmsg)) { | 6596 | cmsg = CMSG_NXTHDR(my_msg, cmsg)) { |
| 6396 | if (!CMSG_OK(my_msg, cmsg)) | 6597 | if (!CMSG_OK(my_msg, cmsg)) |
| 6397 | return -EINVAL; | 6598 | return -EINVAL; |
| @@ -6404,7 +6605,7 @@ static int sctp_msghdr_parse(const struct msghdr *msg, sctp_cmsgs_t *cmsgs) | |||
| 6404 | switch (cmsg->cmsg_type) { | 6605 | switch (cmsg->cmsg_type) { |
| 6405 | case SCTP_INIT: | 6606 | case SCTP_INIT: |
| 6406 | /* SCTP Socket API Extension | 6607 | /* SCTP Socket API Extension |
| 6407 | * 5.2.1 SCTP Initiation Structure (SCTP_INIT) | 6608 | * 5.3.1 SCTP Initiation Structure (SCTP_INIT) |
| 6408 | * | 6609 | * |
| 6409 | * This cmsghdr structure provides information for | 6610 | * This cmsghdr structure provides information for |
| 6410 | * initializing new SCTP associations with sendmsg(). | 6611 | * initializing new SCTP associations with sendmsg(). |
| @@ -6416,15 +6617,15 @@ static int sctp_msghdr_parse(const struct msghdr *msg, sctp_cmsgs_t *cmsgs) | |||
| 6416 | * ------------ ------------ ---------------------- | 6617 | * ------------ ------------ ---------------------- |
| 6417 | * IPPROTO_SCTP SCTP_INIT struct sctp_initmsg | 6618 | * IPPROTO_SCTP SCTP_INIT struct sctp_initmsg |
| 6418 | */ | 6619 | */ |
| 6419 | if (cmsg->cmsg_len != | 6620 | if (cmsg->cmsg_len != CMSG_LEN(sizeof(struct sctp_initmsg))) |
| 6420 | CMSG_LEN(sizeof(struct sctp_initmsg))) | ||
| 6421 | return -EINVAL; | 6621 | return -EINVAL; |
| 6422 | cmsgs->init = (struct sctp_initmsg *)CMSG_DATA(cmsg); | 6622 | |
| 6623 | cmsgs->init = CMSG_DATA(cmsg); | ||
| 6423 | break; | 6624 | break; |
| 6424 | 6625 | ||
| 6425 | case SCTP_SNDRCV: | 6626 | case SCTP_SNDRCV: |
| 6426 | /* SCTP Socket API Extension | 6627 | /* SCTP Socket API Extension |
| 6427 | * 5.2.2 SCTP Header Information Structure(SCTP_SNDRCV) | 6628 | * 5.3.2 SCTP Header Information Structure(SCTP_SNDRCV) |
| 6428 | * | 6629 | * |
| 6429 | * This cmsghdr structure specifies SCTP options for | 6630 | * This cmsghdr structure specifies SCTP options for |
| 6430 | * sendmsg() and describes SCTP header information | 6631 | * sendmsg() and describes SCTP header information |
| @@ -6434,24 +6635,44 @@ static int sctp_msghdr_parse(const struct msghdr *msg, sctp_cmsgs_t *cmsgs) | |||
| 6434 | * ------------ ------------ ---------------------- | 6635 | * ------------ ------------ ---------------------- |
| 6435 | * IPPROTO_SCTP SCTP_SNDRCV struct sctp_sndrcvinfo | 6636 | * IPPROTO_SCTP SCTP_SNDRCV struct sctp_sndrcvinfo |
| 6436 | */ | 6637 | */ |
| 6437 | if (cmsg->cmsg_len != | 6638 | if (cmsg->cmsg_len != CMSG_LEN(sizeof(struct sctp_sndrcvinfo))) |
| 6438 | CMSG_LEN(sizeof(struct sctp_sndrcvinfo))) | ||
| 6439 | return -EINVAL; | 6639 | return -EINVAL; |
| 6440 | 6640 | ||
| 6441 | cmsgs->info = | 6641 | cmsgs->srinfo = CMSG_DATA(cmsg); |
| 6442 | (struct sctp_sndrcvinfo *)CMSG_DATA(cmsg); | ||
| 6443 | 6642 | ||
| 6444 | /* Minimally, validate the sinfo_flags. */ | 6643 | if (cmsgs->srinfo->sinfo_flags & |
| 6445 | if (cmsgs->info->sinfo_flags & | ||
| 6446 | ~(SCTP_UNORDERED | SCTP_ADDR_OVER | | 6644 | ~(SCTP_UNORDERED | SCTP_ADDR_OVER | |
| 6447 | SCTP_ABORT | SCTP_EOF)) | 6645 | SCTP_ABORT | SCTP_EOF)) |
| 6448 | return -EINVAL; | 6646 | return -EINVAL; |
| 6449 | break; | 6647 | break; |
| 6450 | 6648 | ||
| 6649 | case SCTP_SNDINFO: | ||
| 6650 | /* SCTP Socket API Extension | ||
| 6651 | * 5.3.4 SCTP Send Information Structure (SCTP_SNDINFO) | ||
| 6652 | * | ||
| 6653 | * This cmsghdr structure specifies SCTP options for | ||
| 6654 | * sendmsg(). This structure and SCTP_RCVINFO replaces | ||
| 6655 | * SCTP_SNDRCV which has been deprecated. | ||
| 6656 | * | ||
| 6657 | * cmsg_level cmsg_type cmsg_data[] | ||
| 6658 | * ------------ ------------ --------------------- | ||
| 6659 | * IPPROTO_SCTP SCTP_SNDINFO struct sctp_sndinfo | ||
| 6660 | */ | ||
| 6661 | if (cmsg->cmsg_len != CMSG_LEN(sizeof(struct sctp_sndinfo))) | ||
| 6662 | return -EINVAL; | ||
| 6663 | |||
| 6664 | cmsgs->sinfo = CMSG_DATA(cmsg); | ||
| 6665 | |||
| 6666 | if (cmsgs->sinfo->snd_flags & | ||
| 6667 | ~(SCTP_UNORDERED | SCTP_ADDR_OVER | | ||
| 6668 | SCTP_ABORT | SCTP_EOF)) | ||
| 6669 | return -EINVAL; | ||
| 6670 | break; | ||
| 6451 | default: | 6671 | default: |
| 6452 | return -EINVAL; | 6672 | return -EINVAL; |
| 6453 | } | 6673 | } |
| 6454 | } | 6674 | } |
| 6675 | |||
| 6455 | return 0; | 6676 | return 0; |
| 6456 | } | 6677 | } |
| 6457 | 6678 | ||
| @@ -6518,8 +6739,8 @@ out: | |||
| 6518 | * Note: This is pretty much the same routine as in core/datagram.c | 6739 | * Note: This is pretty much the same routine as in core/datagram.c |
| 6519 | * with a few changes to make lksctp work. | 6740 | * with a few changes to make lksctp work. |
| 6520 | */ | 6741 | */ |
| 6521 | static struct sk_buff *sctp_skb_recv_datagram(struct sock *sk, int flags, | 6742 | struct sk_buff *sctp_skb_recv_datagram(struct sock *sk, int flags, |
| 6522 | int noblock, int *err) | 6743 | int noblock, int *err) |
| 6523 | { | 6744 | { |
| 6524 | int error; | 6745 | int error; |
| 6525 | struct sk_buff *skb; | 6746 | struct sk_buff *skb; |
diff --git a/net/sctp/sysctl.c b/net/sctp/sysctl.c index 12c7e01c2677..2e9ada10fd84 100644 --- a/net/sctp/sysctl.c +++ b/net/sctp/sysctl.c | |||
| @@ -424,8 +424,9 @@ static int proc_sctp_do_alpha_beta(struct ctl_table *ctl, int write, | |||
| 424 | void __user *buffer, size_t *lenp, | 424 | void __user *buffer, size_t *lenp, |
| 425 | loff_t *ppos) | 425 | loff_t *ppos) |
| 426 | { | 426 | { |
| 427 | pr_warn_once("Changing rto_alpha or rto_beta may lead to " | 427 | if (write) |
| 428 | "suboptimal rtt/srtt estimations!\n"); | 428 | pr_warn_once("Changing rto_alpha or rto_beta may lead to " |
| 429 | "suboptimal rtt/srtt estimations!\n"); | ||
| 429 | 430 | ||
| 430 | return proc_dointvec_minmax(ctl, write, buffer, lenp, ppos); | 431 | return proc_dointvec_minmax(ctl, write, buffer, lenp, ppos); |
| 431 | } | 432 | } |
diff --git a/net/sctp/transport.c b/net/sctp/transport.c index 7dd672fa651f..a0a431824f63 100644 --- a/net/sctp/transport.c +++ b/net/sctp/transport.c | |||
| @@ -289,8 +289,8 @@ void sctp_transport_route(struct sctp_transport *transport, | |||
| 289 | */ | 289 | */ |
| 290 | if (asoc && (!asoc->peer.primary_path || | 290 | if (asoc && (!asoc->peer.primary_path || |
| 291 | (transport == asoc->peer.active_path))) | 291 | (transport == asoc->peer.active_path))) |
| 292 | opt->pf->af->to_sk_saddr(&transport->saddr, | 292 | opt->pf->to_sk_saddr(&transport->saddr, |
| 293 | asoc->base.sk); | 293 | asoc->base.sk); |
| 294 | } else | 294 | } else |
| 295 | transport->pathmtu = SCTP_DEFAULT_MAXSEGMENT; | 295 | transport->pathmtu = SCTP_DEFAULT_MAXSEGMENT; |
| 296 | } | 296 | } |
| @@ -594,15 +594,16 @@ void sctp_transport_burst_reset(struct sctp_transport *t) | |||
| 594 | } | 594 | } |
| 595 | 595 | ||
| 596 | /* What is the next timeout value for this transport? */ | 596 | /* What is the next timeout value for this transport? */ |
| 597 | unsigned long sctp_transport_timeout(struct sctp_transport *t) | 597 | unsigned long sctp_transport_timeout(struct sctp_transport *trans) |
| 598 | { | 598 | { |
| 599 | unsigned long timeout; | 599 | /* RTO + timer slack +/- 50% of RTO */ |
| 600 | timeout = t->rto + sctp_jitter(t->rto); | 600 | unsigned long timeout = (trans->rto >> 1) + prandom_u32_max(trans->rto); |
| 601 | if ((t->state != SCTP_UNCONFIRMED) && | 601 | |
| 602 | (t->state != SCTP_PF)) | 602 | if (trans->state != SCTP_UNCONFIRMED && |
| 603 | timeout += t->hbinterval; | 603 | trans->state != SCTP_PF) |
| 604 | timeout += jiffies; | 604 | timeout += trans->hbinterval; |
| 605 | return timeout; | 605 | |
| 606 | return timeout + jiffies; | ||
| 606 | } | 607 | } |
| 607 | 608 | ||
| 608 | /* Reset transport variables to their initial values */ | 609 | /* Reset transport variables to their initial values */ |
diff --git a/net/sctp/ulpevent.c b/net/sctp/ulpevent.c index b6842fdb53d4..d1e38308f615 100644 --- a/net/sctp/ulpevent.c +++ b/net/sctp/ulpevent.c | |||
| @@ -341,7 +341,7 @@ struct sctp_ulpevent *sctp_ulpevent_make_peer_addr_change( | |||
| 341 | memcpy(&spc->spc_aaddr, aaddr, sizeof(struct sockaddr_storage)); | 341 | memcpy(&spc->spc_aaddr, aaddr, sizeof(struct sockaddr_storage)); |
| 342 | 342 | ||
| 343 | /* Map ipv4 address into v4-mapped-on-v6 address. */ | 343 | /* Map ipv4 address into v4-mapped-on-v6 address. */ |
| 344 | sctp_get_pf_specific(asoc->base.sk->sk_family)->addr_v4map( | 344 | sctp_get_pf_specific(asoc->base.sk->sk_family)->addr_to_user( |
| 345 | sctp_sk(asoc->base.sk), | 345 | sctp_sk(asoc->base.sk), |
| 346 | (union sctp_addr *)&spc->spc_aaddr); | 346 | (union sctp_addr *)&spc->spc_aaddr); |
| 347 | 347 | ||
| @@ -886,6 +886,69 @@ void sctp_ulpevent_read_sndrcvinfo(const struct sctp_ulpevent *event, | |||
| 886 | sizeof(sinfo), &sinfo); | 886 | sizeof(sinfo), &sinfo); |
| 887 | } | 887 | } |
| 888 | 888 | ||
| 889 | /* RFC6458, Section 5.3.5 SCTP Receive Information Structure | ||
| 890 | * (SCTP_SNDRCV) | ||
| 891 | */ | ||
| 892 | void sctp_ulpevent_read_rcvinfo(const struct sctp_ulpevent *event, | ||
| 893 | struct msghdr *msghdr) | ||
| 894 | { | ||
| 895 | struct sctp_rcvinfo rinfo; | ||
| 896 | |||
| 897 | if (sctp_ulpevent_is_notification(event)) | ||
| 898 | return; | ||
| 899 | |||
| 900 | memset(&rinfo, 0, sizeof(struct sctp_rcvinfo)); | ||
| 901 | rinfo.rcv_sid = event->stream; | ||
| 902 | rinfo.rcv_ssn = event->ssn; | ||
| 903 | rinfo.rcv_ppid = event->ppid; | ||
| 904 | rinfo.rcv_flags = event->flags; | ||
| 905 | rinfo.rcv_tsn = event->tsn; | ||
| 906 | rinfo.rcv_cumtsn = event->cumtsn; | ||
| 907 | rinfo.rcv_assoc_id = sctp_assoc2id(event->asoc); | ||
| 908 | rinfo.rcv_context = event->asoc->default_rcv_context; | ||
| 909 | |||
| 910 | put_cmsg(msghdr, IPPROTO_SCTP, SCTP_RCVINFO, | ||
| 911 | sizeof(rinfo), &rinfo); | ||
| 912 | } | ||
| 913 | |||
| 914 | /* RFC6458, Section 5.3.6. SCTP Next Receive Information Structure | ||
| 915 | * (SCTP_NXTINFO) | ||
| 916 | */ | ||
| 917 | static void __sctp_ulpevent_read_nxtinfo(const struct sctp_ulpevent *event, | ||
| 918 | struct msghdr *msghdr, | ||
| 919 | const struct sk_buff *skb) | ||
| 920 | { | ||
| 921 | struct sctp_nxtinfo nxtinfo; | ||
| 922 | |||
| 923 | memset(&nxtinfo, 0, sizeof(nxtinfo)); | ||
| 924 | nxtinfo.nxt_sid = event->stream; | ||
| 925 | nxtinfo.nxt_ppid = event->ppid; | ||
| 926 | nxtinfo.nxt_flags = event->flags; | ||
| 927 | if (sctp_ulpevent_is_notification(event)) | ||
| 928 | nxtinfo.nxt_flags |= SCTP_NOTIFICATION; | ||
| 929 | nxtinfo.nxt_length = skb->len; | ||
| 930 | nxtinfo.nxt_assoc_id = sctp_assoc2id(event->asoc); | ||
| 931 | |||
| 932 | put_cmsg(msghdr, IPPROTO_SCTP, SCTP_NXTINFO, | ||
| 933 | sizeof(nxtinfo), &nxtinfo); | ||
| 934 | } | ||
| 935 | |||
| 936 | void sctp_ulpevent_read_nxtinfo(const struct sctp_ulpevent *event, | ||
| 937 | struct msghdr *msghdr, | ||
| 938 | struct sock *sk) | ||
| 939 | { | ||
| 940 | struct sk_buff *skb; | ||
| 941 | int err; | ||
| 942 | |||
| 943 | skb = sctp_skb_recv_datagram(sk, MSG_PEEK, 1, &err); | ||
| 944 | if (skb != NULL) { | ||
| 945 | __sctp_ulpevent_read_nxtinfo(sctp_skb2event(skb), | ||
| 946 | msghdr, skb); | ||
| 947 | /* Just release refcount here. */ | ||
| 948 | kfree_skb(skb); | ||
| 949 | } | ||
| 950 | } | ||
| 951 | |||
| 889 | /* Do accounting for bytes received and hold a reference to the association | 952 | /* Do accounting for bytes received and hold a reference to the association |
| 890 | * for each skb. | 953 | * for each skb. |
| 891 | */ | 954 | */ |
diff --git a/net/socket.c b/net/socket.c index abf56b2a14f9..95ee7d8682e7 100644 --- a/net/socket.c +++ b/net/socket.c | |||
| @@ -106,6 +106,7 @@ | |||
| 106 | #include <linux/sockios.h> | 106 | #include <linux/sockios.h> |
| 107 | #include <linux/atalk.h> | 107 | #include <linux/atalk.h> |
| 108 | #include <net/busy_poll.h> | 108 | #include <net/busy_poll.h> |
| 109 | #include <linux/errqueue.h> | ||
| 109 | 110 | ||
| 110 | #ifdef CONFIG_NET_RX_BUSY_POLL | 111 | #ifdef CONFIG_NET_RX_BUSY_POLL |
| 111 | unsigned int sysctl_net_busy_read __read_mostly; | 112 | unsigned int sysctl_net_busy_read __read_mostly; |
| @@ -609,15 +610,26 @@ void sock_release(struct socket *sock) | |||
| 609 | } | 610 | } |
| 610 | EXPORT_SYMBOL(sock_release); | 611 | EXPORT_SYMBOL(sock_release); |
| 611 | 612 | ||
| 612 | void sock_tx_timestamp(struct sock *sk, __u8 *tx_flags) | 613 | void sock_tx_timestamp(const struct sock *sk, __u8 *tx_flags) |
| 613 | { | 614 | { |
| 614 | *tx_flags = 0; | 615 | u8 flags = *tx_flags; |
| 615 | if (sock_flag(sk, SOCK_TIMESTAMPING_TX_HARDWARE)) | 616 | |
| 616 | *tx_flags |= SKBTX_HW_TSTAMP; | 617 | if (sk->sk_tsflags & SOF_TIMESTAMPING_TX_HARDWARE) |
| 617 | if (sock_flag(sk, SOCK_TIMESTAMPING_TX_SOFTWARE)) | 618 | flags |= SKBTX_HW_TSTAMP; |
| 618 | *tx_flags |= SKBTX_SW_TSTAMP; | 619 | |
| 620 | if (sk->sk_tsflags & SOF_TIMESTAMPING_TX_SOFTWARE) | ||
| 621 | flags |= SKBTX_SW_TSTAMP; | ||
| 622 | |||
| 623 | if (sk->sk_tsflags & SOF_TIMESTAMPING_TX_SCHED) | ||
| 624 | flags |= SKBTX_SCHED_TSTAMP; | ||
| 625 | |||
| 626 | if (sk->sk_tsflags & SOF_TIMESTAMPING_TX_ACK) | ||
| 627 | flags |= SKBTX_ACK_TSTAMP; | ||
| 628 | |||
| 619 | if (sock_flag(sk, SOCK_WIFI_STATUS)) | 629 | if (sock_flag(sk, SOCK_WIFI_STATUS)) |
| 620 | *tx_flags |= SKBTX_WIFI_STATUS; | 630 | flags |= SKBTX_WIFI_STATUS; |
| 631 | |||
| 632 | *tx_flags = flags; | ||
| 621 | } | 633 | } |
| 622 | EXPORT_SYMBOL(sock_tx_timestamp); | 634 | EXPORT_SYMBOL(sock_tx_timestamp); |
| 623 | 635 | ||
| @@ -697,7 +709,7 @@ void __sock_recv_timestamp(struct msghdr *msg, struct sock *sk, | |||
| 697 | struct sk_buff *skb) | 709 | struct sk_buff *skb) |
| 698 | { | 710 | { |
| 699 | int need_software_tstamp = sock_flag(sk, SOCK_RCVTSTAMP); | 711 | int need_software_tstamp = sock_flag(sk, SOCK_RCVTSTAMP); |
| 700 | struct timespec ts[3]; | 712 | struct scm_timestamping tss; |
| 701 | int empty = 1; | 713 | int empty = 1; |
| 702 | struct skb_shared_hwtstamps *shhwtstamps = | 714 | struct skb_shared_hwtstamps *shhwtstamps = |
| 703 | skb_hwtstamps(skb); | 715 | skb_hwtstamps(skb); |
| @@ -714,28 +726,25 @@ void __sock_recv_timestamp(struct msghdr *msg, struct sock *sk, | |||
| 714 | put_cmsg(msg, SOL_SOCKET, SCM_TIMESTAMP, | 726 | put_cmsg(msg, SOL_SOCKET, SCM_TIMESTAMP, |
| 715 | sizeof(tv), &tv); | 727 | sizeof(tv), &tv); |
| 716 | } else { | 728 | } else { |
| 717 | skb_get_timestampns(skb, &ts[0]); | 729 | struct timespec ts; |
| 730 | skb_get_timestampns(skb, &ts); | ||
| 718 | put_cmsg(msg, SOL_SOCKET, SCM_TIMESTAMPNS, | 731 | put_cmsg(msg, SOL_SOCKET, SCM_TIMESTAMPNS, |
| 719 | sizeof(ts[0]), &ts[0]); | 732 | sizeof(ts), &ts); |
| 720 | } | 733 | } |
| 721 | } | 734 | } |
| 722 | 735 | ||
| 723 | 736 | memset(&tss, 0, sizeof(tss)); | |
| 724 | memset(ts, 0, sizeof(ts)); | 737 | if ((sk->sk_tsflags & SOF_TIMESTAMPING_SOFTWARE || |
| 725 | if (sock_flag(sk, SOCK_TIMESTAMPING_SOFTWARE) && | 738 | skb_shinfo(skb)->tx_flags & SKBTX_ANY_SW_TSTAMP) && |
| 726 | ktime_to_timespec_cond(skb->tstamp, ts + 0)) | 739 | ktime_to_timespec_cond(skb->tstamp, tss.ts + 0)) |
| 740 | empty = 0; | ||
| 741 | if (shhwtstamps && | ||
| 742 | (sk->sk_tsflags & SOF_TIMESTAMPING_RAW_HARDWARE) && | ||
| 743 | ktime_to_timespec_cond(shhwtstamps->hwtstamp, tss.ts + 2)) | ||
| 727 | empty = 0; | 744 | empty = 0; |
| 728 | if (shhwtstamps) { | ||
| 729 | if (sock_flag(sk, SOCK_TIMESTAMPING_SYS_HARDWARE) && | ||
| 730 | ktime_to_timespec_cond(shhwtstamps->syststamp, ts + 1)) | ||
| 731 | empty = 0; | ||
| 732 | if (sock_flag(sk, SOCK_TIMESTAMPING_RAW_HARDWARE) && | ||
| 733 | ktime_to_timespec_cond(shhwtstamps->hwtstamp, ts + 2)) | ||
| 734 | empty = 0; | ||
| 735 | } | ||
| 736 | if (!empty) | 745 | if (!empty) |
| 737 | put_cmsg(msg, SOL_SOCKET, | 746 | put_cmsg(msg, SOL_SOCKET, |
| 738 | SCM_TIMESTAMPING, sizeof(ts), &ts); | 747 | SCM_TIMESTAMPING, sizeof(tss), &tss); |
| 739 | } | 748 | } |
| 740 | EXPORT_SYMBOL_GPL(__sock_recv_timestamp); | 749 | EXPORT_SYMBOL_GPL(__sock_recv_timestamp); |
| 741 | 750 | ||
diff --git a/net/sunrpc/addr.c b/net/sunrpc/addr.c index a622ad64acd8..2e0a6f92e563 100644 --- a/net/sunrpc/addr.c +++ b/net/sunrpc/addr.c | |||
| @@ -176,7 +176,7 @@ static int rpc_parse_scope_id(struct net *net, const char *buf, | |||
| 176 | len = (buf + buflen) - delim - 1; | 176 | len = (buf + buflen) - delim - 1; |
| 177 | p = kstrndup(delim + 1, len, GFP_KERNEL); | 177 | p = kstrndup(delim + 1, len, GFP_KERNEL); |
| 178 | if (p) { | 178 | if (p) { |
| 179 | unsigned long scope_id = 0; | 179 | u32 scope_id = 0; |
| 180 | struct net_device *dev; | 180 | struct net_device *dev; |
| 181 | 181 | ||
| 182 | dev = dev_get_by_name(net, p); | 182 | dev = dev_get_by_name(net, p); |
| @@ -184,7 +184,7 @@ static int rpc_parse_scope_id(struct net *net, const char *buf, | |||
| 184 | scope_id = dev->ifindex; | 184 | scope_id = dev->ifindex; |
| 185 | dev_put(dev); | 185 | dev_put(dev); |
| 186 | } else { | 186 | } else { |
| 187 | if (strict_strtoul(p, 10, &scope_id) == 0) { | 187 | if (kstrtou32(p, 10, &scope_id) == 0) { |
| 188 | kfree(p); | 188 | kfree(p); |
| 189 | return 0; | 189 | return 0; |
| 190 | } | 190 | } |
| @@ -304,7 +304,7 @@ char *rpc_sockaddr2uaddr(const struct sockaddr *sap, gfp_t gfp_flags) | |||
| 304 | * @sap: buffer into which to plant socket address | 304 | * @sap: buffer into which to plant socket address |
| 305 | * @salen: size of buffer | 305 | * @salen: size of buffer |
| 306 | * | 306 | * |
| 307 | * @uaddr does not have to be '\0'-terminated, but strict_strtoul() and | 307 | * @uaddr does not have to be '\0'-terminated, but kstrtou8() and |
| 308 | * rpc_pton() require proper string termination to be successful. | 308 | * rpc_pton() require proper string termination to be successful. |
| 309 | * | 309 | * |
| 310 | * Returns the size of the socket address if successful; otherwise | 310 | * Returns the size of the socket address if successful; otherwise |
| @@ -315,7 +315,7 @@ size_t rpc_uaddr2sockaddr(struct net *net, const char *uaddr, | |||
| 315 | const size_t salen) | 315 | const size_t salen) |
| 316 | { | 316 | { |
| 317 | char *c, buf[RPCBIND_MAXUADDRLEN + sizeof('\0')]; | 317 | char *c, buf[RPCBIND_MAXUADDRLEN + sizeof('\0')]; |
| 318 | unsigned long portlo, porthi; | 318 | u8 portlo, porthi; |
| 319 | unsigned short port; | 319 | unsigned short port; |
| 320 | 320 | ||
| 321 | if (uaddr_len > RPCBIND_MAXUADDRLEN) | 321 | if (uaddr_len > RPCBIND_MAXUADDRLEN) |
| @@ -327,18 +327,14 @@ size_t rpc_uaddr2sockaddr(struct net *net, const char *uaddr, | |||
| 327 | c = strrchr(buf, '.'); | 327 | c = strrchr(buf, '.'); |
| 328 | if (unlikely(c == NULL)) | 328 | if (unlikely(c == NULL)) |
| 329 | return 0; | 329 | return 0; |
| 330 | if (unlikely(strict_strtoul(c + 1, 10, &portlo) != 0)) | 330 | if (unlikely(kstrtou8(c + 1, 10, &portlo) != 0)) |
| 331 | return 0; | ||
| 332 | if (unlikely(portlo > 255)) | ||
| 333 | return 0; | 331 | return 0; |
| 334 | 332 | ||
| 335 | *c = '\0'; | 333 | *c = '\0'; |
| 336 | c = strrchr(buf, '.'); | 334 | c = strrchr(buf, '.'); |
| 337 | if (unlikely(c == NULL)) | 335 | if (unlikely(c == NULL)) |
| 338 | return 0; | 336 | return 0; |
| 339 | if (unlikely(strict_strtoul(c + 1, 10, &porthi) != 0)) | 337 | if (unlikely(kstrtou8(c + 1, 10, &porthi) != 0)) |
| 340 | return 0; | ||
| 341 | if (unlikely(porthi > 255)) | ||
| 342 | return 0; | 338 | return 0; |
| 343 | 339 | ||
| 344 | port = (unsigned short)((porthi << 8) | portlo); | 340 | port = (unsigned short)((porthi << 8) | portlo); |
diff --git a/net/sunrpc/auth.c b/net/sunrpc/auth.c index f77366717420..383eb919ac0b 100644 --- a/net/sunrpc/auth.c +++ b/net/sunrpc/auth.c | |||
| @@ -48,7 +48,7 @@ static int param_set_hashtbl_sz(const char *val, const struct kernel_param *kp) | |||
| 48 | 48 | ||
| 49 | if (!val) | 49 | if (!val) |
| 50 | goto out_inval; | 50 | goto out_inval; |
| 51 | ret = strict_strtoul(val, 0, &num); | 51 | ret = kstrtoul(val, 0, &num); |
| 52 | if (ret == -EINVAL) | 52 | if (ret == -EINVAL) |
| 53 | goto out_inval; | 53 | goto out_inval; |
| 54 | nbits = fls(num); | 54 | nbits = fls(num); |
| @@ -80,6 +80,10 @@ static struct kernel_param_ops param_ops_hashtbl_sz = { | |||
| 80 | module_param_named(auth_hashtable_size, auth_hashbits, hashtbl_sz, 0644); | 80 | module_param_named(auth_hashtable_size, auth_hashbits, hashtbl_sz, 0644); |
| 81 | MODULE_PARM_DESC(auth_hashtable_size, "RPC credential cache hashtable size"); | 81 | MODULE_PARM_DESC(auth_hashtable_size, "RPC credential cache hashtable size"); |
| 82 | 82 | ||
| 83 | static unsigned long auth_max_cred_cachesize = ULONG_MAX; | ||
| 84 | module_param(auth_max_cred_cachesize, ulong, 0644); | ||
| 85 | MODULE_PARM_DESC(auth_max_cred_cachesize, "RPC credential maximum total cache size"); | ||
| 86 | |||
| 83 | static u32 | 87 | static u32 |
| 84 | pseudoflavor_to_flavor(u32 flavor) { | 88 | pseudoflavor_to_flavor(u32 flavor) { |
| 85 | if (flavor > RPC_AUTH_MAXFLAVOR) | 89 | if (flavor > RPC_AUTH_MAXFLAVOR) |
| @@ -363,6 +367,15 @@ rpcauth_cred_key_to_expire(struct rpc_cred *cred) | |||
| 363 | } | 367 | } |
| 364 | EXPORT_SYMBOL_GPL(rpcauth_cred_key_to_expire); | 368 | EXPORT_SYMBOL_GPL(rpcauth_cred_key_to_expire); |
| 365 | 369 | ||
| 370 | char * | ||
| 371 | rpcauth_stringify_acceptor(struct rpc_cred *cred) | ||
| 372 | { | ||
| 373 | if (!cred->cr_ops->crstringify_acceptor) | ||
| 374 | return NULL; | ||
| 375 | return cred->cr_ops->crstringify_acceptor(cred); | ||
| 376 | } | ||
| 377 | EXPORT_SYMBOL_GPL(rpcauth_stringify_acceptor); | ||
| 378 | |||
| 366 | /* | 379 | /* |
| 367 | * Destroy a list of credentials | 380 | * Destroy a list of credentials |
| 368 | */ | 381 | */ |
| @@ -472,6 +485,20 @@ rpcauth_prune_expired(struct list_head *free, int nr_to_scan) | |||
| 472 | return freed; | 485 | return freed; |
| 473 | } | 486 | } |
| 474 | 487 | ||
| 488 | static unsigned long | ||
| 489 | rpcauth_cache_do_shrink(int nr_to_scan) | ||
| 490 | { | ||
| 491 | LIST_HEAD(free); | ||
| 492 | unsigned long freed; | ||
| 493 | |||
| 494 | spin_lock(&rpc_credcache_lock); | ||
| 495 | freed = rpcauth_prune_expired(&free, nr_to_scan); | ||
| 496 | spin_unlock(&rpc_credcache_lock); | ||
| 497 | rpcauth_destroy_credlist(&free); | ||
| 498 | |||
| 499 | return freed; | ||
| 500 | } | ||
| 501 | |||
| 475 | /* | 502 | /* |
| 476 | * Run memory cache shrinker. | 503 | * Run memory cache shrinker. |
| 477 | */ | 504 | */ |
| @@ -479,9 +506,6 @@ static unsigned long | |||
| 479 | rpcauth_cache_shrink_scan(struct shrinker *shrink, struct shrink_control *sc) | 506 | rpcauth_cache_shrink_scan(struct shrinker *shrink, struct shrink_control *sc) |
| 480 | 507 | ||
| 481 | { | 508 | { |
| 482 | LIST_HEAD(free); | ||
| 483 | unsigned long freed; | ||
| 484 | |||
| 485 | if ((sc->gfp_mask & GFP_KERNEL) != GFP_KERNEL) | 509 | if ((sc->gfp_mask & GFP_KERNEL) != GFP_KERNEL) |
| 486 | return SHRINK_STOP; | 510 | return SHRINK_STOP; |
| 487 | 511 | ||
| @@ -489,12 +513,7 @@ rpcauth_cache_shrink_scan(struct shrinker *shrink, struct shrink_control *sc) | |||
| 489 | if (list_empty(&cred_unused)) | 513 | if (list_empty(&cred_unused)) |
| 490 | return SHRINK_STOP; | 514 | return SHRINK_STOP; |
| 491 | 515 | ||
| 492 | spin_lock(&rpc_credcache_lock); | 516 | return rpcauth_cache_do_shrink(sc->nr_to_scan); |
| 493 | freed = rpcauth_prune_expired(&free, sc->nr_to_scan); | ||
| 494 | spin_unlock(&rpc_credcache_lock); | ||
| 495 | rpcauth_destroy_credlist(&free); | ||
| 496 | |||
| 497 | return freed; | ||
| 498 | } | 517 | } |
| 499 | 518 | ||
| 500 | static unsigned long | 519 | static unsigned long |
| @@ -504,6 +523,21 @@ rpcauth_cache_shrink_count(struct shrinker *shrink, struct shrink_control *sc) | |||
| 504 | return (number_cred_unused / 100) * sysctl_vfs_cache_pressure; | 523 | return (number_cred_unused / 100) * sysctl_vfs_cache_pressure; |
| 505 | } | 524 | } |
| 506 | 525 | ||
| 526 | static void | ||
| 527 | rpcauth_cache_enforce_limit(void) | ||
| 528 | { | ||
| 529 | unsigned long diff; | ||
| 530 | unsigned int nr_to_scan; | ||
| 531 | |||
| 532 | if (number_cred_unused <= auth_max_cred_cachesize) | ||
| 533 | return; | ||
| 534 | diff = number_cred_unused - auth_max_cred_cachesize; | ||
| 535 | nr_to_scan = 100; | ||
| 536 | if (diff < nr_to_scan) | ||
| 537 | nr_to_scan = diff; | ||
| 538 | rpcauth_cache_do_shrink(nr_to_scan); | ||
| 539 | } | ||
| 540 | |||
| 507 | /* | 541 | /* |
| 508 | * Look up a process' credentials in the authentication cache | 542 | * Look up a process' credentials in the authentication cache |
| 509 | */ | 543 | */ |
| @@ -523,6 +557,12 @@ rpcauth_lookup_credcache(struct rpc_auth *auth, struct auth_cred * acred, | |||
| 523 | hlist_for_each_entry_rcu(entry, &cache->hashtable[nr], cr_hash) { | 557 | hlist_for_each_entry_rcu(entry, &cache->hashtable[nr], cr_hash) { |
| 524 | if (!entry->cr_ops->crmatch(acred, entry, flags)) | 558 | if (!entry->cr_ops->crmatch(acred, entry, flags)) |
| 525 | continue; | 559 | continue; |
| 560 | if (flags & RPCAUTH_LOOKUP_RCU) { | ||
| 561 | if (test_bit(RPCAUTH_CRED_HASHED, &entry->cr_flags) && | ||
| 562 | !test_bit(RPCAUTH_CRED_NEW, &entry->cr_flags)) | ||
| 563 | cred = entry; | ||
| 564 | break; | ||
| 565 | } | ||
| 526 | spin_lock(&cache->lock); | 566 | spin_lock(&cache->lock); |
| 527 | if (test_bit(RPCAUTH_CRED_HASHED, &entry->cr_flags) == 0) { | 567 | if (test_bit(RPCAUTH_CRED_HASHED, &entry->cr_flags) == 0) { |
| 528 | spin_unlock(&cache->lock); | 568 | spin_unlock(&cache->lock); |
| @@ -537,6 +577,9 @@ rpcauth_lookup_credcache(struct rpc_auth *auth, struct auth_cred * acred, | |||
| 537 | if (cred != NULL) | 577 | if (cred != NULL) |
| 538 | goto found; | 578 | goto found; |
| 539 | 579 | ||
| 580 | if (flags & RPCAUTH_LOOKUP_RCU) | ||
| 581 | return ERR_PTR(-ECHILD); | ||
| 582 | |||
| 540 | new = auth->au_ops->crcreate(auth, acred, flags); | 583 | new = auth->au_ops->crcreate(auth, acred, flags); |
| 541 | if (IS_ERR(new)) { | 584 | if (IS_ERR(new)) { |
| 542 | cred = new; | 585 | cred = new; |
| @@ -557,6 +600,7 @@ rpcauth_lookup_credcache(struct rpc_auth *auth, struct auth_cred * acred, | |||
| 557 | } else | 600 | } else |
| 558 | list_add_tail(&new->cr_lru, &free); | 601 | list_add_tail(&new->cr_lru, &free); |
| 559 | spin_unlock(&cache->lock); | 602 | spin_unlock(&cache->lock); |
| 603 | rpcauth_cache_enforce_limit(); | ||
| 560 | found: | 604 | found: |
| 561 | if (test_bit(RPCAUTH_CRED_NEW, &cred->cr_flags) && | 605 | if (test_bit(RPCAUTH_CRED_NEW, &cred->cr_flags) && |
| 562 | cred->cr_ops->cr_init != NULL && | 606 | cred->cr_ops->cr_init != NULL && |
| @@ -586,10 +630,8 @@ rpcauth_lookupcred(struct rpc_auth *auth, int flags) | |||
| 586 | memset(&acred, 0, sizeof(acred)); | 630 | memset(&acred, 0, sizeof(acred)); |
| 587 | acred.uid = cred->fsuid; | 631 | acred.uid = cred->fsuid; |
| 588 | acred.gid = cred->fsgid; | 632 | acred.gid = cred->fsgid; |
| 589 | acred.group_info = get_group_info(((struct cred *)cred)->group_info); | 633 | acred.group_info = cred->group_info; |
| 590 | |||
| 591 | ret = auth->au_ops->lookup_cred(auth, &acred, flags); | 634 | ret = auth->au_ops->lookup_cred(auth, &acred, flags); |
| 592 | put_group_info(acred.group_info); | ||
| 593 | return ret; | 635 | return ret; |
| 594 | } | 636 | } |
| 595 | EXPORT_SYMBOL_GPL(rpcauth_lookupcred); | 637 | EXPORT_SYMBOL_GPL(rpcauth_lookupcred); |
diff --git a/net/sunrpc/auth_generic.c b/net/sunrpc/auth_generic.c index ed04869b2d4f..6f6b829c9e8e 100644 --- a/net/sunrpc/auth_generic.c +++ b/net/sunrpc/auth_generic.c | |||
| @@ -38,6 +38,12 @@ struct rpc_cred *rpc_lookup_cred(void) | |||
| 38 | } | 38 | } |
| 39 | EXPORT_SYMBOL_GPL(rpc_lookup_cred); | 39 | EXPORT_SYMBOL_GPL(rpc_lookup_cred); |
| 40 | 40 | ||
| 41 | struct rpc_cred *rpc_lookup_cred_nonblock(void) | ||
| 42 | { | ||
| 43 | return rpcauth_lookupcred(&generic_auth, RPCAUTH_LOOKUP_RCU); | ||
| 44 | } | ||
| 45 | EXPORT_SYMBOL_GPL(rpc_lookup_cred_nonblock); | ||
| 46 | |||
| 41 | /* | 47 | /* |
| 42 | * Public call interface for looking up machine creds. | 48 | * Public call interface for looking up machine creds. |
| 43 | */ | 49 | */ |
diff --git a/net/sunrpc/auth_gss/auth_gss.c b/net/sunrpc/auth_gss/auth_gss.c index b6e440baccc3..afb292cd797d 100644 --- a/net/sunrpc/auth_gss/auth_gss.c +++ b/net/sunrpc/auth_gss/auth_gss.c | |||
| @@ -183,8 +183,9 @@ gss_cred_get_ctx(struct rpc_cred *cred) | |||
| 183 | struct gss_cl_ctx *ctx = NULL; | 183 | struct gss_cl_ctx *ctx = NULL; |
| 184 | 184 | ||
| 185 | rcu_read_lock(); | 185 | rcu_read_lock(); |
| 186 | if (gss_cred->gc_ctx) | 186 | ctx = rcu_dereference(gss_cred->gc_ctx); |
| 187 | ctx = gss_get_ctx(gss_cred->gc_ctx); | 187 | if (ctx) |
| 188 | gss_get_ctx(ctx); | ||
| 188 | rcu_read_unlock(); | 189 | rcu_read_unlock(); |
| 189 | return ctx; | 190 | return ctx; |
| 190 | } | 191 | } |
| @@ -262,9 +263,22 @@ gss_fill_context(const void *p, const void *end, struct gss_cl_ctx *ctx, struct | |||
| 262 | p = ERR_PTR(ret); | 263 | p = ERR_PTR(ret); |
| 263 | goto err; | 264 | goto err; |
| 264 | } | 265 | } |
| 265 | dprintk("RPC: %s Success. gc_expiry %lu now %lu timeout %u\n", | 266 | |
| 266 | __func__, ctx->gc_expiry, now, timeout); | 267 | /* is there any trailing data? */ |
| 267 | return q; | 268 | if (q == end) { |
| 269 | p = q; | ||
| 270 | goto done; | ||
| 271 | } | ||
| 272 | |||
| 273 | /* pull in acceptor name (if there is one) */ | ||
| 274 | p = simple_get_netobj(q, end, &ctx->gc_acceptor); | ||
| 275 | if (IS_ERR(p)) | ||
| 276 | goto err; | ||
| 277 | done: | ||
| 278 | dprintk("RPC: %s Success. gc_expiry %lu now %lu timeout %u acceptor %.*s\n", | ||
| 279 | __func__, ctx->gc_expiry, now, timeout, ctx->gc_acceptor.len, | ||
| 280 | ctx->gc_acceptor.data); | ||
| 281 | return p; | ||
| 268 | err: | 282 | err: |
| 269 | dprintk("RPC: %s returns error %ld\n", __func__, -PTR_ERR(p)); | 283 | dprintk("RPC: %s returns error %ld\n", __func__, -PTR_ERR(p)); |
| 270 | return p; | 284 | return p; |
| @@ -1194,13 +1208,13 @@ gss_destroying_context(struct rpc_cred *cred) | |||
| 1194 | { | 1208 | { |
| 1195 | struct gss_cred *gss_cred = container_of(cred, struct gss_cred, gc_base); | 1209 | struct gss_cred *gss_cred = container_of(cred, struct gss_cred, gc_base); |
| 1196 | struct gss_auth *gss_auth = container_of(cred->cr_auth, struct gss_auth, rpc_auth); | 1210 | struct gss_auth *gss_auth = container_of(cred->cr_auth, struct gss_auth, rpc_auth); |
| 1211 | struct gss_cl_ctx *ctx = rcu_dereference_protected(gss_cred->gc_ctx, 1); | ||
| 1197 | struct rpc_task *task; | 1212 | struct rpc_task *task; |
| 1198 | 1213 | ||
| 1199 | if (gss_cred->gc_ctx == NULL || | 1214 | if (test_bit(RPCAUTH_CRED_UPTODATE, &cred->cr_flags) == 0) |
| 1200 | test_bit(RPCAUTH_CRED_UPTODATE, &cred->cr_flags) == 0) | ||
| 1201 | return 0; | 1215 | return 0; |
| 1202 | 1216 | ||
| 1203 | gss_cred->gc_ctx->gc_proc = RPC_GSS_PROC_DESTROY; | 1217 | ctx->gc_proc = RPC_GSS_PROC_DESTROY; |
| 1204 | cred->cr_ops = &gss_nullops; | 1218 | cred->cr_ops = &gss_nullops; |
| 1205 | 1219 | ||
| 1206 | /* Take a reference to ensure the cred will be destroyed either | 1220 | /* Take a reference to ensure the cred will be destroyed either |
| @@ -1225,6 +1239,7 @@ gss_do_free_ctx(struct gss_cl_ctx *ctx) | |||
| 1225 | 1239 | ||
| 1226 | gss_delete_sec_context(&ctx->gc_gss_ctx); | 1240 | gss_delete_sec_context(&ctx->gc_gss_ctx); |
| 1227 | kfree(ctx->gc_wire_ctx.data); | 1241 | kfree(ctx->gc_wire_ctx.data); |
| 1242 | kfree(ctx->gc_acceptor.data); | ||
| 1228 | kfree(ctx); | 1243 | kfree(ctx); |
| 1229 | } | 1244 | } |
| 1230 | 1245 | ||
| @@ -1260,7 +1275,7 @@ gss_destroy_nullcred(struct rpc_cred *cred) | |||
| 1260 | { | 1275 | { |
| 1261 | struct gss_cred *gss_cred = container_of(cred, struct gss_cred, gc_base); | 1276 | struct gss_cred *gss_cred = container_of(cred, struct gss_cred, gc_base); |
| 1262 | struct gss_auth *gss_auth = container_of(cred->cr_auth, struct gss_auth, rpc_auth); | 1277 | struct gss_auth *gss_auth = container_of(cred->cr_auth, struct gss_auth, rpc_auth); |
| 1263 | struct gss_cl_ctx *ctx = gss_cred->gc_ctx; | 1278 | struct gss_cl_ctx *ctx = rcu_dereference_protected(gss_cred->gc_ctx, 1); |
| 1264 | 1279 | ||
| 1265 | RCU_INIT_POINTER(gss_cred->gc_ctx, NULL); | 1280 | RCU_INIT_POINTER(gss_cred->gc_ctx, NULL); |
| 1266 | call_rcu(&cred->cr_rcu, gss_free_cred_callback); | 1281 | call_rcu(&cred->cr_rcu, gss_free_cred_callback); |
| @@ -1332,6 +1347,36 @@ gss_cred_init(struct rpc_auth *auth, struct rpc_cred *cred) | |||
| 1332 | return err; | 1347 | return err; |
| 1333 | } | 1348 | } |
| 1334 | 1349 | ||
| 1350 | static char * | ||
| 1351 | gss_stringify_acceptor(struct rpc_cred *cred) | ||
| 1352 | { | ||
| 1353 | char *string = NULL; | ||
| 1354 | struct gss_cred *gss_cred = container_of(cred, struct gss_cred, gc_base); | ||
| 1355 | struct gss_cl_ctx *ctx; | ||
| 1356 | struct xdr_netobj *acceptor; | ||
| 1357 | |||
| 1358 | rcu_read_lock(); | ||
| 1359 | ctx = rcu_dereference(gss_cred->gc_ctx); | ||
| 1360 | if (!ctx) | ||
| 1361 | goto out; | ||
| 1362 | |||
| 1363 | acceptor = &ctx->gc_acceptor; | ||
| 1364 | |||
| 1365 | /* no point if there's no string */ | ||
| 1366 | if (!acceptor->len) | ||
| 1367 | goto out; | ||
| 1368 | |||
| 1369 | string = kmalloc(acceptor->len + 1, GFP_KERNEL); | ||
| 1370 | if (!string) | ||
| 1371 | goto out; | ||
| 1372 | |||
| 1373 | memcpy(string, acceptor->data, acceptor->len); | ||
| 1374 | string[acceptor->len] = '\0'; | ||
| 1375 | out: | ||
| 1376 | rcu_read_unlock(); | ||
| 1377 | return string; | ||
| 1378 | } | ||
| 1379 | |||
| 1335 | /* | 1380 | /* |
| 1336 | * Returns -EACCES if GSS context is NULL or will expire within the | 1381 | * Returns -EACCES if GSS context is NULL or will expire within the |
| 1337 | * timeout (miliseconds) | 1382 | * timeout (miliseconds) |
| @@ -1340,15 +1385,16 @@ static int | |||
| 1340 | gss_key_timeout(struct rpc_cred *rc) | 1385 | gss_key_timeout(struct rpc_cred *rc) |
| 1341 | { | 1386 | { |
| 1342 | struct gss_cred *gss_cred = container_of(rc, struct gss_cred, gc_base); | 1387 | struct gss_cred *gss_cred = container_of(rc, struct gss_cred, gc_base); |
| 1388 | struct gss_cl_ctx *ctx; | ||
| 1343 | unsigned long now = jiffies; | 1389 | unsigned long now = jiffies; |
| 1344 | unsigned long expire; | 1390 | unsigned long expire; |
| 1345 | 1391 | ||
| 1346 | if (gss_cred->gc_ctx == NULL) | 1392 | rcu_read_lock(); |
| 1347 | return -EACCES; | 1393 | ctx = rcu_dereference(gss_cred->gc_ctx); |
| 1348 | 1394 | if (ctx) | |
| 1349 | expire = gss_cred->gc_ctx->gc_expiry - (gss_key_expire_timeo * HZ); | 1395 | expire = ctx->gc_expiry - (gss_key_expire_timeo * HZ); |
| 1350 | 1396 | rcu_read_unlock(); | |
| 1351 | if (time_after(now, expire)) | 1397 | if (!ctx || time_after(now, expire)) |
| 1352 | return -EACCES; | 1398 | return -EACCES; |
| 1353 | return 0; | 1399 | return 0; |
| 1354 | } | 1400 | } |
| @@ -1357,13 +1403,19 @@ static int | |||
| 1357 | gss_match(struct auth_cred *acred, struct rpc_cred *rc, int flags) | 1403 | gss_match(struct auth_cred *acred, struct rpc_cred *rc, int flags) |
| 1358 | { | 1404 | { |
| 1359 | struct gss_cred *gss_cred = container_of(rc, struct gss_cred, gc_base); | 1405 | struct gss_cred *gss_cred = container_of(rc, struct gss_cred, gc_base); |
| 1406 | struct gss_cl_ctx *ctx; | ||
| 1360 | int ret; | 1407 | int ret; |
| 1361 | 1408 | ||
| 1362 | if (test_bit(RPCAUTH_CRED_NEW, &rc->cr_flags)) | 1409 | if (test_bit(RPCAUTH_CRED_NEW, &rc->cr_flags)) |
| 1363 | goto out; | 1410 | goto out; |
| 1364 | /* Don't match with creds that have expired. */ | 1411 | /* Don't match with creds that have expired. */ |
| 1365 | if (time_after(jiffies, gss_cred->gc_ctx->gc_expiry)) | 1412 | rcu_read_lock(); |
| 1413 | ctx = rcu_dereference(gss_cred->gc_ctx); | ||
| 1414 | if (!ctx || time_after(jiffies, ctx->gc_expiry)) { | ||
| 1415 | rcu_read_unlock(); | ||
| 1366 | return 0; | 1416 | return 0; |
| 1417 | } | ||
| 1418 | rcu_read_unlock(); | ||
| 1367 | if (!test_bit(RPCAUTH_CRED_UPTODATE, &rc->cr_flags)) | 1419 | if (!test_bit(RPCAUTH_CRED_UPTODATE, &rc->cr_flags)) |
| 1368 | return 0; | 1420 | return 0; |
| 1369 | out: | 1421 | out: |
| @@ -1909,29 +1961,31 @@ static const struct rpc_authops authgss_ops = { | |||
| 1909 | }; | 1961 | }; |
| 1910 | 1962 | ||
| 1911 | static const struct rpc_credops gss_credops = { | 1963 | static const struct rpc_credops gss_credops = { |
| 1912 | .cr_name = "AUTH_GSS", | 1964 | .cr_name = "AUTH_GSS", |
| 1913 | .crdestroy = gss_destroy_cred, | 1965 | .crdestroy = gss_destroy_cred, |
| 1914 | .cr_init = gss_cred_init, | 1966 | .cr_init = gss_cred_init, |
| 1915 | .crbind = rpcauth_generic_bind_cred, | 1967 | .crbind = rpcauth_generic_bind_cred, |
| 1916 | .crmatch = gss_match, | 1968 | .crmatch = gss_match, |
| 1917 | .crmarshal = gss_marshal, | 1969 | .crmarshal = gss_marshal, |
| 1918 | .crrefresh = gss_refresh, | 1970 | .crrefresh = gss_refresh, |
| 1919 | .crvalidate = gss_validate, | 1971 | .crvalidate = gss_validate, |
| 1920 | .crwrap_req = gss_wrap_req, | 1972 | .crwrap_req = gss_wrap_req, |
| 1921 | .crunwrap_resp = gss_unwrap_resp, | 1973 | .crunwrap_resp = gss_unwrap_resp, |
| 1922 | .crkey_timeout = gss_key_timeout, | 1974 | .crkey_timeout = gss_key_timeout, |
| 1975 | .crstringify_acceptor = gss_stringify_acceptor, | ||
| 1923 | }; | 1976 | }; |
| 1924 | 1977 | ||
| 1925 | static const struct rpc_credops gss_nullops = { | 1978 | static const struct rpc_credops gss_nullops = { |
| 1926 | .cr_name = "AUTH_GSS", | 1979 | .cr_name = "AUTH_GSS", |
| 1927 | .crdestroy = gss_destroy_nullcred, | 1980 | .crdestroy = gss_destroy_nullcred, |
| 1928 | .crbind = rpcauth_generic_bind_cred, | 1981 | .crbind = rpcauth_generic_bind_cred, |
| 1929 | .crmatch = gss_match, | 1982 | .crmatch = gss_match, |
| 1930 | .crmarshal = gss_marshal, | 1983 | .crmarshal = gss_marshal, |
| 1931 | .crrefresh = gss_refresh_null, | 1984 | .crrefresh = gss_refresh_null, |
| 1932 | .crvalidate = gss_validate, | 1985 | .crvalidate = gss_validate, |
| 1933 | .crwrap_req = gss_wrap_req, | 1986 | .crwrap_req = gss_wrap_req, |
| 1934 | .crunwrap_resp = gss_unwrap_resp, | 1987 | .crunwrap_resp = gss_unwrap_resp, |
| 1988 | .crstringify_acceptor = gss_stringify_acceptor, | ||
| 1935 | }; | 1989 | }; |
| 1936 | 1990 | ||
| 1937 | static const struct rpc_pipe_ops gss_upcall_ops_v0 = { | 1991 | static const struct rpc_pipe_ops gss_upcall_ops_v0 = { |
diff --git a/net/sunrpc/auth_gss/gss_krb5_crypto.c b/net/sunrpc/auth_gss/gss_krb5_crypto.c index 0f43e894bc0a..f5ed9f6ece06 100644 --- a/net/sunrpc/auth_gss/gss_krb5_crypto.c +++ b/net/sunrpc/auth_gss/gss_krb5_crypto.c | |||
| @@ -641,7 +641,7 @@ out: | |||
| 641 | 641 | ||
| 642 | u32 | 642 | u32 |
| 643 | gss_krb5_aes_encrypt(struct krb5_ctx *kctx, u32 offset, | 643 | gss_krb5_aes_encrypt(struct krb5_ctx *kctx, u32 offset, |
| 644 | struct xdr_buf *buf, int ec, struct page **pages) | 644 | struct xdr_buf *buf, struct page **pages) |
| 645 | { | 645 | { |
| 646 | u32 err; | 646 | u32 err; |
| 647 | struct xdr_netobj hmac; | 647 | struct xdr_netobj hmac; |
| @@ -684,13 +684,8 @@ gss_krb5_aes_encrypt(struct krb5_ctx *kctx, u32 offset, | |||
| 684 | ecptr = buf->tail[0].iov_base; | 684 | ecptr = buf->tail[0].iov_base; |
| 685 | } | 685 | } |
| 686 | 686 | ||
| 687 | memset(ecptr, 'X', ec); | ||
| 688 | buf->tail[0].iov_len += ec; | ||
| 689 | buf->len += ec; | ||
| 690 | |||
| 691 | /* copy plaintext gss token header after filler (if any) */ | 687 | /* copy plaintext gss token header after filler (if any) */ |
| 692 | memcpy(ecptr + ec, buf->head[0].iov_base + offset, | 688 | memcpy(ecptr, buf->head[0].iov_base + offset, GSS_KRB5_TOK_HDR_LEN); |
| 693 | GSS_KRB5_TOK_HDR_LEN); | ||
| 694 | buf->tail[0].iov_len += GSS_KRB5_TOK_HDR_LEN; | 689 | buf->tail[0].iov_len += GSS_KRB5_TOK_HDR_LEN; |
| 695 | buf->len += GSS_KRB5_TOK_HDR_LEN; | 690 | buf->len += GSS_KRB5_TOK_HDR_LEN; |
| 696 | 691 | ||
diff --git a/net/sunrpc/auth_gss/gss_krb5_seal.c b/net/sunrpc/auth_gss/gss_krb5_seal.c index 62ae3273186c..42768e5c3994 100644 --- a/net/sunrpc/auth_gss/gss_krb5_seal.c +++ b/net/sunrpc/auth_gss/gss_krb5_seal.c | |||
| @@ -70,31 +70,37 @@ | |||
| 70 | 70 | ||
| 71 | DEFINE_SPINLOCK(krb5_seq_lock); | 71 | DEFINE_SPINLOCK(krb5_seq_lock); |
| 72 | 72 | ||
| 73 | static char * | 73 | static void * |
| 74 | setup_token(struct krb5_ctx *ctx, struct xdr_netobj *token) | 74 | setup_token(struct krb5_ctx *ctx, struct xdr_netobj *token) |
| 75 | { | 75 | { |
| 76 | __be16 *ptr, *krb5_hdr; | 76 | u16 *ptr; |
| 77 | void *krb5_hdr; | ||
| 77 | int body_size = GSS_KRB5_TOK_HDR_LEN + ctx->gk5e->cksumlength; | 78 | int body_size = GSS_KRB5_TOK_HDR_LEN + ctx->gk5e->cksumlength; |
| 78 | 79 | ||
| 79 | token->len = g_token_size(&ctx->mech_used, body_size); | 80 | token->len = g_token_size(&ctx->mech_used, body_size); |
| 80 | 81 | ||
| 81 | ptr = (__be16 *)token->data; | 82 | ptr = (u16 *)token->data; |
| 82 | g_make_token_header(&ctx->mech_used, body_size, (unsigned char **)&ptr); | 83 | g_make_token_header(&ctx->mech_used, body_size, (unsigned char **)&ptr); |
| 83 | 84 | ||
| 84 | /* ptr now at start of header described in rfc 1964, section 1.2.1: */ | 85 | /* ptr now at start of header described in rfc 1964, section 1.2.1: */ |
| 85 | krb5_hdr = ptr; | 86 | krb5_hdr = ptr; |
| 86 | *ptr++ = KG_TOK_MIC_MSG; | 87 | *ptr++ = KG_TOK_MIC_MSG; |
| 87 | *ptr++ = cpu_to_le16(ctx->gk5e->signalg); | 88 | /* |
| 89 | * signalg is stored as if it were converted from LE to host endian, even | ||
| 90 | * though it's an opaque pair of bytes according to the RFC. | ||
| 91 | */ | ||
| 92 | *ptr++ = (__force u16)cpu_to_le16(ctx->gk5e->signalg); | ||
| 88 | *ptr++ = SEAL_ALG_NONE; | 93 | *ptr++ = SEAL_ALG_NONE; |
| 89 | *ptr++ = 0xffff; | 94 | *ptr = 0xffff; |
| 90 | 95 | ||
| 91 | return (char *)krb5_hdr; | 96 | return krb5_hdr; |
| 92 | } | 97 | } |
| 93 | 98 | ||
| 94 | static void * | 99 | static void * |
| 95 | setup_token_v2(struct krb5_ctx *ctx, struct xdr_netobj *token) | 100 | setup_token_v2(struct krb5_ctx *ctx, struct xdr_netobj *token) |
| 96 | { | 101 | { |
| 97 | __be16 *ptr, *krb5_hdr; | 102 | u16 *ptr; |
| 103 | void *krb5_hdr; | ||
| 98 | u8 *p, flags = 0x00; | 104 | u8 *p, flags = 0x00; |
| 99 | 105 | ||
| 100 | if ((ctx->flags & KRB5_CTX_FLAG_INITIATOR) == 0) | 106 | if ((ctx->flags & KRB5_CTX_FLAG_INITIATOR) == 0) |
| @@ -104,15 +110,15 @@ setup_token_v2(struct krb5_ctx *ctx, struct xdr_netobj *token) | |||
| 104 | 110 | ||
| 105 | /* Per rfc 4121, sec 4.2.6.1, there is no header, | 111 | /* Per rfc 4121, sec 4.2.6.1, there is no header, |
| 106 | * just start the token */ | 112 | * just start the token */ |
| 107 | krb5_hdr = ptr = (__be16 *)token->data; | 113 | krb5_hdr = ptr = (u16 *)token->data; |
| 108 | 114 | ||
| 109 | *ptr++ = KG2_TOK_MIC; | 115 | *ptr++ = KG2_TOK_MIC; |
| 110 | p = (u8 *)ptr; | 116 | p = (u8 *)ptr; |
| 111 | *p++ = flags; | 117 | *p++ = flags; |
| 112 | *p++ = 0xff; | 118 | *p++ = 0xff; |
| 113 | ptr = (__be16 *)p; | 119 | ptr = (u16 *)p; |
| 114 | *ptr++ = 0xffff; | ||
| 115 | *ptr++ = 0xffff; | 120 | *ptr++ = 0xffff; |
| 121 | *ptr = 0xffff; | ||
| 116 | 122 | ||
| 117 | token->len = GSS_KRB5_TOK_HDR_LEN + ctx->gk5e->cksumlength; | 123 | token->len = GSS_KRB5_TOK_HDR_LEN + ctx->gk5e->cksumlength; |
| 118 | return krb5_hdr; | 124 | return krb5_hdr; |
| @@ -181,7 +187,7 @@ gss_get_mic_v2(struct krb5_ctx *ctx, struct xdr_buf *text, | |||
| 181 | spin_lock(&krb5_seq_lock); | 187 | spin_lock(&krb5_seq_lock); |
| 182 | seq_send = ctx->seq_send64++; | 188 | seq_send = ctx->seq_send64++; |
| 183 | spin_unlock(&krb5_seq_lock); | 189 | spin_unlock(&krb5_seq_lock); |
| 184 | *((u64 *)(krb5_hdr + 8)) = cpu_to_be64(seq_send); | 190 | *((__be64 *)(krb5_hdr + 8)) = cpu_to_be64(seq_send); |
| 185 | 191 | ||
| 186 | if (ctx->initiate) { | 192 | if (ctx->initiate) { |
| 187 | cksumkey = ctx->initiator_sign; | 193 | cksumkey = ctx->initiator_sign; |
diff --git a/net/sunrpc/auth_gss/gss_krb5_wrap.c b/net/sunrpc/auth_gss/gss_krb5_wrap.c index 42560e55d978..4b614c604fe0 100644 --- a/net/sunrpc/auth_gss/gss_krb5_wrap.c +++ b/net/sunrpc/auth_gss/gss_krb5_wrap.c | |||
| @@ -201,9 +201,15 @@ gss_wrap_kerberos_v1(struct krb5_ctx *kctx, int offset, | |||
| 201 | 201 | ||
| 202 | msg_start = ptr + GSS_KRB5_TOK_HDR_LEN + kctx->gk5e->cksumlength; | 202 | msg_start = ptr + GSS_KRB5_TOK_HDR_LEN + kctx->gk5e->cksumlength; |
| 203 | 203 | ||
| 204 | *(__be16 *)(ptr + 2) = cpu_to_le16(kctx->gk5e->signalg); | 204 | /* |
| 205 | memset(ptr + 4, 0xff, 4); | 205 | * signalg and sealalg are stored as if they were converted from LE |
| 206 | *(__be16 *)(ptr + 4) = cpu_to_le16(kctx->gk5e->sealalg); | 206 | * to host endian, even though they're opaque pairs of bytes according |
| 207 | * to the RFC. | ||
| 208 | */ | ||
| 209 | *(__le16 *)(ptr + 2) = cpu_to_le16(kctx->gk5e->signalg); | ||
| 210 | *(__le16 *)(ptr + 4) = cpu_to_le16(kctx->gk5e->sealalg); | ||
| 211 | ptr[6] = 0xff; | ||
| 212 | ptr[7] = 0xff; | ||
| 207 | 213 | ||
| 208 | gss_krb5_make_confounder(msg_start, conflen); | 214 | gss_krb5_make_confounder(msg_start, conflen); |
| 209 | 215 | ||
| @@ -438,7 +444,7 @@ gss_wrap_kerberos_v2(struct krb5_ctx *kctx, u32 offset, | |||
| 438 | u8 *ptr, *plainhdr; | 444 | u8 *ptr, *plainhdr; |
| 439 | s32 now; | 445 | s32 now; |
| 440 | u8 flags = 0x00; | 446 | u8 flags = 0x00; |
| 441 | __be16 *be16ptr, ec = 0; | 447 | __be16 *be16ptr; |
| 442 | __be64 *be64ptr; | 448 | __be64 *be64ptr; |
| 443 | u32 err; | 449 | u32 err; |
| 444 | 450 | ||
| @@ -468,16 +474,16 @@ gss_wrap_kerberos_v2(struct krb5_ctx *kctx, u32 offset, | |||
| 468 | be16ptr = (__be16 *)ptr; | 474 | be16ptr = (__be16 *)ptr; |
| 469 | 475 | ||
| 470 | blocksize = crypto_blkcipher_blocksize(kctx->acceptor_enc); | 476 | blocksize = crypto_blkcipher_blocksize(kctx->acceptor_enc); |
| 471 | *be16ptr++ = cpu_to_be16(ec); | 477 | *be16ptr++ = 0; |
| 472 | /* "inner" token header always uses 0 for RRC */ | 478 | /* "inner" token header always uses 0 for RRC */ |
| 473 | *be16ptr++ = cpu_to_be16(0); | 479 | *be16ptr++ = 0; |
| 474 | 480 | ||
| 475 | be64ptr = (__be64 *)be16ptr; | 481 | be64ptr = (__be64 *)be16ptr; |
| 476 | spin_lock(&krb5_seq_lock); | 482 | spin_lock(&krb5_seq_lock); |
| 477 | *be64ptr = cpu_to_be64(kctx->seq_send64++); | 483 | *be64ptr = cpu_to_be64(kctx->seq_send64++); |
| 478 | spin_unlock(&krb5_seq_lock); | 484 | spin_unlock(&krb5_seq_lock); |
| 479 | 485 | ||
| 480 | err = (*kctx->gk5e->encrypt_v2)(kctx, offset, buf, ec, pages); | 486 | err = (*kctx->gk5e->encrypt_v2)(kctx, offset, buf, pages); |
| 481 | if (err) | 487 | if (err) |
| 482 | return err; | 488 | return err; |
| 483 | 489 | ||
diff --git a/net/sunrpc/auth_gss/svcauth_gss.c b/net/sunrpc/auth_gss/svcauth_gss.c index 4ce5eccec1f6..c548ab213f76 100644 --- a/net/sunrpc/auth_gss/svcauth_gss.c +++ b/net/sunrpc/auth_gss/svcauth_gss.c | |||
| @@ -886,7 +886,7 @@ unwrap_priv_data(struct svc_rqst *rqstp, struct xdr_buf *buf, u32 seq, struct gs | |||
| 886 | u32 priv_len, maj_stat; | 886 | u32 priv_len, maj_stat; |
| 887 | int pad, saved_len, remaining_len, offset; | 887 | int pad, saved_len, remaining_len, offset; |
| 888 | 888 | ||
| 889 | rqstp->rq_splice_ok = 0; | 889 | rqstp->rq_splice_ok = false; |
| 890 | 890 | ||
| 891 | priv_len = svc_getnl(&buf->head[0]); | 891 | priv_len = svc_getnl(&buf->head[0]); |
| 892 | if (rqstp->rq_deferred) { | 892 | if (rqstp->rq_deferred) { |
diff --git a/net/sunrpc/auth_null.c b/net/sunrpc/auth_null.c index f0ebe07978a2..712c123e04e9 100644 --- a/net/sunrpc/auth_null.c +++ b/net/sunrpc/auth_null.c | |||
| @@ -35,6 +35,8 @@ nul_destroy(struct rpc_auth *auth) | |||
| 35 | static struct rpc_cred * | 35 | static struct rpc_cred * |
| 36 | nul_lookup_cred(struct rpc_auth *auth, struct auth_cred *acred, int flags) | 36 | nul_lookup_cred(struct rpc_auth *auth, struct auth_cred *acred, int flags) |
| 37 | { | 37 | { |
| 38 | if (flags & RPCAUTH_LOOKUP_RCU) | ||
| 39 | return &null_cred; | ||
| 38 | return get_rpccred(&null_cred); | 40 | return get_rpccred(&null_cred); |
| 39 | } | 41 | } |
| 40 | 42 | ||
diff --git a/net/sunrpc/clnt.c b/net/sunrpc/clnt.c index 2e6ab10734f6..488ddeed9363 100644 --- a/net/sunrpc/clnt.c +++ b/net/sunrpc/clnt.c | |||
| @@ -1746,6 +1746,7 @@ call_bind_status(struct rpc_task *task) | |||
| 1746 | case -EHOSTDOWN: | 1746 | case -EHOSTDOWN: |
| 1747 | case -EHOSTUNREACH: | 1747 | case -EHOSTUNREACH: |
| 1748 | case -ENETUNREACH: | 1748 | case -ENETUNREACH: |
| 1749 | case -ENOBUFS: | ||
| 1749 | case -EPIPE: | 1750 | case -EPIPE: |
| 1750 | dprintk("RPC: %5u remote rpcbind unreachable: %d\n", | 1751 | dprintk("RPC: %5u remote rpcbind unreachable: %d\n", |
| 1751 | task->tk_pid, task->tk_status); | 1752 | task->tk_pid, task->tk_status); |
| @@ -1812,6 +1813,8 @@ call_connect_status(struct rpc_task *task) | |||
| 1812 | case -ECONNABORTED: | 1813 | case -ECONNABORTED: |
| 1813 | case -ENETUNREACH: | 1814 | case -ENETUNREACH: |
| 1814 | case -EHOSTUNREACH: | 1815 | case -EHOSTUNREACH: |
| 1816 | case -ENOBUFS: | ||
| 1817 | case -EPIPE: | ||
| 1815 | if (RPC_IS_SOFTCONN(task)) | 1818 | if (RPC_IS_SOFTCONN(task)) |
| 1816 | break; | 1819 | break; |
| 1817 | /* retry with existing socket, after a delay */ | 1820 | /* retry with existing socket, after a delay */ |
| @@ -1918,6 +1921,7 @@ call_transmit_status(struct rpc_task *task) | |||
| 1918 | case -ECONNRESET: | 1921 | case -ECONNRESET: |
| 1919 | case -ECONNABORTED: | 1922 | case -ECONNABORTED: |
| 1920 | case -ENOTCONN: | 1923 | case -ENOTCONN: |
| 1924 | case -ENOBUFS: | ||
| 1921 | case -EPIPE: | 1925 | case -EPIPE: |
| 1922 | rpc_task_force_reencode(task); | 1926 | rpc_task_force_reencode(task); |
| 1923 | } | 1927 | } |
| @@ -2034,6 +2038,7 @@ call_status(struct rpc_task *task) | |||
| 2034 | case -ECONNRESET: | 2038 | case -ECONNRESET: |
| 2035 | case -ECONNABORTED: | 2039 | case -ECONNABORTED: |
| 2036 | rpc_force_rebind(clnt); | 2040 | rpc_force_rebind(clnt); |
| 2041 | case -ENOBUFS: | ||
| 2037 | rpc_delay(task, 3*HZ); | 2042 | rpc_delay(task, 3*HZ); |
| 2038 | case -EPIPE: | 2043 | case -EPIPE: |
| 2039 | case -ENOTCONN: | 2044 | case -ENOTCONN: |
diff --git a/net/sunrpc/rpc_pipe.c b/net/sunrpc/rpc_pipe.c index b18554898562..2d12b76b5a64 100644 --- a/net/sunrpc/rpc_pipe.c +++ b/net/sunrpc/rpc_pipe.c | |||
| @@ -195,7 +195,7 @@ static struct inode * | |||
| 195 | rpc_alloc_inode(struct super_block *sb) | 195 | rpc_alloc_inode(struct super_block *sb) |
| 196 | { | 196 | { |
| 197 | struct rpc_inode *rpci; | 197 | struct rpc_inode *rpci; |
| 198 | rpci = (struct rpc_inode *)kmem_cache_alloc(rpc_inode_cachep, GFP_KERNEL); | 198 | rpci = kmem_cache_alloc(rpc_inode_cachep, GFP_KERNEL); |
| 199 | if (!rpci) | 199 | if (!rpci) |
| 200 | return NULL; | 200 | return NULL; |
| 201 | return &rpci->vfs_inode; | 201 | return &rpci->vfs_inode; |
diff --git a/net/sunrpc/sched.c b/net/sunrpc/sched.c index c0365c14b858..9358c79fd589 100644 --- a/net/sunrpc/sched.c +++ b/net/sunrpc/sched.c | |||
| @@ -250,7 +250,7 @@ void rpc_destroy_wait_queue(struct rpc_wait_queue *queue) | |||
| 250 | } | 250 | } |
| 251 | EXPORT_SYMBOL_GPL(rpc_destroy_wait_queue); | 251 | EXPORT_SYMBOL_GPL(rpc_destroy_wait_queue); |
| 252 | 252 | ||
| 253 | static int rpc_wait_bit_killable(void *word) | 253 | static int rpc_wait_bit_killable(struct wait_bit_key *key) |
| 254 | { | 254 | { |
| 255 | if (fatal_signal_pending(current)) | 255 | if (fatal_signal_pending(current)) |
| 256 | return -ERESTARTSYS; | 256 | return -ERESTARTSYS; |
| @@ -309,7 +309,7 @@ static int rpc_complete_task(struct rpc_task *task) | |||
| 309 | * to enforce taking of the wq->lock and hence avoid races with | 309 | * to enforce taking of the wq->lock and hence avoid races with |
| 310 | * rpc_complete_task(). | 310 | * rpc_complete_task(). |
| 311 | */ | 311 | */ |
| 312 | int __rpc_wait_for_completion_task(struct rpc_task *task, int (*action)(void *)) | 312 | int __rpc_wait_for_completion_task(struct rpc_task *task, wait_bit_action_f *action) |
| 313 | { | 313 | { |
| 314 | if (action == NULL) | 314 | if (action == NULL) |
| 315 | action = rpc_wait_bit_killable; | 315 | action = rpc_wait_bit_killable; |
diff --git a/net/sunrpc/svc.c b/net/sunrpc/svc.c index 5de6801cd924..1db5007ddbce 100644 --- a/net/sunrpc/svc.c +++ b/net/sunrpc/svc.c | |||
| @@ -1086,9 +1086,9 @@ svc_process_common(struct svc_rqst *rqstp, struct kvec *argv, struct kvec *resv) | |||
| 1086 | goto err_short_len; | 1086 | goto err_short_len; |
| 1087 | 1087 | ||
| 1088 | /* Will be turned off only in gss privacy case: */ | 1088 | /* Will be turned off only in gss privacy case: */ |
| 1089 | rqstp->rq_splice_ok = 1; | 1089 | rqstp->rq_splice_ok = true; |
| 1090 | /* Will be turned off only when NFSv4 Sessions are used */ | 1090 | /* Will be turned off only when NFSv4 Sessions are used */ |
| 1091 | rqstp->rq_usedeferral = 1; | 1091 | rqstp->rq_usedeferral = true; |
| 1092 | rqstp->rq_dropme = false; | 1092 | rqstp->rq_dropme = false; |
| 1093 | 1093 | ||
| 1094 | /* Setup reply header */ | 1094 | /* Setup reply header */ |
diff --git a/net/sunrpc/svc_xprt.c b/net/sunrpc/svc_xprt.c index b4737fbdec13..6666c6745858 100644 --- a/net/sunrpc/svc_xprt.c +++ b/net/sunrpc/svc_xprt.c | |||
| @@ -23,6 +23,7 @@ static int svc_deferred_recv(struct svc_rqst *rqstp); | |||
| 23 | static struct cache_deferred_req *svc_defer(struct cache_req *req); | 23 | static struct cache_deferred_req *svc_defer(struct cache_req *req); |
| 24 | static void svc_age_temp_xprts(unsigned long closure); | 24 | static void svc_age_temp_xprts(unsigned long closure); |
| 25 | static void svc_delete_xprt(struct svc_xprt *xprt); | 25 | static void svc_delete_xprt(struct svc_xprt *xprt); |
| 26 | static void svc_xprt_do_enqueue(struct svc_xprt *xprt); | ||
| 26 | 27 | ||
| 27 | /* apparently the "standard" is that clients close | 28 | /* apparently the "standard" is that clients close |
| 28 | * idle connections after 5 minutes, servers after | 29 | * idle connections after 5 minutes, servers after |
| @@ -222,11 +223,12 @@ static void svc_xprt_received(struct svc_xprt *xprt) | |||
| 222 | if (!test_bit(XPT_BUSY, &xprt->xpt_flags)) | 223 | if (!test_bit(XPT_BUSY, &xprt->xpt_flags)) |
| 223 | return; | 224 | return; |
| 224 | /* As soon as we clear busy, the xprt could be closed and | 225 | /* As soon as we clear busy, the xprt could be closed and |
| 225 | * 'put', so we need a reference to call svc_xprt_enqueue with: | 226 | * 'put', so we need a reference to call svc_xprt_do_enqueue with: |
| 226 | */ | 227 | */ |
| 227 | svc_xprt_get(xprt); | 228 | svc_xprt_get(xprt); |
| 229 | smp_mb__before_atomic(); | ||
| 228 | clear_bit(XPT_BUSY, &xprt->xpt_flags); | 230 | clear_bit(XPT_BUSY, &xprt->xpt_flags); |
| 229 | svc_xprt_enqueue(xprt); | 231 | svc_xprt_do_enqueue(xprt); |
| 230 | svc_xprt_put(xprt); | 232 | svc_xprt_put(xprt); |
| 231 | } | 233 | } |
| 232 | 234 | ||
| @@ -335,12 +337,7 @@ static bool svc_xprt_has_something_to_do(struct svc_xprt *xprt) | |||
| 335 | return false; | 337 | return false; |
| 336 | } | 338 | } |
| 337 | 339 | ||
| 338 | /* | 340 | static void svc_xprt_do_enqueue(struct svc_xprt *xprt) |
| 339 | * Queue up a transport with data pending. If there are idle nfsd | ||
| 340 | * processes, wake 'em up. | ||
| 341 | * | ||
| 342 | */ | ||
| 343 | void svc_xprt_enqueue(struct svc_xprt *xprt) | ||
| 344 | { | 341 | { |
| 345 | struct svc_pool *pool; | 342 | struct svc_pool *pool; |
| 346 | struct svc_rqst *rqstp; | 343 | struct svc_rqst *rqstp; |
| @@ -398,6 +395,18 @@ void svc_xprt_enqueue(struct svc_xprt *xprt) | |||
| 398 | out_unlock: | 395 | out_unlock: |
| 399 | spin_unlock_bh(&pool->sp_lock); | 396 | spin_unlock_bh(&pool->sp_lock); |
| 400 | } | 397 | } |
| 398 | |||
| 399 | /* | ||
| 400 | * Queue up a transport with data pending. If there are idle nfsd | ||
| 401 | * processes, wake 'em up. | ||
| 402 | * | ||
| 403 | */ | ||
| 404 | void svc_xprt_enqueue(struct svc_xprt *xprt) | ||
| 405 | { | ||
| 406 | if (test_bit(XPT_BUSY, &xprt->xpt_flags)) | ||
| 407 | return; | ||
| 408 | svc_xprt_do_enqueue(xprt); | ||
| 409 | } | ||
| 401 | EXPORT_SYMBOL_GPL(svc_xprt_enqueue); | 410 | EXPORT_SYMBOL_GPL(svc_xprt_enqueue); |
| 402 | 411 | ||
| 403 | /* | 412 | /* |
| @@ -439,6 +448,8 @@ void svc_reserve(struct svc_rqst *rqstp, int space) | |||
| 439 | atomic_sub((rqstp->rq_reserved - space), &xprt->xpt_reserved); | 448 | atomic_sub((rqstp->rq_reserved - space), &xprt->xpt_reserved); |
| 440 | rqstp->rq_reserved = space; | 449 | rqstp->rq_reserved = space; |
| 441 | 450 | ||
| 451 | if (xprt->xpt_ops->xpo_adjust_wspace) | ||
| 452 | xprt->xpt_ops->xpo_adjust_wspace(xprt); | ||
| 442 | svc_xprt_enqueue(xprt); | 453 | svc_xprt_enqueue(xprt); |
| 443 | } | 454 | } |
| 444 | } | 455 | } |
diff --git a/net/sunrpc/svcsock.c b/net/sunrpc/svcsock.c index b507cd327d9b..c24a8ff33f8f 100644 --- a/net/sunrpc/svcsock.c +++ b/net/sunrpc/svcsock.c | |||
| @@ -446,15 +446,43 @@ static void svc_write_space(struct sock *sk) | |||
| 446 | } | 446 | } |
| 447 | } | 447 | } |
| 448 | 448 | ||
| 449 | static int svc_tcp_has_wspace(struct svc_xprt *xprt) | ||
| 450 | { | ||
| 451 | struct svc_sock *svsk = container_of(xprt, struct svc_sock, sk_xprt); | ||
| 452 | struct svc_serv *serv = svsk->sk_xprt.xpt_server; | ||
| 453 | int required; | ||
| 454 | |||
| 455 | if (test_bit(XPT_LISTENER, &xprt->xpt_flags)) | ||
| 456 | return 1; | ||
| 457 | required = atomic_read(&xprt->xpt_reserved) + serv->sv_max_mesg; | ||
| 458 | if (sk_stream_wspace(svsk->sk_sk) >= required || | ||
| 459 | (sk_stream_min_wspace(svsk->sk_sk) == 0 && | ||
| 460 | atomic_read(&xprt->xpt_reserved) == 0)) | ||
| 461 | return 1; | ||
| 462 | set_bit(SOCK_NOSPACE, &svsk->sk_sock->flags); | ||
| 463 | return 0; | ||
| 464 | } | ||
| 465 | |||
| 449 | static void svc_tcp_write_space(struct sock *sk) | 466 | static void svc_tcp_write_space(struct sock *sk) |
| 450 | { | 467 | { |
| 468 | struct svc_sock *svsk = (struct svc_sock *)(sk->sk_user_data); | ||
| 451 | struct socket *sock = sk->sk_socket; | 469 | struct socket *sock = sk->sk_socket; |
| 452 | 470 | ||
| 453 | if (sk_stream_is_writeable(sk) && sock) | 471 | if (!sk_stream_is_writeable(sk) || !sock) |
| 472 | return; | ||
| 473 | if (!svsk || svc_tcp_has_wspace(&svsk->sk_xprt)) | ||
| 454 | clear_bit(SOCK_NOSPACE, &sock->flags); | 474 | clear_bit(SOCK_NOSPACE, &sock->flags); |
| 455 | svc_write_space(sk); | 475 | svc_write_space(sk); |
| 456 | } | 476 | } |
| 457 | 477 | ||
| 478 | static void svc_tcp_adjust_wspace(struct svc_xprt *xprt) | ||
| 479 | { | ||
| 480 | struct svc_sock *svsk = container_of(xprt, struct svc_sock, sk_xprt); | ||
| 481 | |||
| 482 | if (svc_tcp_has_wspace(xprt)) | ||
| 483 | clear_bit(SOCK_NOSPACE, &svsk->sk_sock->flags); | ||
| 484 | } | ||
| 485 | |||
| 458 | /* | 486 | /* |
| 459 | * See net/ipv6/ip_sockglue.c : ip_cmsg_recv_pktinfo | 487 | * See net/ipv6/ip_sockglue.c : ip_cmsg_recv_pktinfo |
| 460 | */ | 488 | */ |
| @@ -692,6 +720,7 @@ static struct svc_xprt_class svc_udp_class = { | |||
| 692 | .xcl_owner = THIS_MODULE, | 720 | .xcl_owner = THIS_MODULE, |
| 693 | .xcl_ops = &svc_udp_ops, | 721 | .xcl_ops = &svc_udp_ops, |
| 694 | .xcl_max_payload = RPCSVC_MAXPAYLOAD_UDP, | 722 | .xcl_max_payload = RPCSVC_MAXPAYLOAD_UDP, |
| 723 | .xcl_ident = XPRT_TRANSPORT_UDP, | ||
| 695 | }; | 724 | }; |
| 696 | 725 | ||
| 697 | static void svc_udp_init(struct svc_sock *svsk, struct svc_serv *serv) | 726 | static void svc_udp_init(struct svc_sock *svsk, struct svc_serv *serv) |
| @@ -1197,23 +1226,6 @@ static void svc_tcp_prep_reply_hdr(struct svc_rqst *rqstp) | |||
| 1197 | svc_putnl(resv, 0); | 1226 | svc_putnl(resv, 0); |
| 1198 | } | 1227 | } |
| 1199 | 1228 | ||
| 1200 | static int svc_tcp_has_wspace(struct svc_xprt *xprt) | ||
| 1201 | { | ||
| 1202 | struct svc_sock *svsk = container_of(xprt, struct svc_sock, sk_xprt); | ||
| 1203 | struct svc_serv *serv = svsk->sk_xprt.xpt_server; | ||
| 1204 | int required; | ||
| 1205 | |||
| 1206 | if (test_bit(XPT_LISTENER, &xprt->xpt_flags)) | ||
| 1207 | return 1; | ||
| 1208 | required = atomic_read(&xprt->xpt_reserved) + serv->sv_max_mesg; | ||
| 1209 | if (sk_stream_wspace(svsk->sk_sk) >= required || | ||
| 1210 | (sk_stream_min_wspace(svsk->sk_sk) == 0 && | ||
| 1211 | atomic_read(&xprt->xpt_reserved) == 0)) | ||
| 1212 | return 1; | ||
| 1213 | set_bit(SOCK_NOSPACE, &svsk->sk_sock->flags); | ||
| 1214 | return 0; | ||
| 1215 | } | ||
| 1216 | |||
| 1217 | static struct svc_xprt *svc_tcp_create(struct svc_serv *serv, | 1229 | static struct svc_xprt *svc_tcp_create(struct svc_serv *serv, |
| 1218 | struct net *net, | 1230 | struct net *net, |
| 1219 | struct sockaddr *sa, int salen, | 1231 | struct sockaddr *sa, int salen, |
| @@ -1285,6 +1297,7 @@ static struct svc_xprt_ops svc_tcp_ops = { | |||
| 1285 | .xpo_has_wspace = svc_tcp_has_wspace, | 1297 | .xpo_has_wspace = svc_tcp_has_wspace, |
| 1286 | .xpo_accept = svc_tcp_accept, | 1298 | .xpo_accept = svc_tcp_accept, |
| 1287 | .xpo_secure_port = svc_sock_secure_port, | 1299 | .xpo_secure_port = svc_sock_secure_port, |
| 1300 | .xpo_adjust_wspace = svc_tcp_adjust_wspace, | ||
| 1288 | }; | 1301 | }; |
| 1289 | 1302 | ||
| 1290 | static struct svc_xprt_class svc_tcp_class = { | 1303 | static struct svc_xprt_class svc_tcp_class = { |
| @@ -1292,6 +1305,7 @@ static struct svc_xprt_class svc_tcp_class = { | |||
| 1292 | .xcl_owner = THIS_MODULE, | 1305 | .xcl_owner = THIS_MODULE, |
| 1293 | .xcl_ops = &svc_tcp_ops, | 1306 | .xcl_ops = &svc_tcp_ops, |
| 1294 | .xcl_max_payload = RPCSVC_MAXPAYLOAD_TCP, | 1307 | .xcl_max_payload = RPCSVC_MAXPAYLOAD_TCP, |
| 1308 | .xcl_ident = XPRT_TRANSPORT_TCP, | ||
| 1295 | }; | 1309 | }; |
| 1296 | 1310 | ||
| 1297 | void svc_init_xprt_sock(void) | 1311 | void svc_init_xprt_sock(void) |
diff --git a/net/sunrpc/xdr.c b/net/sunrpc/xdr.c index 23fb4e75e245..290af97bf6f9 100644 --- a/net/sunrpc/xdr.c +++ b/net/sunrpc/xdr.c | |||
| @@ -509,7 +509,8 @@ void xdr_commit_encode(struct xdr_stream *xdr) | |||
| 509 | } | 509 | } |
| 510 | EXPORT_SYMBOL_GPL(xdr_commit_encode); | 510 | EXPORT_SYMBOL_GPL(xdr_commit_encode); |
| 511 | 511 | ||
| 512 | __be32 *xdr_get_next_encode_buffer(struct xdr_stream *xdr, size_t nbytes) | 512 | static __be32 *xdr_get_next_encode_buffer(struct xdr_stream *xdr, |
| 513 | size_t nbytes) | ||
| 513 | { | 514 | { |
| 514 | static __be32 *p; | 515 | static __be32 *p; |
| 515 | int space_left; | 516 | int space_left; |
diff --git a/net/sunrpc/xprt.c b/net/sunrpc/xprt.c index c3b2b3369e52..56e4e150e80e 100644 --- a/net/sunrpc/xprt.c +++ b/net/sunrpc/xprt.c | |||
| @@ -744,6 +744,7 @@ static void xprt_connect_status(struct rpc_task *task) | |||
| 744 | case -ECONNABORTED: | 744 | case -ECONNABORTED: |
| 745 | case -ENETUNREACH: | 745 | case -ENETUNREACH: |
| 746 | case -EHOSTUNREACH: | 746 | case -EHOSTUNREACH: |
| 747 | case -EPIPE: | ||
| 747 | case -EAGAIN: | 748 | case -EAGAIN: |
| 748 | dprintk("RPC: %5u xprt_connect_status: retrying\n", task->tk_pid); | 749 | dprintk("RPC: %5u xprt_connect_status: retrying\n", task->tk_pid); |
| 749 | break; | 750 | break; |
| @@ -1306,7 +1307,7 @@ struct rpc_xprt *xprt_create_transport(struct xprt_create *args) | |||
| 1306 | } | 1307 | } |
| 1307 | } | 1308 | } |
| 1308 | spin_unlock(&xprt_list_lock); | 1309 | spin_unlock(&xprt_list_lock); |
| 1309 | printk(KERN_ERR "RPC: transport (%d) not supported\n", args->ident); | 1310 | dprintk("RPC: transport (%d) not supported\n", args->ident); |
| 1310 | return ERR_PTR(-EIO); | 1311 | return ERR_PTR(-EIO); |
| 1311 | 1312 | ||
| 1312 | found: | 1313 | found: |
diff --git a/net/sunrpc/xprtrdma/rpc_rdma.c b/net/sunrpc/xprtrdma/rpc_rdma.c index 693966d3f33b..6166c985fe24 100644 --- a/net/sunrpc/xprtrdma/rpc_rdma.c +++ b/net/sunrpc/xprtrdma/rpc_rdma.c | |||
| @@ -53,14 +53,6 @@ | |||
| 53 | # define RPCDBG_FACILITY RPCDBG_TRANS | 53 | # define RPCDBG_FACILITY RPCDBG_TRANS |
| 54 | #endif | 54 | #endif |
| 55 | 55 | ||
| 56 | enum rpcrdma_chunktype { | ||
| 57 | rpcrdma_noch = 0, | ||
| 58 | rpcrdma_readch, | ||
| 59 | rpcrdma_areadch, | ||
| 60 | rpcrdma_writech, | ||
| 61 | rpcrdma_replych | ||
| 62 | }; | ||
| 63 | |||
| 64 | #ifdef RPC_DEBUG | 56 | #ifdef RPC_DEBUG |
| 65 | static const char transfertypes[][12] = { | 57 | static const char transfertypes[][12] = { |
| 66 | "pure inline", /* no chunks */ | 58 | "pure inline", /* no chunks */ |
| @@ -279,13 +271,37 @@ rpcrdma_create_chunks(struct rpc_rqst *rqst, struct xdr_buf *target, | |||
| 279 | return (unsigned char *)iptr - (unsigned char *)headerp; | 271 | return (unsigned char *)iptr - (unsigned char *)headerp; |
| 280 | 272 | ||
| 281 | out: | 273 | out: |
| 282 | for (pos = 0; nchunks--;) | 274 | if (r_xprt->rx_ia.ri_memreg_strategy != RPCRDMA_FRMR) { |
| 283 | pos += rpcrdma_deregister_external( | 275 | for (pos = 0; nchunks--;) |
| 284 | &req->rl_segments[pos], r_xprt); | 276 | pos += rpcrdma_deregister_external( |
| 277 | &req->rl_segments[pos], r_xprt); | ||
| 278 | } | ||
| 285 | return n; | 279 | return n; |
| 286 | } | 280 | } |
| 287 | 281 | ||
| 288 | /* | 282 | /* |
| 283 | * Marshal chunks. This routine returns the header length | ||
| 284 | * consumed by marshaling. | ||
| 285 | * | ||
| 286 | * Returns positive RPC/RDMA header size, or negative errno. | ||
| 287 | */ | ||
| 288 | |||
| 289 | ssize_t | ||
| 290 | rpcrdma_marshal_chunks(struct rpc_rqst *rqst, ssize_t result) | ||
| 291 | { | ||
| 292 | struct rpcrdma_req *req = rpcr_to_rdmar(rqst); | ||
| 293 | struct rpcrdma_msg *headerp = (struct rpcrdma_msg *)req->rl_base; | ||
| 294 | |||
| 295 | if (req->rl_rtype != rpcrdma_noch) | ||
| 296 | result = rpcrdma_create_chunks(rqst, &rqst->rq_snd_buf, | ||
| 297 | headerp, req->rl_rtype); | ||
| 298 | else if (req->rl_wtype != rpcrdma_noch) | ||
| 299 | result = rpcrdma_create_chunks(rqst, &rqst->rq_rcv_buf, | ||
| 300 | headerp, req->rl_wtype); | ||
| 301 | return result; | ||
| 302 | } | ||
| 303 | |||
| 304 | /* | ||
| 289 | * Copy write data inline. | 305 | * Copy write data inline. |
| 290 | * This function is used for "small" requests. Data which is passed | 306 | * This function is used for "small" requests. Data which is passed |
| 291 | * to RPC via iovecs (or page list) is copied directly into the | 307 | * to RPC via iovecs (or page list) is copied directly into the |
| @@ -377,7 +393,6 @@ rpcrdma_marshal_req(struct rpc_rqst *rqst) | |||
| 377 | char *base; | 393 | char *base; |
| 378 | size_t rpclen, padlen; | 394 | size_t rpclen, padlen; |
| 379 | ssize_t hdrlen; | 395 | ssize_t hdrlen; |
| 380 | enum rpcrdma_chunktype rtype, wtype; | ||
| 381 | struct rpcrdma_msg *headerp; | 396 | struct rpcrdma_msg *headerp; |
| 382 | 397 | ||
| 383 | /* | 398 | /* |
| @@ -415,13 +430,13 @@ rpcrdma_marshal_req(struct rpc_rqst *rqst) | |||
| 415 | * into pages; otherwise use reply chunks. | 430 | * into pages; otherwise use reply chunks. |
| 416 | */ | 431 | */ |
| 417 | if (rqst->rq_rcv_buf.buflen <= RPCRDMA_INLINE_READ_THRESHOLD(rqst)) | 432 | if (rqst->rq_rcv_buf.buflen <= RPCRDMA_INLINE_READ_THRESHOLD(rqst)) |
| 418 | wtype = rpcrdma_noch; | 433 | req->rl_wtype = rpcrdma_noch; |
| 419 | else if (rqst->rq_rcv_buf.page_len == 0) | 434 | else if (rqst->rq_rcv_buf.page_len == 0) |
| 420 | wtype = rpcrdma_replych; | 435 | req->rl_wtype = rpcrdma_replych; |
| 421 | else if (rqst->rq_rcv_buf.flags & XDRBUF_READ) | 436 | else if (rqst->rq_rcv_buf.flags & XDRBUF_READ) |
| 422 | wtype = rpcrdma_writech; | 437 | req->rl_wtype = rpcrdma_writech; |
| 423 | else | 438 | else |
| 424 | wtype = rpcrdma_replych; | 439 | req->rl_wtype = rpcrdma_replych; |
| 425 | 440 | ||
| 426 | /* | 441 | /* |
| 427 | * Chunks needed for arguments? | 442 | * Chunks needed for arguments? |
| @@ -438,16 +453,16 @@ rpcrdma_marshal_req(struct rpc_rqst *rqst) | |||
| 438 | * TBD check NFSv4 setacl | 453 | * TBD check NFSv4 setacl |
| 439 | */ | 454 | */ |
| 440 | if (rqst->rq_snd_buf.len <= RPCRDMA_INLINE_WRITE_THRESHOLD(rqst)) | 455 | if (rqst->rq_snd_buf.len <= RPCRDMA_INLINE_WRITE_THRESHOLD(rqst)) |
| 441 | rtype = rpcrdma_noch; | 456 | req->rl_rtype = rpcrdma_noch; |
| 442 | else if (rqst->rq_snd_buf.page_len == 0) | 457 | else if (rqst->rq_snd_buf.page_len == 0) |
| 443 | rtype = rpcrdma_areadch; | 458 | req->rl_rtype = rpcrdma_areadch; |
| 444 | else | 459 | else |
| 445 | rtype = rpcrdma_readch; | 460 | req->rl_rtype = rpcrdma_readch; |
| 446 | 461 | ||
| 447 | /* The following simplification is not true forever */ | 462 | /* The following simplification is not true forever */ |
| 448 | if (rtype != rpcrdma_noch && wtype == rpcrdma_replych) | 463 | if (req->rl_rtype != rpcrdma_noch && req->rl_wtype == rpcrdma_replych) |
| 449 | wtype = rpcrdma_noch; | 464 | req->rl_wtype = rpcrdma_noch; |
| 450 | if (rtype != rpcrdma_noch && wtype != rpcrdma_noch) { | 465 | if (req->rl_rtype != rpcrdma_noch && req->rl_wtype != rpcrdma_noch) { |
| 451 | dprintk("RPC: %s: cannot marshal multiple chunk lists\n", | 466 | dprintk("RPC: %s: cannot marshal multiple chunk lists\n", |
| 452 | __func__); | 467 | __func__); |
| 453 | return -EIO; | 468 | return -EIO; |
| @@ -461,7 +476,7 @@ rpcrdma_marshal_req(struct rpc_rqst *rqst) | |||
| 461 | * When padding is in use and applies to the transfer, insert | 476 | * When padding is in use and applies to the transfer, insert |
| 462 | * it and change the message type. | 477 | * it and change the message type. |
| 463 | */ | 478 | */ |
| 464 | if (rtype == rpcrdma_noch) { | 479 | if (req->rl_rtype == rpcrdma_noch) { |
| 465 | 480 | ||
| 466 | padlen = rpcrdma_inline_pullup(rqst, | 481 | padlen = rpcrdma_inline_pullup(rqst, |
| 467 | RPCRDMA_INLINE_PAD_VALUE(rqst)); | 482 | RPCRDMA_INLINE_PAD_VALUE(rqst)); |
| @@ -476,7 +491,7 @@ rpcrdma_marshal_req(struct rpc_rqst *rqst) | |||
| 476 | headerp->rm_body.rm_padded.rm_pempty[1] = xdr_zero; | 491 | headerp->rm_body.rm_padded.rm_pempty[1] = xdr_zero; |
| 477 | headerp->rm_body.rm_padded.rm_pempty[2] = xdr_zero; | 492 | headerp->rm_body.rm_padded.rm_pempty[2] = xdr_zero; |
| 478 | hdrlen += 2 * sizeof(u32); /* extra words in padhdr */ | 493 | hdrlen += 2 * sizeof(u32); /* extra words in padhdr */ |
| 479 | if (wtype != rpcrdma_noch) { | 494 | if (req->rl_wtype != rpcrdma_noch) { |
| 480 | dprintk("RPC: %s: invalid chunk list\n", | 495 | dprintk("RPC: %s: invalid chunk list\n", |
| 481 | __func__); | 496 | __func__); |
| 482 | return -EIO; | 497 | return -EIO; |
| @@ -497,30 +512,18 @@ rpcrdma_marshal_req(struct rpc_rqst *rqst) | |||
| 497 | * on receive. Therefore, we request a reply chunk | 512 | * on receive. Therefore, we request a reply chunk |
| 498 | * for non-writes wherever feasible and efficient. | 513 | * for non-writes wherever feasible and efficient. |
| 499 | */ | 514 | */ |
| 500 | if (wtype == rpcrdma_noch) | 515 | if (req->rl_wtype == rpcrdma_noch) |
| 501 | wtype = rpcrdma_replych; | 516 | req->rl_wtype = rpcrdma_replych; |
| 502 | } | 517 | } |
| 503 | } | 518 | } |
| 504 | 519 | ||
| 505 | /* | 520 | hdrlen = rpcrdma_marshal_chunks(rqst, hdrlen); |
| 506 | * Marshal chunks. This routine will return the header length | ||
| 507 | * consumed by marshaling. | ||
| 508 | */ | ||
| 509 | if (rtype != rpcrdma_noch) { | ||
| 510 | hdrlen = rpcrdma_create_chunks(rqst, | ||
| 511 | &rqst->rq_snd_buf, headerp, rtype); | ||
| 512 | wtype = rtype; /* simplify dprintk */ | ||
| 513 | |||
| 514 | } else if (wtype != rpcrdma_noch) { | ||
| 515 | hdrlen = rpcrdma_create_chunks(rqst, | ||
| 516 | &rqst->rq_rcv_buf, headerp, wtype); | ||
| 517 | } | ||
| 518 | if (hdrlen < 0) | 521 | if (hdrlen < 0) |
| 519 | return hdrlen; | 522 | return hdrlen; |
| 520 | 523 | ||
| 521 | dprintk("RPC: %s: %s: hdrlen %zd rpclen %zd padlen %zd" | 524 | dprintk("RPC: %s: %s: hdrlen %zd rpclen %zd padlen %zd" |
| 522 | " headerp 0x%p base 0x%p lkey 0x%x\n", | 525 | " headerp 0x%p base 0x%p lkey 0x%x\n", |
| 523 | __func__, transfertypes[wtype], hdrlen, rpclen, padlen, | 526 | __func__, transfertypes[req->rl_wtype], hdrlen, rpclen, padlen, |
| 524 | headerp, base, req->rl_iov.lkey); | 527 | headerp, base, req->rl_iov.lkey); |
| 525 | 528 | ||
| 526 | /* | 529 | /* |
diff --git a/net/sunrpc/xprtrdma/svc_rdma_recvfrom.c b/net/sunrpc/xprtrdma/svc_rdma_recvfrom.c index 8f92a61ee2df..e0110270d650 100644 --- a/net/sunrpc/xprtrdma/svc_rdma_recvfrom.c +++ b/net/sunrpc/xprtrdma/svc_rdma_recvfrom.c | |||
| @@ -43,6 +43,7 @@ | |||
| 43 | #include <linux/sunrpc/debug.h> | 43 | #include <linux/sunrpc/debug.h> |
| 44 | #include <linux/sunrpc/rpc_rdma.h> | 44 | #include <linux/sunrpc/rpc_rdma.h> |
| 45 | #include <linux/spinlock.h> | 45 | #include <linux/spinlock.h> |
| 46 | #include <linux/highmem.h> | ||
| 46 | #include <asm/unaligned.h> | 47 | #include <asm/unaligned.h> |
| 47 | #include <rdma/ib_verbs.h> | 48 | #include <rdma/ib_verbs.h> |
| 48 | #include <rdma/rdma_cm.h> | 49 | #include <rdma/rdma_cm.h> |
| @@ -435,6 +436,32 @@ static int rdma_read_chunks(struct svcxprt_rdma *xprt, | |||
| 435 | return ret; | 436 | return ret; |
| 436 | } | 437 | } |
| 437 | 438 | ||
| 439 | /* | ||
| 440 | * To avoid a separate RDMA READ just for a handful of zero bytes, | ||
| 441 | * RFC 5666 section 3.7 allows the client to omit the XDR zero pad | ||
| 442 | * in chunk lists. | ||
| 443 | */ | ||
| 444 | static void | ||
| 445 | rdma_fix_xdr_pad(struct xdr_buf *buf) | ||
| 446 | { | ||
| 447 | unsigned int page_len = buf->page_len; | ||
| 448 | unsigned int size = (XDR_QUADLEN(page_len) << 2) - page_len; | ||
| 449 | unsigned int offset, pg_no; | ||
| 450 | char *p; | ||
| 451 | |||
| 452 | if (size == 0) | ||
| 453 | return; | ||
| 454 | |||
| 455 | pg_no = page_len >> PAGE_SHIFT; | ||
| 456 | offset = page_len & ~PAGE_MASK; | ||
| 457 | p = page_address(buf->pages[pg_no]); | ||
| 458 | memset(p + offset, 0, size); | ||
| 459 | |||
| 460 | buf->page_len += size; | ||
| 461 | buf->buflen += size; | ||
| 462 | buf->len += size; | ||
| 463 | } | ||
| 464 | |||
| 438 | static int rdma_read_complete(struct svc_rqst *rqstp, | 465 | static int rdma_read_complete(struct svc_rqst *rqstp, |
| 439 | struct svc_rdma_op_ctxt *head) | 466 | struct svc_rdma_op_ctxt *head) |
| 440 | { | 467 | { |
| @@ -449,6 +476,7 @@ static int rdma_read_complete(struct svc_rqst *rqstp, | |||
| 449 | rqstp->rq_pages[page_no] = head->pages[page_no]; | 476 | rqstp->rq_pages[page_no] = head->pages[page_no]; |
| 450 | } | 477 | } |
| 451 | /* Point rq_arg.pages past header */ | 478 | /* Point rq_arg.pages past header */ |
| 479 | rdma_fix_xdr_pad(&head->arg); | ||
| 452 | rqstp->rq_arg.pages = &rqstp->rq_pages[head->hdr_count]; | 480 | rqstp->rq_arg.pages = &rqstp->rq_pages[head->hdr_count]; |
| 453 | rqstp->rq_arg.page_len = head->arg.page_len; | 481 | rqstp->rq_arg.page_len = head->arg.page_len; |
| 454 | rqstp->rq_arg.page_base = head->arg.page_base; | 482 | rqstp->rq_arg.page_base = head->arg.page_base; |
diff --git a/net/sunrpc/xprtrdma/svc_rdma_sendto.c b/net/sunrpc/xprtrdma/svc_rdma_sendto.c index 49fd21a5c215..9f1b50689c0f 100644 --- a/net/sunrpc/xprtrdma/svc_rdma_sendto.c +++ b/net/sunrpc/xprtrdma/svc_rdma_sendto.c | |||
| @@ -192,6 +192,8 @@ static int send_write(struct svcxprt_rdma *xprt, struct svc_rqst *rqstp, | |||
| 192 | xdr_sge_no++; | 192 | xdr_sge_no++; |
| 193 | BUG_ON(xdr_sge_no > vec->count); | 193 | BUG_ON(xdr_sge_no > vec->count); |
| 194 | bc -= sge_bytes; | 194 | bc -= sge_bytes; |
| 195 | if (sge_no == xprt->sc_max_sge) | ||
| 196 | break; | ||
| 195 | } | 197 | } |
| 196 | 198 | ||
| 197 | /* Prepare WRITE WR */ | 199 | /* Prepare WRITE WR */ |
| @@ -209,7 +211,7 @@ static int send_write(struct svcxprt_rdma *xprt, struct svc_rqst *rqstp, | |||
| 209 | atomic_inc(&rdma_stat_write); | 211 | atomic_inc(&rdma_stat_write); |
| 210 | if (svc_rdma_send(xprt, &write_wr)) | 212 | if (svc_rdma_send(xprt, &write_wr)) |
| 211 | goto err; | 213 | goto err; |
| 212 | return 0; | 214 | return write_len - bc; |
| 213 | err: | 215 | err: |
| 214 | svc_rdma_unmap_dma(ctxt); | 216 | svc_rdma_unmap_dma(ctxt); |
| 215 | svc_rdma_put_context(ctxt, 0); | 217 | svc_rdma_put_context(ctxt, 0); |
| @@ -225,7 +227,6 @@ static int send_write_chunks(struct svcxprt_rdma *xprt, | |||
| 225 | { | 227 | { |
| 226 | u32 xfer_len = rqstp->rq_res.page_len + rqstp->rq_res.tail[0].iov_len; | 228 | u32 xfer_len = rqstp->rq_res.page_len + rqstp->rq_res.tail[0].iov_len; |
| 227 | int write_len; | 229 | int write_len; |
| 228 | int max_write; | ||
| 229 | u32 xdr_off; | 230 | u32 xdr_off; |
| 230 | int chunk_off; | 231 | int chunk_off; |
| 231 | int chunk_no; | 232 | int chunk_no; |
| @@ -239,8 +240,6 @@ static int send_write_chunks(struct svcxprt_rdma *xprt, | |||
| 239 | res_ary = (struct rpcrdma_write_array *) | 240 | res_ary = (struct rpcrdma_write_array *) |
| 240 | &rdma_resp->rm_body.rm_chunks[1]; | 241 | &rdma_resp->rm_body.rm_chunks[1]; |
| 241 | 242 | ||
| 242 | max_write = xprt->sc_max_sge * PAGE_SIZE; | ||
| 243 | |||
| 244 | /* Write chunks start at the pagelist */ | 243 | /* Write chunks start at the pagelist */ |
| 245 | for (xdr_off = rqstp->rq_res.head[0].iov_len, chunk_no = 0; | 244 | for (xdr_off = rqstp->rq_res.head[0].iov_len, chunk_no = 0; |
| 246 | xfer_len && chunk_no < arg_ary->wc_nchunks; | 245 | xfer_len && chunk_no < arg_ary->wc_nchunks; |
| @@ -260,23 +259,21 @@ static int send_write_chunks(struct svcxprt_rdma *xprt, | |||
| 260 | write_len); | 259 | write_len); |
| 261 | chunk_off = 0; | 260 | chunk_off = 0; |
| 262 | while (write_len) { | 261 | while (write_len) { |
| 263 | int this_write; | ||
| 264 | this_write = min(write_len, max_write); | ||
| 265 | ret = send_write(xprt, rqstp, | 262 | ret = send_write(xprt, rqstp, |
| 266 | ntohl(arg_ch->rs_handle), | 263 | ntohl(arg_ch->rs_handle), |
| 267 | rs_offset + chunk_off, | 264 | rs_offset + chunk_off, |
| 268 | xdr_off, | 265 | xdr_off, |
| 269 | this_write, | 266 | write_len, |
| 270 | vec); | 267 | vec); |
| 271 | if (ret) { | 268 | if (ret <= 0) { |
| 272 | dprintk("svcrdma: RDMA_WRITE failed, ret=%d\n", | 269 | dprintk("svcrdma: RDMA_WRITE failed, ret=%d\n", |
| 273 | ret); | 270 | ret); |
| 274 | return -EIO; | 271 | return -EIO; |
| 275 | } | 272 | } |
| 276 | chunk_off += this_write; | 273 | chunk_off += ret; |
| 277 | xdr_off += this_write; | 274 | xdr_off += ret; |
| 278 | xfer_len -= this_write; | 275 | xfer_len -= ret; |
| 279 | write_len -= this_write; | 276 | write_len -= ret; |
| 280 | } | 277 | } |
| 281 | } | 278 | } |
| 282 | /* Update the req with the number of chunks actually used */ | 279 | /* Update the req with the number of chunks actually used */ |
| @@ -293,7 +290,6 @@ static int send_reply_chunks(struct svcxprt_rdma *xprt, | |||
| 293 | { | 290 | { |
| 294 | u32 xfer_len = rqstp->rq_res.len; | 291 | u32 xfer_len = rqstp->rq_res.len; |
| 295 | int write_len; | 292 | int write_len; |
| 296 | int max_write; | ||
| 297 | u32 xdr_off; | 293 | u32 xdr_off; |
| 298 | int chunk_no; | 294 | int chunk_no; |
| 299 | int chunk_off; | 295 | int chunk_off; |
| @@ -311,8 +307,6 @@ static int send_reply_chunks(struct svcxprt_rdma *xprt, | |||
| 311 | res_ary = (struct rpcrdma_write_array *) | 307 | res_ary = (struct rpcrdma_write_array *) |
| 312 | &rdma_resp->rm_body.rm_chunks[2]; | 308 | &rdma_resp->rm_body.rm_chunks[2]; |
| 313 | 309 | ||
| 314 | max_write = xprt->sc_max_sge * PAGE_SIZE; | ||
| 315 | |||
| 316 | /* xdr offset starts at RPC message */ | 310 | /* xdr offset starts at RPC message */ |
| 317 | nchunks = ntohl(arg_ary->wc_nchunks); | 311 | nchunks = ntohl(arg_ary->wc_nchunks); |
| 318 | for (xdr_off = 0, chunk_no = 0; | 312 | for (xdr_off = 0, chunk_no = 0; |
| @@ -330,24 +324,21 @@ static int send_reply_chunks(struct svcxprt_rdma *xprt, | |||
| 330 | write_len); | 324 | write_len); |
| 331 | chunk_off = 0; | 325 | chunk_off = 0; |
| 332 | while (write_len) { | 326 | while (write_len) { |
| 333 | int this_write; | ||
| 334 | |||
| 335 | this_write = min(write_len, max_write); | ||
| 336 | ret = send_write(xprt, rqstp, | 327 | ret = send_write(xprt, rqstp, |
| 337 | ntohl(ch->rs_handle), | 328 | ntohl(ch->rs_handle), |
| 338 | rs_offset + chunk_off, | 329 | rs_offset + chunk_off, |
| 339 | xdr_off, | 330 | xdr_off, |
| 340 | this_write, | 331 | write_len, |
| 341 | vec); | 332 | vec); |
| 342 | if (ret) { | 333 | if (ret <= 0) { |
| 343 | dprintk("svcrdma: RDMA_WRITE failed, ret=%d\n", | 334 | dprintk("svcrdma: RDMA_WRITE failed, ret=%d\n", |
| 344 | ret); | 335 | ret); |
| 345 | return -EIO; | 336 | return -EIO; |
| 346 | } | 337 | } |
| 347 | chunk_off += this_write; | 338 | chunk_off += ret; |
| 348 | xdr_off += this_write; | 339 | xdr_off += ret; |
| 349 | xfer_len -= this_write; | 340 | xfer_len -= ret; |
| 350 | write_len -= this_write; | 341 | write_len -= ret; |
| 351 | } | 342 | } |
| 352 | } | 343 | } |
| 353 | /* Update the req with the number of chunks actually used */ | 344 | /* Update the req with the number of chunks actually used */ |
diff --git a/net/sunrpc/xprtrdma/svc_rdma_transport.c b/net/sunrpc/xprtrdma/svc_rdma_transport.c index e7323fbbd348..374feb44afea 100644 --- a/net/sunrpc/xprtrdma/svc_rdma_transport.c +++ b/net/sunrpc/xprtrdma/svc_rdma_transport.c | |||
| @@ -92,6 +92,7 @@ struct svc_xprt_class svc_rdma_class = { | |||
| 92 | .xcl_owner = THIS_MODULE, | 92 | .xcl_owner = THIS_MODULE, |
| 93 | .xcl_ops = &svc_rdma_ops, | 93 | .xcl_ops = &svc_rdma_ops, |
| 94 | .xcl_max_payload = RPCSVC_MAXPAYLOAD_TCP, | 94 | .xcl_max_payload = RPCSVC_MAXPAYLOAD_TCP, |
| 95 | .xcl_ident = XPRT_TRANSPORT_RDMA, | ||
| 95 | }; | 96 | }; |
| 96 | 97 | ||
| 97 | struct svc_rdma_op_ctxt *svc_rdma_get_context(struct svcxprt_rdma *xprt) | 98 | struct svc_rdma_op_ctxt *svc_rdma_get_context(struct svcxprt_rdma *xprt) |
| @@ -942,23 +943,8 @@ static struct svc_xprt *svc_rdma_accept(struct svc_xprt *xprt) | |||
| 942 | 943 | ||
| 943 | ret = rdma_create_qp(newxprt->sc_cm_id, newxprt->sc_pd, &qp_attr); | 944 | ret = rdma_create_qp(newxprt->sc_cm_id, newxprt->sc_pd, &qp_attr); |
| 944 | if (ret) { | 945 | if (ret) { |
| 945 | /* | 946 | dprintk("svcrdma: failed to create QP, ret=%d\n", ret); |
| 946 | * XXX: This is a hack. We need a xx_request_qp interface | 947 | goto errout; |
| 947 | * that will adjust the qp_attr's with a best-effort | ||
| 948 | * number | ||
| 949 | */ | ||
| 950 | qp_attr.cap.max_send_sge -= 2; | ||
| 951 | qp_attr.cap.max_recv_sge -= 2; | ||
| 952 | ret = rdma_create_qp(newxprt->sc_cm_id, newxprt->sc_pd, | ||
| 953 | &qp_attr); | ||
| 954 | if (ret) { | ||
| 955 | dprintk("svcrdma: failed to create QP, ret=%d\n", ret); | ||
| 956 | goto errout; | ||
| 957 | } | ||
| 958 | newxprt->sc_max_sge = qp_attr.cap.max_send_sge; | ||
| 959 | newxprt->sc_max_sge = qp_attr.cap.max_recv_sge; | ||
| 960 | newxprt->sc_sq_depth = qp_attr.cap.max_send_wr; | ||
| 961 | newxprt->sc_max_requests = qp_attr.cap.max_recv_wr; | ||
| 962 | } | 948 | } |
| 963 | newxprt->sc_qp = newxprt->sc_cm_id->qp; | 949 | newxprt->sc_qp = newxprt->sc_cm_id->qp; |
| 964 | 950 | ||
diff --git a/net/sunrpc/xprtrdma/transport.c b/net/sunrpc/xprtrdma/transport.c index 66f91f0d071a..2faac4940563 100644 --- a/net/sunrpc/xprtrdma/transport.c +++ b/net/sunrpc/xprtrdma/transport.c | |||
| @@ -296,7 +296,6 @@ xprt_setup_rdma(struct xprt_create *args) | |||
| 296 | 296 | ||
| 297 | xprt->resvport = 0; /* privileged port not needed */ | 297 | xprt->resvport = 0; /* privileged port not needed */ |
| 298 | xprt->tsh_size = 0; /* RPC-RDMA handles framing */ | 298 | xprt->tsh_size = 0; /* RPC-RDMA handles framing */ |
| 299 | xprt->max_payload = RPCRDMA_MAX_DATA_SEGS * PAGE_SIZE; | ||
| 300 | xprt->ops = &xprt_rdma_procs; | 299 | xprt->ops = &xprt_rdma_procs; |
| 301 | 300 | ||
| 302 | /* | 301 | /* |
| @@ -382,6 +381,9 @@ xprt_setup_rdma(struct xprt_create *args) | |||
| 382 | new_ep->rep_xprt = xprt; | 381 | new_ep->rep_xprt = xprt; |
| 383 | 382 | ||
| 384 | xprt_rdma_format_addresses(xprt); | 383 | xprt_rdma_format_addresses(xprt); |
| 384 | xprt->max_payload = rpcrdma_max_payload(new_xprt); | ||
| 385 | dprintk("RPC: %s: transport data payload maximum: %zu bytes\n", | ||
| 386 | __func__, xprt->max_payload); | ||
| 385 | 387 | ||
| 386 | if (!try_module_get(THIS_MODULE)) | 388 | if (!try_module_get(THIS_MODULE)) |
| 387 | goto out4; | 389 | goto out4; |
| @@ -412,7 +414,7 @@ xprt_rdma_close(struct rpc_xprt *xprt) | |||
| 412 | if (r_xprt->rx_ep.rep_connected > 0) | 414 | if (r_xprt->rx_ep.rep_connected > 0) |
| 413 | xprt->reestablish_timeout = 0; | 415 | xprt->reestablish_timeout = 0; |
| 414 | xprt_disconnect_done(xprt); | 416 | xprt_disconnect_done(xprt); |
| 415 | (void) rpcrdma_ep_disconnect(&r_xprt->rx_ep, &r_xprt->rx_ia); | 417 | rpcrdma_ep_disconnect(&r_xprt->rx_ep, &r_xprt->rx_ia); |
| 416 | } | 418 | } |
| 417 | 419 | ||
| 418 | static void | 420 | static void |
| @@ -595,13 +597,14 @@ xprt_rdma_send_request(struct rpc_task *task) | |||
| 595 | struct rpc_xprt *xprt = rqst->rq_xprt; | 597 | struct rpc_xprt *xprt = rqst->rq_xprt; |
| 596 | struct rpcrdma_req *req = rpcr_to_rdmar(rqst); | 598 | struct rpcrdma_req *req = rpcr_to_rdmar(rqst); |
| 597 | struct rpcrdma_xprt *r_xprt = rpcx_to_rdmax(xprt); | 599 | struct rpcrdma_xprt *r_xprt = rpcx_to_rdmax(xprt); |
| 598 | int rc; | 600 | int rc = 0; |
| 599 | 601 | ||
| 600 | if (req->rl_niovs == 0) { | 602 | if (req->rl_niovs == 0) |
| 601 | rc = rpcrdma_marshal_req(rqst); | 603 | rc = rpcrdma_marshal_req(rqst); |
| 602 | if (rc < 0) | 604 | else if (r_xprt->rx_ia.ri_memreg_strategy == RPCRDMA_FRMR) |
| 603 | goto failed_marshal; | 605 | rc = rpcrdma_marshal_chunks(rqst, 0); |
| 604 | } | 606 | if (rc < 0) |
| 607 | goto failed_marshal; | ||
| 605 | 608 | ||
| 606 | if (req->rl_reply == NULL) /* e.g. reconnection */ | 609 | if (req->rl_reply == NULL) /* e.g. reconnection */ |
| 607 | rpcrdma_recv_buffer_get(req); | 610 | rpcrdma_recv_buffer_get(req); |
diff --git a/net/sunrpc/xprtrdma/verbs.c b/net/sunrpc/xprtrdma/verbs.c index 13dbd1c389ff..61c41298b4ea 100644 --- a/net/sunrpc/xprtrdma/verbs.c +++ b/net/sunrpc/xprtrdma/verbs.c | |||
| @@ -61,6 +61,8 @@ | |||
| 61 | # define RPCDBG_FACILITY RPCDBG_TRANS | 61 | # define RPCDBG_FACILITY RPCDBG_TRANS |
| 62 | #endif | 62 | #endif |
| 63 | 63 | ||
| 64 | static void rpcrdma_reset_frmrs(struct rpcrdma_ia *); | ||
| 65 | |||
| 64 | /* | 66 | /* |
| 65 | * internal functions | 67 | * internal functions |
| 66 | */ | 68 | */ |
| @@ -103,17 +105,6 @@ rpcrdma_run_tasklet(unsigned long data) | |||
| 103 | 105 | ||
| 104 | static DECLARE_TASKLET(rpcrdma_tasklet_g, rpcrdma_run_tasklet, 0UL); | 106 | static DECLARE_TASKLET(rpcrdma_tasklet_g, rpcrdma_run_tasklet, 0UL); |
| 105 | 107 | ||
| 106 | static inline void | ||
| 107 | rpcrdma_schedule_tasklet(struct rpcrdma_rep *rep) | ||
| 108 | { | ||
| 109 | unsigned long flags; | ||
| 110 | |||
| 111 | spin_lock_irqsave(&rpcrdma_tk_lock_g, flags); | ||
| 112 | list_add_tail(&rep->rr_list, &rpcrdma_tasklets_g); | ||
| 113 | spin_unlock_irqrestore(&rpcrdma_tk_lock_g, flags); | ||
| 114 | tasklet_schedule(&rpcrdma_tasklet_g); | ||
| 115 | } | ||
| 116 | |||
| 117 | static void | 108 | static void |
| 118 | rpcrdma_qp_async_error_upcall(struct ib_event *event, void *context) | 109 | rpcrdma_qp_async_error_upcall(struct ib_event *event, void *context) |
| 119 | { | 110 | { |
| @@ -153,12 +144,7 @@ rpcrdma_sendcq_process_wc(struct ib_wc *wc) | |||
| 153 | if (wc->wr_id == 0ULL) | 144 | if (wc->wr_id == 0ULL) |
| 154 | return; | 145 | return; |
| 155 | if (wc->status != IB_WC_SUCCESS) | 146 | if (wc->status != IB_WC_SUCCESS) |
| 156 | return; | 147 | frmr->r.frmr.fr_state = FRMR_IS_STALE; |
| 157 | |||
| 158 | if (wc->opcode == IB_WC_FAST_REG_MR) | ||
| 159 | frmr->r.frmr.state = FRMR_IS_VALID; | ||
| 160 | else if (wc->opcode == IB_WC_LOCAL_INV) | ||
| 161 | frmr->r.frmr.state = FRMR_IS_INVALID; | ||
| 162 | } | 148 | } |
| 163 | 149 | ||
| 164 | static int | 150 | static int |
| @@ -217,7 +203,7 @@ rpcrdma_sendcq_upcall(struct ib_cq *cq, void *cq_context) | |||
| 217 | } | 203 | } |
| 218 | 204 | ||
| 219 | static void | 205 | static void |
| 220 | rpcrdma_recvcq_process_wc(struct ib_wc *wc) | 206 | rpcrdma_recvcq_process_wc(struct ib_wc *wc, struct list_head *sched_list) |
| 221 | { | 207 | { |
| 222 | struct rpcrdma_rep *rep = | 208 | struct rpcrdma_rep *rep = |
| 223 | (struct rpcrdma_rep *)(unsigned long)wc->wr_id; | 209 | (struct rpcrdma_rep *)(unsigned long)wc->wr_id; |
| @@ -248,28 +234,38 @@ rpcrdma_recvcq_process_wc(struct ib_wc *wc) | |||
| 248 | } | 234 | } |
| 249 | 235 | ||
| 250 | out_schedule: | 236 | out_schedule: |
| 251 | rpcrdma_schedule_tasklet(rep); | 237 | list_add_tail(&rep->rr_list, sched_list); |
| 252 | } | 238 | } |
| 253 | 239 | ||
| 254 | static int | 240 | static int |
| 255 | rpcrdma_recvcq_poll(struct ib_cq *cq, struct rpcrdma_ep *ep) | 241 | rpcrdma_recvcq_poll(struct ib_cq *cq, struct rpcrdma_ep *ep) |
| 256 | { | 242 | { |
| 243 | struct list_head sched_list; | ||
| 257 | struct ib_wc *wcs; | 244 | struct ib_wc *wcs; |
| 258 | int budget, count, rc; | 245 | int budget, count, rc; |
| 246 | unsigned long flags; | ||
| 259 | 247 | ||
| 248 | INIT_LIST_HEAD(&sched_list); | ||
| 260 | budget = RPCRDMA_WC_BUDGET / RPCRDMA_POLLSIZE; | 249 | budget = RPCRDMA_WC_BUDGET / RPCRDMA_POLLSIZE; |
| 261 | do { | 250 | do { |
| 262 | wcs = ep->rep_recv_wcs; | 251 | wcs = ep->rep_recv_wcs; |
| 263 | 252 | ||
| 264 | rc = ib_poll_cq(cq, RPCRDMA_POLLSIZE, wcs); | 253 | rc = ib_poll_cq(cq, RPCRDMA_POLLSIZE, wcs); |
| 265 | if (rc <= 0) | 254 | if (rc <= 0) |
| 266 | return rc; | 255 | goto out_schedule; |
| 267 | 256 | ||
| 268 | count = rc; | 257 | count = rc; |
| 269 | while (count-- > 0) | 258 | while (count-- > 0) |
| 270 | rpcrdma_recvcq_process_wc(wcs++); | 259 | rpcrdma_recvcq_process_wc(wcs++, &sched_list); |
| 271 | } while (rc == RPCRDMA_POLLSIZE && --budget); | 260 | } while (rc == RPCRDMA_POLLSIZE && --budget); |
| 272 | return 0; | 261 | rc = 0; |
| 262 | |||
| 263 | out_schedule: | ||
| 264 | spin_lock_irqsave(&rpcrdma_tk_lock_g, flags); | ||
| 265 | list_splice_tail(&sched_list, &rpcrdma_tasklets_g); | ||
| 266 | spin_unlock_irqrestore(&rpcrdma_tk_lock_g, flags); | ||
| 267 | tasklet_schedule(&rpcrdma_tasklet_g); | ||
| 268 | return rc; | ||
| 273 | } | 269 | } |
| 274 | 270 | ||
| 275 | /* | 271 | /* |
| @@ -310,6 +306,13 @@ rpcrdma_recvcq_upcall(struct ib_cq *cq, void *cq_context) | |||
| 310 | rpcrdma_recvcq_poll(cq, ep); | 306 | rpcrdma_recvcq_poll(cq, ep); |
| 311 | } | 307 | } |
| 312 | 308 | ||
| 309 | static void | ||
| 310 | rpcrdma_flush_cqs(struct rpcrdma_ep *ep) | ||
| 311 | { | ||
| 312 | rpcrdma_recvcq_upcall(ep->rep_attr.recv_cq, ep); | ||
| 313 | rpcrdma_sendcq_upcall(ep->rep_attr.send_cq, ep); | ||
| 314 | } | ||
| 315 | |||
| 313 | #ifdef RPC_DEBUG | 316 | #ifdef RPC_DEBUG |
| 314 | static const char * const conn[] = { | 317 | static const char * const conn[] = { |
| 315 | "address resolved", | 318 | "address resolved", |
| @@ -323,8 +326,16 @@ static const char * const conn[] = { | |||
| 323 | "rejected", | 326 | "rejected", |
| 324 | "established", | 327 | "established", |
| 325 | "disconnected", | 328 | "disconnected", |
| 326 | "device removal" | 329 | "device removal", |
| 330 | "multicast join", | ||
| 331 | "multicast error", | ||
| 332 | "address change", | ||
| 333 | "timewait exit", | ||
| 327 | }; | 334 | }; |
| 335 | |||
| 336 | #define CONNECTION_MSG(status) \ | ||
| 337 | ((status) < ARRAY_SIZE(conn) ? \ | ||
| 338 | conn[(status)] : "unrecognized connection error") | ||
| 328 | #endif | 339 | #endif |
| 329 | 340 | ||
| 330 | static int | 341 | static int |
| @@ -382,23 +393,18 @@ rpcrdma_conn_upcall(struct rdma_cm_id *id, struct rdma_cm_event *event) | |||
| 382 | case RDMA_CM_EVENT_DEVICE_REMOVAL: | 393 | case RDMA_CM_EVENT_DEVICE_REMOVAL: |
| 383 | connstate = -ENODEV; | 394 | connstate = -ENODEV; |
| 384 | connected: | 395 | connected: |
| 385 | dprintk("RPC: %s: %s: %pI4:%u (ep 0x%p event 0x%x)\n", | ||
| 386 | __func__, | ||
| 387 | (event->event <= 11) ? conn[event->event] : | ||
| 388 | "unknown connection error", | ||
| 389 | &addr->sin_addr.s_addr, | ||
| 390 | ntohs(addr->sin_port), | ||
| 391 | ep, event->event); | ||
| 392 | atomic_set(&rpcx_to_rdmax(ep->rep_xprt)->rx_buf.rb_credits, 1); | 396 | atomic_set(&rpcx_to_rdmax(ep->rep_xprt)->rx_buf.rb_credits, 1); |
| 393 | dprintk("RPC: %s: %sconnected\n", | 397 | dprintk("RPC: %s: %sconnected\n", |
| 394 | __func__, connstate > 0 ? "" : "dis"); | 398 | __func__, connstate > 0 ? "" : "dis"); |
| 395 | ep->rep_connected = connstate; | 399 | ep->rep_connected = connstate; |
| 396 | ep->rep_func(ep); | 400 | ep->rep_func(ep); |
| 397 | wake_up_all(&ep->rep_connect_wait); | 401 | wake_up_all(&ep->rep_connect_wait); |
| 398 | break; | 402 | /*FALLTHROUGH*/ |
| 399 | default: | 403 | default: |
| 400 | dprintk("RPC: %s: unexpected CM event %d\n", | 404 | dprintk("RPC: %s: %pI4:%u (ep 0x%p): %s\n", |
| 401 | __func__, event->event); | 405 | __func__, &addr->sin_addr.s_addr, |
| 406 | ntohs(addr->sin_port), ep, | ||
| 407 | CONNECTION_MSG(event->event)); | ||
| 402 | break; | 408 | break; |
| 403 | } | 409 | } |
| 404 | 410 | ||
| @@ -558,12 +564,7 @@ rpcrdma_ia_open(struct rpcrdma_xprt *xprt, struct sockaddr *addr, int memreg) | |||
| 558 | if (!ia->ri_id->device->alloc_fmr) { | 564 | if (!ia->ri_id->device->alloc_fmr) { |
| 559 | dprintk("RPC: %s: MTHCAFMR registration " | 565 | dprintk("RPC: %s: MTHCAFMR registration " |
| 560 | "not supported by HCA\n", __func__); | 566 | "not supported by HCA\n", __func__); |
| 561 | #if RPCRDMA_PERSISTENT_REGISTRATION | ||
| 562 | memreg = RPCRDMA_ALLPHYSICAL; | 567 | memreg = RPCRDMA_ALLPHYSICAL; |
| 563 | #else | ||
| 564 | rc = -ENOMEM; | ||
| 565 | goto out2; | ||
| 566 | #endif | ||
| 567 | } | 568 | } |
| 568 | } | 569 | } |
| 569 | 570 | ||
| @@ -578,20 +579,16 @@ rpcrdma_ia_open(struct rpcrdma_xprt *xprt, struct sockaddr *addr, int memreg) | |||
| 578 | switch (memreg) { | 579 | switch (memreg) { |
| 579 | case RPCRDMA_FRMR: | 580 | case RPCRDMA_FRMR: |
| 580 | break; | 581 | break; |
| 581 | #if RPCRDMA_PERSISTENT_REGISTRATION | ||
| 582 | case RPCRDMA_ALLPHYSICAL: | 582 | case RPCRDMA_ALLPHYSICAL: |
| 583 | mem_priv = IB_ACCESS_LOCAL_WRITE | | 583 | mem_priv = IB_ACCESS_LOCAL_WRITE | |
| 584 | IB_ACCESS_REMOTE_WRITE | | 584 | IB_ACCESS_REMOTE_WRITE | |
| 585 | IB_ACCESS_REMOTE_READ; | 585 | IB_ACCESS_REMOTE_READ; |
| 586 | goto register_setup; | 586 | goto register_setup; |
| 587 | #endif | ||
| 588 | case RPCRDMA_MTHCAFMR: | 587 | case RPCRDMA_MTHCAFMR: |
| 589 | if (ia->ri_have_dma_lkey) | 588 | if (ia->ri_have_dma_lkey) |
| 590 | break; | 589 | break; |
| 591 | mem_priv = IB_ACCESS_LOCAL_WRITE; | 590 | mem_priv = IB_ACCESS_LOCAL_WRITE; |
| 592 | #if RPCRDMA_PERSISTENT_REGISTRATION | ||
| 593 | register_setup: | 591 | register_setup: |
| 594 | #endif | ||
| 595 | ia->ri_bind_mem = ib_get_dma_mr(ia->ri_pd, mem_priv); | 592 | ia->ri_bind_mem = ib_get_dma_mr(ia->ri_pd, mem_priv); |
| 596 | if (IS_ERR(ia->ri_bind_mem)) { | 593 | if (IS_ERR(ia->ri_bind_mem)) { |
| 597 | printk(KERN_ALERT "%s: ib_get_dma_mr for " | 594 | printk(KERN_ALERT "%s: ib_get_dma_mr for " |
| @@ -613,6 +610,7 @@ rpcrdma_ia_open(struct rpcrdma_xprt *xprt, struct sockaddr *addr, int memreg) | |||
| 613 | /* Else will do memory reg/dereg for each chunk */ | 610 | /* Else will do memory reg/dereg for each chunk */ |
| 614 | ia->ri_memreg_strategy = memreg; | 611 | ia->ri_memreg_strategy = memreg; |
| 615 | 612 | ||
| 613 | rwlock_init(&ia->ri_qplock); | ||
| 616 | return 0; | 614 | return 0; |
| 617 | out2: | 615 | out2: |
| 618 | rdma_destroy_id(ia->ri_id); | 616 | rdma_destroy_id(ia->ri_id); |
| @@ -826,10 +824,7 @@ rpcrdma_ep_destroy(struct rpcrdma_ep *ep, struct rpcrdma_ia *ia) | |||
| 826 | cancel_delayed_work_sync(&ep->rep_connect_worker); | 824 | cancel_delayed_work_sync(&ep->rep_connect_worker); |
| 827 | 825 | ||
| 828 | if (ia->ri_id->qp) { | 826 | if (ia->ri_id->qp) { |
| 829 | rc = rpcrdma_ep_disconnect(ep, ia); | 827 | rpcrdma_ep_disconnect(ep, ia); |
| 830 | if (rc) | ||
| 831 | dprintk("RPC: %s: rpcrdma_ep_disconnect" | ||
| 832 | " returned %i\n", __func__, rc); | ||
| 833 | rdma_destroy_qp(ia->ri_id); | 828 | rdma_destroy_qp(ia->ri_id); |
| 834 | ia->ri_id->qp = NULL; | 829 | ia->ri_id->qp = NULL; |
| 835 | } | 830 | } |
| @@ -859,7 +854,7 @@ rpcrdma_ep_destroy(struct rpcrdma_ep *ep, struct rpcrdma_ia *ia) | |||
| 859 | int | 854 | int |
| 860 | rpcrdma_ep_connect(struct rpcrdma_ep *ep, struct rpcrdma_ia *ia) | 855 | rpcrdma_ep_connect(struct rpcrdma_ep *ep, struct rpcrdma_ia *ia) |
| 861 | { | 856 | { |
| 862 | struct rdma_cm_id *id; | 857 | struct rdma_cm_id *id, *old; |
| 863 | int rc = 0; | 858 | int rc = 0; |
| 864 | int retry_count = 0; | 859 | int retry_count = 0; |
| 865 | 860 | ||
| @@ -867,13 +862,12 @@ rpcrdma_ep_connect(struct rpcrdma_ep *ep, struct rpcrdma_ia *ia) | |||
| 867 | struct rpcrdma_xprt *xprt; | 862 | struct rpcrdma_xprt *xprt; |
| 868 | retry: | 863 | retry: |
| 869 | dprintk("RPC: %s: reconnecting...\n", __func__); | 864 | dprintk("RPC: %s: reconnecting...\n", __func__); |
| 870 | rc = rpcrdma_ep_disconnect(ep, ia); | ||
| 871 | if (rc && rc != -ENOTCONN) | ||
| 872 | dprintk("RPC: %s: rpcrdma_ep_disconnect" | ||
| 873 | " status %i\n", __func__, rc); | ||
| 874 | 865 | ||
| 875 | rpcrdma_clean_cq(ep->rep_attr.recv_cq); | 866 | rpcrdma_ep_disconnect(ep, ia); |
| 876 | rpcrdma_clean_cq(ep->rep_attr.send_cq); | 867 | rpcrdma_flush_cqs(ep); |
| 868 | |||
| 869 | if (ia->ri_memreg_strategy == RPCRDMA_FRMR) | ||
| 870 | rpcrdma_reset_frmrs(ia); | ||
| 877 | 871 | ||
| 878 | xprt = container_of(ia, struct rpcrdma_xprt, rx_ia); | 872 | xprt = container_of(ia, struct rpcrdma_xprt, rx_ia); |
| 879 | id = rpcrdma_create_id(xprt, ia, | 873 | id = rpcrdma_create_id(xprt, ia, |
| @@ -905,9 +899,14 @@ retry: | |||
| 905 | rc = -ENETUNREACH; | 899 | rc = -ENETUNREACH; |
| 906 | goto out; | 900 | goto out; |
| 907 | } | 901 | } |
| 908 | rdma_destroy_qp(ia->ri_id); | 902 | |
| 909 | rdma_destroy_id(ia->ri_id); | 903 | write_lock(&ia->ri_qplock); |
| 904 | old = ia->ri_id; | ||
| 910 | ia->ri_id = id; | 905 | ia->ri_id = id; |
| 906 | write_unlock(&ia->ri_qplock); | ||
| 907 | |||
| 908 | rdma_destroy_qp(old); | ||
| 909 | rdma_destroy_id(old); | ||
| 911 | } else { | 910 | } else { |
| 912 | dprintk("RPC: %s: connecting...\n", __func__); | 911 | dprintk("RPC: %s: connecting...\n", __func__); |
| 913 | rc = rdma_create_qp(ia->ri_id, ia->ri_pd, &ep->rep_attr); | 912 | rc = rdma_create_qp(ia->ri_id, ia->ri_pd, &ep->rep_attr); |
| @@ -974,13 +973,12 @@ out: | |||
| 974 | * This call is not reentrant, and must not be made in parallel | 973 | * This call is not reentrant, and must not be made in parallel |
| 975 | * on the same endpoint. | 974 | * on the same endpoint. |
| 976 | */ | 975 | */ |
| 977 | int | 976 | void |
| 978 | rpcrdma_ep_disconnect(struct rpcrdma_ep *ep, struct rpcrdma_ia *ia) | 977 | rpcrdma_ep_disconnect(struct rpcrdma_ep *ep, struct rpcrdma_ia *ia) |
| 979 | { | 978 | { |
| 980 | int rc; | 979 | int rc; |
| 981 | 980 | ||
| 982 | rpcrdma_clean_cq(ep->rep_attr.recv_cq); | 981 | rpcrdma_flush_cqs(ep); |
| 983 | rpcrdma_clean_cq(ep->rep_attr.send_cq); | ||
| 984 | rc = rdma_disconnect(ia->ri_id); | 982 | rc = rdma_disconnect(ia->ri_id); |
| 985 | if (!rc) { | 983 | if (!rc) { |
| 986 | /* returns without wait if not connected */ | 984 | /* returns without wait if not connected */ |
| @@ -992,12 +990,93 @@ rpcrdma_ep_disconnect(struct rpcrdma_ep *ep, struct rpcrdma_ia *ia) | |||
| 992 | dprintk("RPC: %s: rdma_disconnect %i\n", __func__, rc); | 990 | dprintk("RPC: %s: rdma_disconnect %i\n", __func__, rc); |
| 993 | ep->rep_connected = rc; | 991 | ep->rep_connected = rc; |
| 994 | } | 992 | } |
| 993 | } | ||
| 994 | |||
| 995 | static int | ||
| 996 | rpcrdma_init_fmrs(struct rpcrdma_ia *ia, struct rpcrdma_buffer *buf) | ||
| 997 | { | ||
| 998 | int mr_access_flags = IB_ACCESS_REMOTE_WRITE | IB_ACCESS_REMOTE_READ; | ||
| 999 | struct ib_fmr_attr fmr_attr = { | ||
| 1000 | .max_pages = RPCRDMA_MAX_DATA_SEGS, | ||
| 1001 | .max_maps = 1, | ||
| 1002 | .page_shift = PAGE_SHIFT | ||
| 1003 | }; | ||
| 1004 | struct rpcrdma_mw *r; | ||
| 1005 | int i, rc; | ||
| 1006 | |||
| 1007 | i = (buf->rb_max_requests + 1) * RPCRDMA_MAX_SEGS; | ||
| 1008 | dprintk("RPC: %s: initalizing %d FMRs\n", __func__, i); | ||
| 1009 | |||
| 1010 | while (i--) { | ||
| 1011 | r = kzalloc(sizeof(*r), GFP_KERNEL); | ||
| 1012 | if (r == NULL) | ||
| 1013 | return -ENOMEM; | ||
| 1014 | |||
| 1015 | r->r.fmr = ib_alloc_fmr(ia->ri_pd, mr_access_flags, &fmr_attr); | ||
| 1016 | if (IS_ERR(r->r.fmr)) { | ||
| 1017 | rc = PTR_ERR(r->r.fmr); | ||
| 1018 | dprintk("RPC: %s: ib_alloc_fmr failed %i\n", | ||
| 1019 | __func__, rc); | ||
| 1020 | goto out_free; | ||
| 1021 | } | ||
| 1022 | |||
| 1023 | list_add(&r->mw_list, &buf->rb_mws); | ||
| 1024 | list_add(&r->mw_all, &buf->rb_all); | ||
| 1025 | } | ||
| 1026 | return 0; | ||
| 1027 | |||
| 1028 | out_free: | ||
| 1029 | kfree(r); | ||
| 1030 | return rc; | ||
| 1031 | } | ||
| 1032 | |||
| 1033 | static int | ||
| 1034 | rpcrdma_init_frmrs(struct rpcrdma_ia *ia, struct rpcrdma_buffer *buf) | ||
| 1035 | { | ||
| 1036 | struct rpcrdma_frmr *f; | ||
| 1037 | struct rpcrdma_mw *r; | ||
| 1038 | int i, rc; | ||
| 1039 | |||
| 1040 | i = (buf->rb_max_requests + 1) * RPCRDMA_MAX_SEGS; | ||
| 1041 | dprintk("RPC: %s: initalizing %d FRMRs\n", __func__, i); | ||
| 1042 | |||
| 1043 | while (i--) { | ||
| 1044 | r = kzalloc(sizeof(*r), GFP_KERNEL); | ||
| 1045 | if (r == NULL) | ||
| 1046 | return -ENOMEM; | ||
| 1047 | f = &r->r.frmr; | ||
| 1048 | |||
| 1049 | f->fr_mr = ib_alloc_fast_reg_mr(ia->ri_pd, | ||
| 1050 | ia->ri_max_frmr_depth); | ||
| 1051 | if (IS_ERR(f->fr_mr)) { | ||
| 1052 | rc = PTR_ERR(f->fr_mr); | ||
| 1053 | dprintk("RPC: %s: ib_alloc_fast_reg_mr " | ||
| 1054 | "failed %i\n", __func__, rc); | ||
| 1055 | goto out_free; | ||
| 1056 | } | ||
| 1057 | |||
| 1058 | f->fr_pgl = ib_alloc_fast_reg_page_list(ia->ri_id->device, | ||
| 1059 | ia->ri_max_frmr_depth); | ||
| 1060 | if (IS_ERR(f->fr_pgl)) { | ||
| 1061 | rc = PTR_ERR(f->fr_pgl); | ||
| 1062 | dprintk("RPC: %s: ib_alloc_fast_reg_page_list " | ||
| 1063 | "failed %i\n", __func__, rc); | ||
| 1064 | |||
| 1065 | ib_dereg_mr(f->fr_mr); | ||
| 1066 | goto out_free; | ||
| 1067 | } | ||
| 1068 | |||
| 1069 | list_add(&r->mw_list, &buf->rb_mws); | ||
| 1070 | list_add(&r->mw_all, &buf->rb_all); | ||
| 1071 | } | ||
| 1072 | |||
| 1073 | return 0; | ||
| 1074 | |||
| 1075 | out_free: | ||
| 1076 | kfree(r); | ||
| 995 | return rc; | 1077 | return rc; |
| 996 | } | 1078 | } |
| 997 | 1079 | ||
| 998 | /* | ||
| 999 | * Initialize buffer memory | ||
| 1000 | */ | ||
| 1001 | int | 1080 | int |
| 1002 | rpcrdma_buffer_create(struct rpcrdma_buffer *buf, struct rpcrdma_ep *ep, | 1081 | rpcrdma_buffer_create(struct rpcrdma_buffer *buf, struct rpcrdma_ep *ep, |
| 1003 | struct rpcrdma_ia *ia, struct rpcrdma_create_data_internal *cdata) | 1082 | struct rpcrdma_ia *ia, struct rpcrdma_create_data_internal *cdata) |
| @@ -1005,7 +1084,6 @@ rpcrdma_buffer_create(struct rpcrdma_buffer *buf, struct rpcrdma_ep *ep, | |||
| 1005 | char *p; | 1084 | char *p; |
| 1006 | size_t len, rlen, wlen; | 1085 | size_t len, rlen, wlen; |
| 1007 | int i, rc; | 1086 | int i, rc; |
| 1008 | struct rpcrdma_mw *r; | ||
| 1009 | 1087 | ||
| 1010 | buf->rb_max_requests = cdata->max_requests; | 1088 | buf->rb_max_requests = cdata->max_requests; |
| 1011 | spin_lock_init(&buf->rb_lock); | 1089 | spin_lock_init(&buf->rb_lock); |
| @@ -1016,28 +1094,12 @@ rpcrdma_buffer_create(struct rpcrdma_buffer *buf, struct rpcrdma_ep *ep, | |||
| 1016 | * 2. arrays of struct rpcrdma_req to fill in pointers | 1094 | * 2. arrays of struct rpcrdma_req to fill in pointers |
| 1017 | * 3. array of struct rpcrdma_rep for replies | 1095 | * 3. array of struct rpcrdma_rep for replies |
| 1018 | * 4. padding, if any | 1096 | * 4. padding, if any |
| 1019 | * 5. mw's, fmr's or frmr's, if any | ||
| 1020 | * Send/recv buffers in req/rep need to be registered | 1097 | * Send/recv buffers in req/rep need to be registered |
| 1021 | */ | 1098 | */ |
| 1022 | |||
| 1023 | len = buf->rb_max_requests * | 1099 | len = buf->rb_max_requests * |
| 1024 | (sizeof(struct rpcrdma_req *) + sizeof(struct rpcrdma_rep *)); | 1100 | (sizeof(struct rpcrdma_req *) + sizeof(struct rpcrdma_rep *)); |
| 1025 | len += cdata->padding; | 1101 | len += cdata->padding; |
| 1026 | switch (ia->ri_memreg_strategy) { | ||
| 1027 | case RPCRDMA_FRMR: | ||
| 1028 | len += buf->rb_max_requests * RPCRDMA_MAX_SEGS * | ||
| 1029 | sizeof(struct rpcrdma_mw); | ||
| 1030 | break; | ||
| 1031 | case RPCRDMA_MTHCAFMR: | ||
| 1032 | /* TBD we are perhaps overallocating here */ | ||
| 1033 | len += (buf->rb_max_requests + 1) * RPCRDMA_MAX_SEGS * | ||
| 1034 | sizeof(struct rpcrdma_mw); | ||
| 1035 | break; | ||
| 1036 | default: | ||
| 1037 | break; | ||
| 1038 | } | ||
| 1039 | 1102 | ||
| 1040 | /* allocate 1, 4 and 5 in one shot */ | ||
| 1041 | p = kzalloc(len, GFP_KERNEL); | 1103 | p = kzalloc(len, GFP_KERNEL); |
| 1042 | if (p == NULL) { | 1104 | if (p == NULL) { |
| 1043 | dprintk("RPC: %s: req_t/rep_t/pad kzalloc(%zd) failed\n", | 1105 | dprintk("RPC: %s: req_t/rep_t/pad kzalloc(%zd) failed\n", |
| @@ -1064,51 +1126,17 @@ rpcrdma_buffer_create(struct rpcrdma_buffer *buf, struct rpcrdma_ep *ep, | |||
| 1064 | p += cdata->padding; | 1126 | p += cdata->padding; |
| 1065 | 1127 | ||
| 1066 | INIT_LIST_HEAD(&buf->rb_mws); | 1128 | INIT_LIST_HEAD(&buf->rb_mws); |
| 1067 | r = (struct rpcrdma_mw *)p; | 1129 | INIT_LIST_HEAD(&buf->rb_all); |
| 1068 | switch (ia->ri_memreg_strategy) { | 1130 | switch (ia->ri_memreg_strategy) { |
| 1069 | case RPCRDMA_FRMR: | 1131 | case RPCRDMA_FRMR: |
| 1070 | for (i = buf->rb_max_requests * RPCRDMA_MAX_SEGS; i; i--) { | 1132 | rc = rpcrdma_init_frmrs(ia, buf); |
| 1071 | r->r.frmr.fr_mr = ib_alloc_fast_reg_mr(ia->ri_pd, | 1133 | if (rc) |
| 1072 | ia->ri_max_frmr_depth); | 1134 | goto out; |
| 1073 | if (IS_ERR(r->r.frmr.fr_mr)) { | ||
| 1074 | rc = PTR_ERR(r->r.frmr.fr_mr); | ||
| 1075 | dprintk("RPC: %s: ib_alloc_fast_reg_mr" | ||
| 1076 | " failed %i\n", __func__, rc); | ||
| 1077 | goto out; | ||
| 1078 | } | ||
| 1079 | r->r.frmr.fr_pgl = ib_alloc_fast_reg_page_list( | ||
| 1080 | ia->ri_id->device, | ||
| 1081 | ia->ri_max_frmr_depth); | ||
| 1082 | if (IS_ERR(r->r.frmr.fr_pgl)) { | ||
| 1083 | rc = PTR_ERR(r->r.frmr.fr_pgl); | ||
| 1084 | dprintk("RPC: %s: " | ||
| 1085 | "ib_alloc_fast_reg_page_list " | ||
| 1086 | "failed %i\n", __func__, rc); | ||
| 1087 | |||
| 1088 | ib_dereg_mr(r->r.frmr.fr_mr); | ||
| 1089 | goto out; | ||
| 1090 | } | ||
| 1091 | list_add(&r->mw_list, &buf->rb_mws); | ||
| 1092 | ++r; | ||
| 1093 | } | ||
| 1094 | break; | 1135 | break; |
| 1095 | case RPCRDMA_MTHCAFMR: | 1136 | case RPCRDMA_MTHCAFMR: |
| 1096 | /* TBD we are perhaps overallocating here */ | 1137 | rc = rpcrdma_init_fmrs(ia, buf); |
| 1097 | for (i = (buf->rb_max_requests+1) * RPCRDMA_MAX_SEGS; i; i--) { | 1138 | if (rc) |
| 1098 | static struct ib_fmr_attr fa = | 1139 | goto out; |
| 1099 | { RPCRDMA_MAX_DATA_SEGS, 1, PAGE_SHIFT }; | ||
| 1100 | r->r.fmr = ib_alloc_fmr(ia->ri_pd, | ||
| 1101 | IB_ACCESS_REMOTE_WRITE | IB_ACCESS_REMOTE_READ, | ||
| 1102 | &fa); | ||
| 1103 | if (IS_ERR(r->r.fmr)) { | ||
| 1104 | rc = PTR_ERR(r->r.fmr); | ||
| 1105 | dprintk("RPC: %s: ib_alloc_fmr" | ||
| 1106 | " failed %i\n", __func__, rc); | ||
| 1107 | goto out; | ||
| 1108 | } | ||
| 1109 | list_add(&r->mw_list, &buf->rb_mws); | ||
| 1110 | ++r; | ||
| 1111 | } | ||
| 1112 | break; | 1140 | break; |
| 1113 | default: | 1141 | default: |
| 1114 | break; | 1142 | break; |
| @@ -1176,24 +1204,57 @@ out: | |||
| 1176 | return rc; | 1204 | return rc; |
| 1177 | } | 1205 | } |
| 1178 | 1206 | ||
| 1179 | /* | 1207 | static void |
| 1180 | * Unregister and destroy buffer memory. Need to deal with | 1208 | rpcrdma_destroy_fmrs(struct rpcrdma_buffer *buf) |
| 1181 | * partial initialization, so it's callable from failed create. | 1209 | { |
| 1182 | * Must be called before destroying endpoint, as registrations | 1210 | struct rpcrdma_mw *r; |
| 1183 | * reference it. | 1211 | int rc; |
| 1184 | */ | 1212 | |
| 1213 | while (!list_empty(&buf->rb_all)) { | ||
| 1214 | r = list_entry(buf->rb_all.next, struct rpcrdma_mw, mw_all); | ||
| 1215 | list_del(&r->mw_all); | ||
| 1216 | list_del(&r->mw_list); | ||
| 1217 | |||
| 1218 | rc = ib_dealloc_fmr(r->r.fmr); | ||
| 1219 | if (rc) | ||
| 1220 | dprintk("RPC: %s: ib_dealloc_fmr failed %i\n", | ||
| 1221 | __func__, rc); | ||
| 1222 | |||
| 1223 | kfree(r); | ||
| 1224 | } | ||
| 1225 | } | ||
| 1226 | |||
| 1227 | static void | ||
| 1228 | rpcrdma_destroy_frmrs(struct rpcrdma_buffer *buf) | ||
| 1229 | { | ||
| 1230 | struct rpcrdma_mw *r; | ||
| 1231 | int rc; | ||
| 1232 | |||
| 1233 | while (!list_empty(&buf->rb_all)) { | ||
| 1234 | r = list_entry(buf->rb_all.next, struct rpcrdma_mw, mw_all); | ||
| 1235 | list_del(&r->mw_all); | ||
| 1236 | list_del(&r->mw_list); | ||
| 1237 | |||
| 1238 | rc = ib_dereg_mr(r->r.frmr.fr_mr); | ||
| 1239 | if (rc) | ||
| 1240 | dprintk("RPC: %s: ib_dereg_mr failed %i\n", | ||
| 1241 | __func__, rc); | ||
| 1242 | ib_free_fast_reg_page_list(r->r.frmr.fr_pgl); | ||
| 1243 | |||
| 1244 | kfree(r); | ||
| 1245 | } | ||
| 1246 | } | ||
| 1247 | |||
| 1185 | void | 1248 | void |
| 1186 | rpcrdma_buffer_destroy(struct rpcrdma_buffer *buf) | 1249 | rpcrdma_buffer_destroy(struct rpcrdma_buffer *buf) |
| 1187 | { | 1250 | { |
| 1188 | int rc, i; | ||
| 1189 | struct rpcrdma_ia *ia = rdmab_to_ia(buf); | 1251 | struct rpcrdma_ia *ia = rdmab_to_ia(buf); |
| 1190 | struct rpcrdma_mw *r; | 1252 | int i; |
| 1191 | 1253 | ||
| 1192 | /* clean up in reverse order from create | 1254 | /* clean up in reverse order from create |
| 1193 | * 1. recv mr memory (mr free, then kfree) | 1255 | * 1. recv mr memory (mr free, then kfree) |
| 1194 | * 2. send mr memory (mr free, then kfree) | 1256 | * 2. send mr memory (mr free, then kfree) |
| 1195 | * 3. padding (if any) [moved to rpcrdma_ep_destroy] | 1257 | * 3. MWs |
| 1196 | * 4. arrays | ||
| 1197 | */ | 1258 | */ |
| 1198 | dprintk("RPC: %s: entering\n", __func__); | 1259 | dprintk("RPC: %s: entering\n", __func__); |
| 1199 | 1260 | ||
| @@ -1212,34 +1273,217 @@ rpcrdma_buffer_destroy(struct rpcrdma_buffer *buf) | |||
| 1212 | } | 1273 | } |
| 1213 | } | 1274 | } |
| 1214 | 1275 | ||
| 1276 | switch (ia->ri_memreg_strategy) { | ||
| 1277 | case RPCRDMA_FRMR: | ||
| 1278 | rpcrdma_destroy_frmrs(buf); | ||
| 1279 | break; | ||
| 1280 | case RPCRDMA_MTHCAFMR: | ||
| 1281 | rpcrdma_destroy_fmrs(buf); | ||
| 1282 | break; | ||
| 1283 | default: | ||
| 1284 | break; | ||
| 1285 | } | ||
| 1286 | |||
| 1287 | kfree(buf->rb_pool); | ||
| 1288 | } | ||
| 1289 | |||
| 1290 | /* After a disconnect, a flushed FAST_REG_MR can leave an FRMR in | ||
| 1291 | * an unusable state. Find FRMRs in this state and dereg / reg | ||
| 1292 | * each. FRMRs that are VALID and attached to an rpcrdma_req are | ||
| 1293 | * also torn down. | ||
| 1294 | * | ||
| 1295 | * This gives all in-use FRMRs a fresh rkey and leaves them INVALID. | ||
| 1296 | * | ||
| 1297 | * This is invoked only in the transport connect worker in order | ||
| 1298 | * to serialize with rpcrdma_register_frmr_external(). | ||
| 1299 | */ | ||
| 1300 | static void | ||
| 1301 | rpcrdma_reset_frmrs(struct rpcrdma_ia *ia) | ||
| 1302 | { | ||
| 1303 | struct rpcrdma_xprt *r_xprt = | ||
| 1304 | container_of(ia, struct rpcrdma_xprt, rx_ia); | ||
| 1305 | struct rpcrdma_buffer *buf = &r_xprt->rx_buf; | ||
| 1306 | struct list_head *pos; | ||
| 1307 | struct rpcrdma_mw *r; | ||
| 1308 | int rc; | ||
| 1309 | |||
| 1310 | list_for_each(pos, &buf->rb_all) { | ||
| 1311 | r = list_entry(pos, struct rpcrdma_mw, mw_all); | ||
| 1312 | |||
| 1313 | if (r->r.frmr.fr_state == FRMR_IS_INVALID) | ||
| 1314 | continue; | ||
| 1315 | |||
| 1316 | rc = ib_dereg_mr(r->r.frmr.fr_mr); | ||
| 1317 | if (rc) | ||
| 1318 | dprintk("RPC: %s: ib_dereg_mr failed %i\n", | ||
| 1319 | __func__, rc); | ||
| 1320 | ib_free_fast_reg_page_list(r->r.frmr.fr_pgl); | ||
| 1321 | |||
| 1322 | r->r.frmr.fr_mr = ib_alloc_fast_reg_mr(ia->ri_pd, | ||
| 1323 | ia->ri_max_frmr_depth); | ||
| 1324 | if (IS_ERR(r->r.frmr.fr_mr)) { | ||
| 1325 | rc = PTR_ERR(r->r.frmr.fr_mr); | ||
| 1326 | dprintk("RPC: %s: ib_alloc_fast_reg_mr" | ||
| 1327 | " failed %i\n", __func__, rc); | ||
| 1328 | continue; | ||
| 1329 | } | ||
| 1330 | r->r.frmr.fr_pgl = ib_alloc_fast_reg_page_list( | ||
| 1331 | ia->ri_id->device, | ||
| 1332 | ia->ri_max_frmr_depth); | ||
| 1333 | if (IS_ERR(r->r.frmr.fr_pgl)) { | ||
| 1334 | rc = PTR_ERR(r->r.frmr.fr_pgl); | ||
| 1335 | dprintk("RPC: %s: " | ||
| 1336 | "ib_alloc_fast_reg_page_list " | ||
| 1337 | "failed %i\n", __func__, rc); | ||
| 1338 | |||
| 1339 | ib_dereg_mr(r->r.frmr.fr_mr); | ||
| 1340 | continue; | ||
| 1341 | } | ||
| 1342 | r->r.frmr.fr_state = FRMR_IS_INVALID; | ||
| 1343 | } | ||
| 1344 | } | ||
| 1345 | |||
| 1346 | /* "*mw" can be NULL when rpcrdma_buffer_get_mrs() fails, leaving | ||
| 1347 | * some req segments uninitialized. | ||
| 1348 | */ | ||
| 1349 | static void | ||
| 1350 | rpcrdma_buffer_put_mr(struct rpcrdma_mw **mw, struct rpcrdma_buffer *buf) | ||
| 1351 | { | ||
| 1352 | if (*mw) { | ||
| 1353 | list_add_tail(&(*mw)->mw_list, &buf->rb_mws); | ||
| 1354 | *mw = NULL; | ||
| 1355 | } | ||
| 1356 | } | ||
| 1357 | |||
| 1358 | /* Cycle mw's back in reverse order, and "spin" them. | ||
| 1359 | * This delays and scrambles reuse as much as possible. | ||
| 1360 | */ | ||
| 1361 | static void | ||
| 1362 | rpcrdma_buffer_put_mrs(struct rpcrdma_req *req, struct rpcrdma_buffer *buf) | ||
| 1363 | { | ||
| 1364 | struct rpcrdma_mr_seg *seg = req->rl_segments; | ||
| 1365 | struct rpcrdma_mr_seg *seg1 = seg; | ||
| 1366 | int i; | ||
| 1367 | |||
| 1368 | for (i = 1, seg++; i < RPCRDMA_MAX_SEGS; seg++, i++) | ||
| 1369 | rpcrdma_buffer_put_mr(&seg->mr_chunk.rl_mw, buf); | ||
| 1370 | rpcrdma_buffer_put_mr(&seg1->mr_chunk.rl_mw, buf); | ||
| 1371 | } | ||
| 1372 | |||
| 1373 | static void | ||
| 1374 | rpcrdma_buffer_put_sendbuf(struct rpcrdma_req *req, struct rpcrdma_buffer *buf) | ||
| 1375 | { | ||
| 1376 | buf->rb_send_bufs[--buf->rb_send_index] = req; | ||
| 1377 | req->rl_niovs = 0; | ||
| 1378 | if (req->rl_reply) { | ||
| 1379 | buf->rb_recv_bufs[--buf->rb_recv_index] = req->rl_reply; | ||
| 1380 | req->rl_reply->rr_func = NULL; | ||
| 1381 | req->rl_reply = NULL; | ||
| 1382 | } | ||
| 1383 | } | ||
| 1384 | |||
| 1385 | /* rpcrdma_unmap_one() was already done by rpcrdma_deregister_frmr_external(). | ||
| 1386 | * Redo only the ib_post_send(). | ||
| 1387 | */ | ||
| 1388 | static void | ||
| 1389 | rpcrdma_retry_local_inv(struct rpcrdma_mw *r, struct rpcrdma_ia *ia) | ||
| 1390 | { | ||
| 1391 | struct rpcrdma_xprt *r_xprt = | ||
| 1392 | container_of(ia, struct rpcrdma_xprt, rx_ia); | ||
| 1393 | struct ib_send_wr invalidate_wr, *bad_wr; | ||
| 1394 | int rc; | ||
| 1395 | |||
| 1396 | dprintk("RPC: %s: FRMR %p is stale\n", __func__, r); | ||
| 1397 | |||
| 1398 | /* When this FRMR is re-inserted into rb_mws, it is no longer stale */ | ||
| 1399 | r->r.frmr.fr_state = FRMR_IS_INVALID; | ||
| 1400 | |||
| 1401 | memset(&invalidate_wr, 0, sizeof(invalidate_wr)); | ||
| 1402 | invalidate_wr.wr_id = (unsigned long)(void *)r; | ||
| 1403 | invalidate_wr.opcode = IB_WR_LOCAL_INV; | ||
| 1404 | invalidate_wr.ex.invalidate_rkey = r->r.frmr.fr_mr->rkey; | ||
| 1405 | DECR_CQCOUNT(&r_xprt->rx_ep); | ||
| 1406 | |||
| 1407 | dprintk("RPC: %s: frmr %p invalidating rkey %08x\n", | ||
| 1408 | __func__, r, r->r.frmr.fr_mr->rkey); | ||
| 1409 | |||
| 1410 | read_lock(&ia->ri_qplock); | ||
| 1411 | rc = ib_post_send(ia->ri_id->qp, &invalidate_wr, &bad_wr); | ||
| 1412 | read_unlock(&ia->ri_qplock); | ||
| 1413 | if (rc) { | ||
| 1414 | /* Force rpcrdma_buffer_get() to retry */ | ||
| 1415 | r->r.frmr.fr_state = FRMR_IS_STALE; | ||
| 1416 | dprintk("RPC: %s: ib_post_send failed, %i\n", | ||
| 1417 | __func__, rc); | ||
| 1418 | } | ||
| 1419 | } | ||
| 1420 | |||
| 1421 | static void | ||
| 1422 | rpcrdma_retry_flushed_linv(struct list_head *stale, | ||
| 1423 | struct rpcrdma_buffer *buf) | ||
| 1424 | { | ||
| 1425 | struct rpcrdma_ia *ia = rdmab_to_ia(buf); | ||
| 1426 | struct list_head *pos; | ||
| 1427 | struct rpcrdma_mw *r; | ||
| 1428 | unsigned long flags; | ||
| 1429 | |||
| 1430 | list_for_each(pos, stale) { | ||
| 1431 | r = list_entry(pos, struct rpcrdma_mw, mw_list); | ||
| 1432 | rpcrdma_retry_local_inv(r, ia); | ||
| 1433 | } | ||
| 1434 | |||
| 1435 | spin_lock_irqsave(&buf->rb_lock, flags); | ||
| 1436 | list_splice_tail(stale, &buf->rb_mws); | ||
| 1437 | spin_unlock_irqrestore(&buf->rb_lock, flags); | ||
| 1438 | } | ||
| 1439 | |||
| 1440 | static struct rpcrdma_req * | ||
| 1441 | rpcrdma_buffer_get_frmrs(struct rpcrdma_req *req, struct rpcrdma_buffer *buf, | ||
| 1442 | struct list_head *stale) | ||
| 1443 | { | ||
| 1444 | struct rpcrdma_mw *r; | ||
| 1445 | int i; | ||
| 1446 | |||
| 1447 | i = RPCRDMA_MAX_SEGS - 1; | ||
| 1215 | while (!list_empty(&buf->rb_mws)) { | 1448 | while (!list_empty(&buf->rb_mws)) { |
| 1216 | r = list_entry(buf->rb_mws.next, | 1449 | r = list_entry(buf->rb_mws.next, |
| 1217 | struct rpcrdma_mw, mw_list); | 1450 | struct rpcrdma_mw, mw_list); |
| 1218 | list_del(&r->mw_list); | 1451 | list_del(&r->mw_list); |
| 1219 | switch (ia->ri_memreg_strategy) { | 1452 | if (r->r.frmr.fr_state == FRMR_IS_STALE) { |
| 1220 | case RPCRDMA_FRMR: | 1453 | list_add(&r->mw_list, stale); |
| 1221 | rc = ib_dereg_mr(r->r.frmr.fr_mr); | 1454 | continue; |
| 1222 | if (rc) | ||
| 1223 | dprintk("RPC: %s:" | ||
| 1224 | " ib_dereg_mr" | ||
| 1225 | " failed %i\n", | ||
| 1226 | __func__, rc); | ||
| 1227 | ib_free_fast_reg_page_list(r->r.frmr.fr_pgl); | ||
| 1228 | break; | ||
| 1229 | case RPCRDMA_MTHCAFMR: | ||
| 1230 | rc = ib_dealloc_fmr(r->r.fmr); | ||
| 1231 | if (rc) | ||
| 1232 | dprintk("RPC: %s:" | ||
| 1233 | " ib_dealloc_fmr" | ||
| 1234 | " failed %i\n", | ||
| 1235 | __func__, rc); | ||
| 1236 | break; | ||
| 1237 | default: | ||
| 1238 | break; | ||
| 1239 | } | 1455 | } |
| 1456 | req->rl_segments[i].mr_chunk.rl_mw = r; | ||
| 1457 | if (unlikely(i-- == 0)) | ||
| 1458 | return req; /* Success */ | ||
| 1240 | } | 1459 | } |
| 1241 | 1460 | ||
| 1242 | kfree(buf->rb_pool); | 1461 | /* Not enough entries on rb_mws for this req */ |
| 1462 | rpcrdma_buffer_put_sendbuf(req, buf); | ||
| 1463 | rpcrdma_buffer_put_mrs(req, buf); | ||
| 1464 | return NULL; | ||
| 1465 | } | ||
| 1466 | |||
| 1467 | static struct rpcrdma_req * | ||
| 1468 | rpcrdma_buffer_get_fmrs(struct rpcrdma_req *req, struct rpcrdma_buffer *buf) | ||
| 1469 | { | ||
| 1470 | struct rpcrdma_mw *r; | ||
| 1471 | int i; | ||
| 1472 | |||
| 1473 | i = RPCRDMA_MAX_SEGS - 1; | ||
| 1474 | while (!list_empty(&buf->rb_mws)) { | ||
| 1475 | r = list_entry(buf->rb_mws.next, | ||
| 1476 | struct rpcrdma_mw, mw_list); | ||
| 1477 | list_del(&r->mw_list); | ||
| 1478 | req->rl_segments[i].mr_chunk.rl_mw = r; | ||
| 1479 | if (unlikely(i-- == 0)) | ||
| 1480 | return req; /* Success */ | ||
| 1481 | } | ||
| 1482 | |||
| 1483 | /* Not enough entries on rb_mws for this req */ | ||
| 1484 | rpcrdma_buffer_put_sendbuf(req, buf); | ||
| 1485 | rpcrdma_buffer_put_mrs(req, buf); | ||
| 1486 | return NULL; | ||
| 1243 | } | 1487 | } |
| 1244 | 1488 | ||
| 1245 | /* | 1489 | /* |
| @@ -1254,10 +1498,10 @@ rpcrdma_buffer_destroy(struct rpcrdma_buffer *buf) | |||
| 1254 | struct rpcrdma_req * | 1498 | struct rpcrdma_req * |
| 1255 | rpcrdma_buffer_get(struct rpcrdma_buffer *buffers) | 1499 | rpcrdma_buffer_get(struct rpcrdma_buffer *buffers) |
| 1256 | { | 1500 | { |
| 1501 | struct rpcrdma_ia *ia = rdmab_to_ia(buffers); | ||
| 1502 | struct list_head stale; | ||
| 1257 | struct rpcrdma_req *req; | 1503 | struct rpcrdma_req *req; |
| 1258 | unsigned long flags; | 1504 | unsigned long flags; |
| 1259 | int i; | ||
| 1260 | struct rpcrdma_mw *r; | ||
| 1261 | 1505 | ||
| 1262 | spin_lock_irqsave(&buffers->rb_lock, flags); | 1506 | spin_lock_irqsave(&buffers->rb_lock, flags); |
| 1263 | if (buffers->rb_send_index == buffers->rb_max_requests) { | 1507 | if (buffers->rb_send_index == buffers->rb_max_requests) { |
| @@ -1277,16 +1521,21 @@ rpcrdma_buffer_get(struct rpcrdma_buffer *buffers) | |||
| 1277 | buffers->rb_recv_bufs[buffers->rb_recv_index++] = NULL; | 1521 | buffers->rb_recv_bufs[buffers->rb_recv_index++] = NULL; |
| 1278 | } | 1522 | } |
| 1279 | buffers->rb_send_bufs[buffers->rb_send_index++] = NULL; | 1523 | buffers->rb_send_bufs[buffers->rb_send_index++] = NULL; |
| 1280 | if (!list_empty(&buffers->rb_mws)) { | 1524 | |
| 1281 | i = RPCRDMA_MAX_SEGS - 1; | 1525 | INIT_LIST_HEAD(&stale); |
| 1282 | do { | 1526 | switch (ia->ri_memreg_strategy) { |
| 1283 | r = list_entry(buffers->rb_mws.next, | 1527 | case RPCRDMA_FRMR: |
| 1284 | struct rpcrdma_mw, mw_list); | 1528 | req = rpcrdma_buffer_get_frmrs(req, buffers, &stale); |
| 1285 | list_del(&r->mw_list); | 1529 | break; |
| 1286 | req->rl_segments[i].mr_chunk.rl_mw = r; | 1530 | case RPCRDMA_MTHCAFMR: |
| 1287 | } while (--i >= 0); | 1531 | req = rpcrdma_buffer_get_fmrs(req, buffers); |
| 1532 | break; | ||
| 1533 | default: | ||
| 1534 | break; | ||
| 1288 | } | 1535 | } |
| 1289 | spin_unlock_irqrestore(&buffers->rb_lock, flags); | 1536 | spin_unlock_irqrestore(&buffers->rb_lock, flags); |
| 1537 | if (!list_empty(&stale)) | ||
| 1538 | rpcrdma_retry_flushed_linv(&stale, buffers); | ||
| 1290 | return req; | 1539 | return req; |
| 1291 | } | 1540 | } |
| 1292 | 1541 | ||
| @@ -1299,34 +1548,14 @@ rpcrdma_buffer_put(struct rpcrdma_req *req) | |||
| 1299 | { | 1548 | { |
| 1300 | struct rpcrdma_buffer *buffers = req->rl_buffer; | 1549 | struct rpcrdma_buffer *buffers = req->rl_buffer; |
| 1301 | struct rpcrdma_ia *ia = rdmab_to_ia(buffers); | 1550 | struct rpcrdma_ia *ia = rdmab_to_ia(buffers); |
| 1302 | int i; | ||
| 1303 | unsigned long flags; | 1551 | unsigned long flags; |
| 1304 | 1552 | ||
| 1305 | spin_lock_irqsave(&buffers->rb_lock, flags); | 1553 | spin_lock_irqsave(&buffers->rb_lock, flags); |
| 1306 | buffers->rb_send_bufs[--buffers->rb_send_index] = req; | 1554 | rpcrdma_buffer_put_sendbuf(req, buffers); |
| 1307 | req->rl_niovs = 0; | ||
| 1308 | if (req->rl_reply) { | ||
| 1309 | buffers->rb_recv_bufs[--buffers->rb_recv_index] = req->rl_reply; | ||
| 1310 | req->rl_reply->rr_func = NULL; | ||
| 1311 | req->rl_reply = NULL; | ||
| 1312 | } | ||
| 1313 | switch (ia->ri_memreg_strategy) { | 1555 | switch (ia->ri_memreg_strategy) { |
| 1314 | case RPCRDMA_FRMR: | 1556 | case RPCRDMA_FRMR: |
| 1315 | case RPCRDMA_MTHCAFMR: | 1557 | case RPCRDMA_MTHCAFMR: |
| 1316 | /* | 1558 | rpcrdma_buffer_put_mrs(req, buffers); |
| 1317 | * Cycle mw's back in reverse order, and "spin" them. | ||
| 1318 | * This delays and scrambles reuse as much as possible. | ||
| 1319 | */ | ||
| 1320 | i = 1; | ||
| 1321 | do { | ||
| 1322 | struct rpcrdma_mw **mw; | ||
| 1323 | mw = &req->rl_segments[i].mr_chunk.rl_mw; | ||
| 1324 | list_add_tail(&(*mw)->mw_list, &buffers->rb_mws); | ||
| 1325 | *mw = NULL; | ||
| 1326 | } while (++i < RPCRDMA_MAX_SEGS); | ||
| 1327 | list_add_tail(&req->rl_segments[0].mr_chunk.rl_mw->mw_list, | ||
| 1328 | &buffers->rb_mws); | ||
| 1329 | req->rl_segments[0].mr_chunk.rl_mw = NULL; | ||
| 1330 | break; | 1559 | break; |
| 1331 | default: | 1560 | default: |
| 1332 | break; | 1561 | break; |
| @@ -1388,6 +1617,9 @@ rpcrdma_register_internal(struct rpcrdma_ia *ia, void *va, int len, | |||
| 1388 | */ | 1617 | */ |
| 1389 | iov->addr = ib_dma_map_single(ia->ri_id->device, | 1618 | iov->addr = ib_dma_map_single(ia->ri_id->device, |
| 1390 | va, len, DMA_BIDIRECTIONAL); | 1619 | va, len, DMA_BIDIRECTIONAL); |
| 1620 | if (ib_dma_mapping_error(ia->ri_id->device, iov->addr)) | ||
| 1621 | return -ENOMEM; | ||
| 1622 | |||
| 1391 | iov->length = len; | 1623 | iov->length = len; |
| 1392 | 1624 | ||
| 1393 | if (ia->ri_have_dma_lkey) { | 1625 | if (ia->ri_have_dma_lkey) { |
| @@ -1483,8 +1715,10 @@ rpcrdma_register_frmr_external(struct rpcrdma_mr_seg *seg, | |||
| 1483 | struct rpcrdma_xprt *r_xprt) | 1715 | struct rpcrdma_xprt *r_xprt) |
| 1484 | { | 1716 | { |
| 1485 | struct rpcrdma_mr_seg *seg1 = seg; | 1717 | struct rpcrdma_mr_seg *seg1 = seg; |
| 1486 | struct ib_send_wr invalidate_wr, frmr_wr, *bad_wr, *post_wr; | 1718 | struct rpcrdma_mw *mw = seg1->mr_chunk.rl_mw; |
| 1487 | 1719 | struct rpcrdma_frmr *frmr = &mw->r.frmr; | |
| 1720 | struct ib_mr *mr = frmr->fr_mr; | ||
| 1721 | struct ib_send_wr fastreg_wr, *bad_wr; | ||
| 1488 | u8 key; | 1722 | u8 key; |
| 1489 | int len, pageoff; | 1723 | int len, pageoff; |
| 1490 | int i, rc; | 1724 | int i, rc; |
| @@ -1502,8 +1736,7 @@ rpcrdma_register_frmr_external(struct rpcrdma_mr_seg *seg, | |||
| 1502 | rpcrdma_map_one(ia, seg, writing); | 1736 | rpcrdma_map_one(ia, seg, writing); |
| 1503 | pa = seg->mr_dma; | 1737 | pa = seg->mr_dma; |
| 1504 | for (seg_len = seg->mr_len; seg_len > 0; seg_len -= PAGE_SIZE) { | 1738 | for (seg_len = seg->mr_len; seg_len > 0; seg_len -= PAGE_SIZE) { |
| 1505 | seg1->mr_chunk.rl_mw->r.frmr.fr_pgl-> | 1739 | frmr->fr_pgl->page_list[page_no++] = pa; |
| 1506 | page_list[page_no++] = pa; | ||
| 1507 | pa += PAGE_SIZE; | 1740 | pa += PAGE_SIZE; |
| 1508 | } | 1741 | } |
| 1509 | len += seg->mr_len; | 1742 | len += seg->mr_len; |
| @@ -1515,65 +1748,51 @@ rpcrdma_register_frmr_external(struct rpcrdma_mr_seg *seg, | |||
| 1515 | break; | 1748 | break; |
| 1516 | } | 1749 | } |
| 1517 | dprintk("RPC: %s: Using frmr %p to map %d segments\n", | 1750 | dprintk("RPC: %s: Using frmr %p to map %d segments\n", |
| 1518 | __func__, seg1->mr_chunk.rl_mw, i); | 1751 | __func__, mw, i); |
| 1519 | 1752 | ||
| 1520 | if (unlikely(seg1->mr_chunk.rl_mw->r.frmr.state == FRMR_IS_VALID)) { | 1753 | frmr->fr_state = FRMR_IS_VALID; |
| 1521 | dprintk("RPC: %s: frmr %x left valid, posting invalidate.\n", | 1754 | |
| 1522 | __func__, | 1755 | memset(&fastreg_wr, 0, sizeof(fastreg_wr)); |
| 1523 | seg1->mr_chunk.rl_mw->r.frmr.fr_mr->rkey); | 1756 | fastreg_wr.wr_id = (unsigned long)(void *)mw; |
| 1524 | /* Invalidate before using. */ | 1757 | fastreg_wr.opcode = IB_WR_FAST_REG_MR; |
| 1525 | memset(&invalidate_wr, 0, sizeof invalidate_wr); | 1758 | fastreg_wr.wr.fast_reg.iova_start = seg1->mr_dma; |
| 1526 | invalidate_wr.wr_id = (unsigned long)(void *)seg1->mr_chunk.rl_mw; | 1759 | fastreg_wr.wr.fast_reg.page_list = frmr->fr_pgl; |
| 1527 | invalidate_wr.next = &frmr_wr; | 1760 | fastreg_wr.wr.fast_reg.page_list_len = page_no; |
| 1528 | invalidate_wr.opcode = IB_WR_LOCAL_INV; | 1761 | fastreg_wr.wr.fast_reg.page_shift = PAGE_SHIFT; |
| 1529 | invalidate_wr.send_flags = IB_SEND_SIGNALED; | 1762 | fastreg_wr.wr.fast_reg.length = page_no << PAGE_SHIFT; |
| 1530 | invalidate_wr.ex.invalidate_rkey = | 1763 | if (fastreg_wr.wr.fast_reg.length < len) { |
| 1531 | seg1->mr_chunk.rl_mw->r.frmr.fr_mr->rkey; | 1764 | rc = -EIO; |
| 1532 | DECR_CQCOUNT(&r_xprt->rx_ep); | 1765 | goto out_err; |
| 1533 | post_wr = &invalidate_wr; | ||
| 1534 | } else | ||
| 1535 | post_wr = &frmr_wr; | ||
| 1536 | |||
| 1537 | /* Prepare FRMR WR */ | ||
| 1538 | memset(&frmr_wr, 0, sizeof frmr_wr); | ||
| 1539 | frmr_wr.wr_id = (unsigned long)(void *)seg1->mr_chunk.rl_mw; | ||
| 1540 | frmr_wr.opcode = IB_WR_FAST_REG_MR; | ||
| 1541 | frmr_wr.send_flags = IB_SEND_SIGNALED; | ||
| 1542 | frmr_wr.wr.fast_reg.iova_start = seg1->mr_dma; | ||
| 1543 | frmr_wr.wr.fast_reg.page_list = seg1->mr_chunk.rl_mw->r.frmr.fr_pgl; | ||
| 1544 | frmr_wr.wr.fast_reg.page_list_len = page_no; | ||
| 1545 | frmr_wr.wr.fast_reg.page_shift = PAGE_SHIFT; | ||
| 1546 | frmr_wr.wr.fast_reg.length = page_no << PAGE_SHIFT; | ||
| 1547 | if (frmr_wr.wr.fast_reg.length < len) { | ||
| 1548 | while (seg1->mr_nsegs--) | ||
| 1549 | rpcrdma_unmap_one(ia, seg++); | ||
| 1550 | return -EIO; | ||
| 1551 | } | 1766 | } |
| 1552 | 1767 | ||
| 1553 | /* Bump the key */ | 1768 | /* Bump the key */ |
| 1554 | key = (u8)(seg1->mr_chunk.rl_mw->r.frmr.fr_mr->rkey & 0x000000FF); | 1769 | key = (u8)(mr->rkey & 0x000000FF); |
| 1555 | ib_update_fast_reg_key(seg1->mr_chunk.rl_mw->r.frmr.fr_mr, ++key); | 1770 | ib_update_fast_reg_key(mr, ++key); |
| 1556 | 1771 | ||
| 1557 | frmr_wr.wr.fast_reg.access_flags = (writing ? | 1772 | fastreg_wr.wr.fast_reg.access_flags = (writing ? |
| 1558 | IB_ACCESS_REMOTE_WRITE | IB_ACCESS_LOCAL_WRITE : | 1773 | IB_ACCESS_REMOTE_WRITE | IB_ACCESS_LOCAL_WRITE : |
| 1559 | IB_ACCESS_REMOTE_READ); | 1774 | IB_ACCESS_REMOTE_READ); |
| 1560 | frmr_wr.wr.fast_reg.rkey = seg1->mr_chunk.rl_mw->r.frmr.fr_mr->rkey; | 1775 | fastreg_wr.wr.fast_reg.rkey = mr->rkey; |
| 1561 | DECR_CQCOUNT(&r_xprt->rx_ep); | 1776 | DECR_CQCOUNT(&r_xprt->rx_ep); |
| 1562 | 1777 | ||
| 1563 | rc = ib_post_send(ia->ri_id->qp, post_wr, &bad_wr); | 1778 | rc = ib_post_send(ia->ri_id->qp, &fastreg_wr, &bad_wr); |
| 1564 | |||
| 1565 | if (rc) { | 1779 | if (rc) { |
| 1566 | dprintk("RPC: %s: failed ib_post_send for register," | 1780 | dprintk("RPC: %s: failed ib_post_send for register," |
| 1567 | " status %i\n", __func__, rc); | 1781 | " status %i\n", __func__, rc); |
| 1568 | while (i--) | 1782 | ib_update_fast_reg_key(mr, --key); |
| 1569 | rpcrdma_unmap_one(ia, --seg); | 1783 | goto out_err; |
| 1570 | } else { | 1784 | } else { |
| 1571 | seg1->mr_rkey = seg1->mr_chunk.rl_mw->r.frmr.fr_mr->rkey; | 1785 | seg1->mr_rkey = mr->rkey; |
| 1572 | seg1->mr_base = seg1->mr_dma + pageoff; | 1786 | seg1->mr_base = seg1->mr_dma + pageoff; |
| 1573 | seg1->mr_nsegs = i; | 1787 | seg1->mr_nsegs = i; |
| 1574 | seg1->mr_len = len; | 1788 | seg1->mr_len = len; |
| 1575 | } | 1789 | } |
| 1576 | *nsegs = i; | 1790 | *nsegs = i; |
| 1791 | return 0; | ||
| 1792 | out_err: | ||
| 1793 | frmr->fr_state = FRMR_IS_INVALID; | ||
| 1794 | while (i--) | ||
| 1795 | rpcrdma_unmap_one(ia, --seg); | ||
| 1577 | return rc; | 1796 | return rc; |
| 1578 | } | 1797 | } |
| 1579 | 1798 | ||
| @@ -1585,20 +1804,25 @@ rpcrdma_deregister_frmr_external(struct rpcrdma_mr_seg *seg, | |||
| 1585 | struct ib_send_wr invalidate_wr, *bad_wr; | 1804 | struct ib_send_wr invalidate_wr, *bad_wr; |
| 1586 | int rc; | 1805 | int rc; |
| 1587 | 1806 | ||
| 1588 | while (seg1->mr_nsegs--) | 1807 | seg1->mr_chunk.rl_mw->r.frmr.fr_state = FRMR_IS_INVALID; |
| 1589 | rpcrdma_unmap_one(ia, seg++); | ||
| 1590 | 1808 | ||
| 1591 | memset(&invalidate_wr, 0, sizeof invalidate_wr); | 1809 | memset(&invalidate_wr, 0, sizeof invalidate_wr); |
| 1592 | invalidate_wr.wr_id = (unsigned long)(void *)seg1->mr_chunk.rl_mw; | 1810 | invalidate_wr.wr_id = (unsigned long)(void *)seg1->mr_chunk.rl_mw; |
| 1593 | invalidate_wr.opcode = IB_WR_LOCAL_INV; | 1811 | invalidate_wr.opcode = IB_WR_LOCAL_INV; |
| 1594 | invalidate_wr.send_flags = IB_SEND_SIGNALED; | ||
| 1595 | invalidate_wr.ex.invalidate_rkey = seg1->mr_chunk.rl_mw->r.frmr.fr_mr->rkey; | 1812 | invalidate_wr.ex.invalidate_rkey = seg1->mr_chunk.rl_mw->r.frmr.fr_mr->rkey; |
| 1596 | DECR_CQCOUNT(&r_xprt->rx_ep); | 1813 | DECR_CQCOUNT(&r_xprt->rx_ep); |
| 1597 | 1814 | ||
| 1815 | read_lock(&ia->ri_qplock); | ||
| 1816 | while (seg1->mr_nsegs--) | ||
| 1817 | rpcrdma_unmap_one(ia, seg++); | ||
| 1598 | rc = ib_post_send(ia->ri_id->qp, &invalidate_wr, &bad_wr); | 1818 | rc = ib_post_send(ia->ri_id->qp, &invalidate_wr, &bad_wr); |
| 1599 | if (rc) | 1819 | read_unlock(&ia->ri_qplock); |
| 1820 | if (rc) { | ||
| 1821 | /* Force rpcrdma_buffer_get() to retry */ | ||
| 1822 | seg1->mr_chunk.rl_mw->r.frmr.fr_state = FRMR_IS_STALE; | ||
| 1600 | dprintk("RPC: %s: failed ib_post_send for invalidate," | 1823 | dprintk("RPC: %s: failed ib_post_send for invalidate," |
| 1601 | " status %i\n", __func__, rc); | 1824 | " status %i\n", __func__, rc); |
| 1825 | } | ||
| 1602 | return rc; | 1826 | return rc; |
| 1603 | } | 1827 | } |
| 1604 | 1828 | ||
| @@ -1656,8 +1880,10 @@ rpcrdma_deregister_fmr_external(struct rpcrdma_mr_seg *seg, | |||
| 1656 | 1880 | ||
| 1657 | list_add(&seg1->mr_chunk.rl_mw->r.fmr->list, &l); | 1881 | list_add(&seg1->mr_chunk.rl_mw->r.fmr->list, &l); |
| 1658 | rc = ib_unmap_fmr(&l); | 1882 | rc = ib_unmap_fmr(&l); |
| 1883 | read_lock(&ia->ri_qplock); | ||
| 1659 | while (seg1->mr_nsegs--) | 1884 | while (seg1->mr_nsegs--) |
| 1660 | rpcrdma_unmap_one(ia, seg++); | 1885 | rpcrdma_unmap_one(ia, seg++); |
| 1886 | read_unlock(&ia->ri_qplock); | ||
| 1661 | if (rc) | 1887 | if (rc) |
| 1662 | dprintk("RPC: %s: failed ib_unmap_fmr," | 1888 | dprintk("RPC: %s: failed ib_unmap_fmr," |
| 1663 | " status %i\n", __func__, rc); | 1889 | " status %i\n", __func__, rc); |
| @@ -1673,7 +1899,6 @@ rpcrdma_register_external(struct rpcrdma_mr_seg *seg, | |||
| 1673 | 1899 | ||
| 1674 | switch (ia->ri_memreg_strategy) { | 1900 | switch (ia->ri_memreg_strategy) { |
| 1675 | 1901 | ||
| 1676 | #if RPCRDMA_PERSISTENT_REGISTRATION | ||
| 1677 | case RPCRDMA_ALLPHYSICAL: | 1902 | case RPCRDMA_ALLPHYSICAL: |
| 1678 | rpcrdma_map_one(ia, seg, writing); | 1903 | rpcrdma_map_one(ia, seg, writing); |
| 1679 | seg->mr_rkey = ia->ri_bind_mem->rkey; | 1904 | seg->mr_rkey = ia->ri_bind_mem->rkey; |
| @@ -1681,7 +1906,6 @@ rpcrdma_register_external(struct rpcrdma_mr_seg *seg, | |||
| 1681 | seg->mr_nsegs = 1; | 1906 | seg->mr_nsegs = 1; |
| 1682 | nsegs = 1; | 1907 | nsegs = 1; |
| 1683 | break; | 1908 | break; |
| 1684 | #endif | ||
| 1685 | 1909 | ||
| 1686 | /* Registration using frmr registration */ | 1910 | /* Registration using frmr registration */ |
| 1687 | case RPCRDMA_FRMR: | 1911 | case RPCRDMA_FRMR: |
| @@ -1711,11 +1935,11 @@ rpcrdma_deregister_external(struct rpcrdma_mr_seg *seg, | |||
| 1711 | 1935 | ||
| 1712 | switch (ia->ri_memreg_strategy) { | 1936 | switch (ia->ri_memreg_strategy) { |
| 1713 | 1937 | ||
| 1714 | #if RPCRDMA_PERSISTENT_REGISTRATION | ||
| 1715 | case RPCRDMA_ALLPHYSICAL: | 1938 | case RPCRDMA_ALLPHYSICAL: |
| 1939 | read_lock(&ia->ri_qplock); | ||
| 1716 | rpcrdma_unmap_one(ia, seg); | 1940 | rpcrdma_unmap_one(ia, seg); |
| 1941 | read_unlock(&ia->ri_qplock); | ||
| 1717 | break; | 1942 | break; |
| 1718 | #endif | ||
| 1719 | 1943 | ||
| 1720 | case RPCRDMA_FRMR: | 1944 | case RPCRDMA_FRMR: |
| 1721 | rc = rpcrdma_deregister_frmr_external(seg, ia, r_xprt); | 1945 | rc = rpcrdma_deregister_frmr_external(seg, ia, r_xprt); |
| @@ -1809,3 +2033,44 @@ rpcrdma_ep_post_recv(struct rpcrdma_ia *ia, | |||
| 1809 | rc); | 2033 | rc); |
| 1810 | return rc; | 2034 | return rc; |
| 1811 | } | 2035 | } |
| 2036 | |||
| 2037 | /* Physical mapping means one Read/Write list entry per-page. | ||
| 2038 | * All list entries must fit within an inline buffer | ||
| 2039 | * | ||
| 2040 | * NB: The server must return a Write list for NFS READ, | ||
| 2041 | * which has the same constraint. Factor in the inline | ||
| 2042 | * rsize as well. | ||
| 2043 | */ | ||
| 2044 | static size_t | ||
| 2045 | rpcrdma_physical_max_payload(struct rpcrdma_xprt *r_xprt) | ||
| 2046 | { | ||
| 2047 | struct rpcrdma_create_data_internal *cdata = &r_xprt->rx_data; | ||
| 2048 | unsigned int inline_size, pages; | ||
| 2049 | |||
| 2050 | inline_size = min_t(unsigned int, | ||
| 2051 | cdata->inline_wsize, cdata->inline_rsize); | ||
| 2052 | inline_size -= RPCRDMA_HDRLEN_MIN; | ||
| 2053 | pages = inline_size / sizeof(struct rpcrdma_segment); | ||
| 2054 | return pages << PAGE_SHIFT; | ||
| 2055 | } | ||
| 2056 | |||
| 2057 | static size_t | ||
| 2058 | rpcrdma_mr_max_payload(struct rpcrdma_xprt *r_xprt) | ||
| 2059 | { | ||
| 2060 | return RPCRDMA_MAX_DATA_SEGS << PAGE_SHIFT; | ||
| 2061 | } | ||
| 2062 | |||
| 2063 | size_t | ||
| 2064 | rpcrdma_max_payload(struct rpcrdma_xprt *r_xprt) | ||
| 2065 | { | ||
| 2066 | size_t result; | ||
| 2067 | |||
| 2068 | switch (r_xprt->rx_ia.ri_memreg_strategy) { | ||
| 2069 | case RPCRDMA_ALLPHYSICAL: | ||
| 2070 | result = rpcrdma_physical_max_payload(r_xprt); | ||
| 2071 | break; | ||
| 2072 | default: | ||
| 2073 | result = rpcrdma_mr_max_payload(r_xprt); | ||
| 2074 | } | ||
| 2075 | return result; | ||
| 2076 | } | ||
diff --git a/net/sunrpc/xprtrdma/xprt_rdma.h b/net/sunrpc/xprtrdma/xprt_rdma.h index 89e7cd479705..c419498b8f46 100644 --- a/net/sunrpc/xprtrdma/xprt_rdma.h +++ b/net/sunrpc/xprtrdma/xprt_rdma.h | |||
| @@ -59,6 +59,7 @@ | |||
| 59 | * Interface Adapter -- one per transport instance | 59 | * Interface Adapter -- one per transport instance |
| 60 | */ | 60 | */ |
| 61 | struct rpcrdma_ia { | 61 | struct rpcrdma_ia { |
| 62 | rwlock_t ri_qplock; | ||
| 62 | struct rdma_cm_id *ri_id; | 63 | struct rdma_cm_id *ri_id; |
| 63 | struct ib_pd *ri_pd; | 64 | struct ib_pd *ri_pd; |
| 64 | struct ib_mr *ri_bind_mem; | 65 | struct ib_mr *ri_bind_mem; |
| @@ -98,6 +99,14 @@ struct rpcrdma_ep { | |||
| 98 | #define INIT_CQCOUNT(ep) atomic_set(&(ep)->rep_cqcount, (ep)->rep_cqinit) | 99 | #define INIT_CQCOUNT(ep) atomic_set(&(ep)->rep_cqcount, (ep)->rep_cqinit) |
| 99 | #define DECR_CQCOUNT(ep) atomic_sub_return(1, &(ep)->rep_cqcount) | 100 | #define DECR_CQCOUNT(ep) atomic_sub_return(1, &(ep)->rep_cqcount) |
| 100 | 101 | ||
| 102 | enum rpcrdma_chunktype { | ||
| 103 | rpcrdma_noch = 0, | ||
| 104 | rpcrdma_readch, | ||
| 105 | rpcrdma_areadch, | ||
| 106 | rpcrdma_writech, | ||
| 107 | rpcrdma_replych | ||
| 108 | }; | ||
| 109 | |||
| 101 | /* | 110 | /* |
| 102 | * struct rpcrdma_rep -- this structure encapsulates state required to recv | 111 | * struct rpcrdma_rep -- this structure encapsulates state required to recv |
| 103 | * and complete a reply, asychronously. It needs several pieces of | 112 | * and complete a reply, asychronously. It needs several pieces of |
| @@ -137,6 +146,40 @@ struct rpcrdma_rep { | |||
| 137 | }; | 146 | }; |
| 138 | 147 | ||
| 139 | /* | 148 | /* |
| 149 | * struct rpcrdma_mw - external memory region metadata | ||
| 150 | * | ||
| 151 | * An external memory region is any buffer or page that is registered | ||
| 152 | * on the fly (ie, not pre-registered). | ||
| 153 | * | ||
| 154 | * Each rpcrdma_buffer has a list of free MWs anchored in rb_mws. During | ||
| 155 | * call_allocate, rpcrdma_buffer_get() assigns one to each segment in | ||
| 156 | * an rpcrdma_req. Then rpcrdma_register_external() grabs these to keep | ||
| 157 | * track of registration metadata while each RPC is pending. | ||
| 158 | * rpcrdma_deregister_external() uses this metadata to unmap and | ||
| 159 | * release these resources when an RPC is complete. | ||
| 160 | */ | ||
| 161 | enum rpcrdma_frmr_state { | ||
| 162 | FRMR_IS_INVALID, /* ready to be used */ | ||
| 163 | FRMR_IS_VALID, /* in use */ | ||
| 164 | FRMR_IS_STALE, /* failed completion */ | ||
| 165 | }; | ||
| 166 | |||
| 167 | struct rpcrdma_frmr { | ||
| 168 | struct ib_fast_reg_page_list *fr_pgl; | ||
| 169 | struct ib_mr *fr_mr; | ||
| 170 | enum rpcrdma_frmr_state fr_state; | ||
| 171 | }; | ||
| 172 | |||
| 173 | struct rpcrdma_mw { | ||
| 174 | union { | ||
| 175 | struct ib_fmr *fmr; | ||
| 176 | struct rpcrdma_frmr frmr; | ||
| 177 | } r; | ||
| 178 | struct list_head mw_list; | ||
| 179 | struct list_head mw_all; | ||
| 180 | }; | ||
| 181 | |||
| 182 | /* | ||
| 140 | * struct rpcrdma_req -- structure central to the request/reply sequence. | 183 | * struct rpcrdma_req -- structure central to the request/reply sequence. |
| 141 | * | 184 | * |
| 142 | * N of these are associated with a transport instance, and stored in | 185 | * N of these are associated with a transport instance, and stored in |
| @@ -163,17 +206,7 @@ struct rpcrdma_rep { | |||
| 163 | struct rpcrdma_mr_seg { /* chunk descriptors */ | 206 | struct rpcrdma_mr_seg { /* chunk descriptors */ |
| 164 | union { /* chunk memory handles */ | 207 | union { /* chunk memory handles */ |
| 165 | struct ib_mr *rl_mr; /* if registered directly */ | 208 | struct ib_mr *rl_mr; /* if registered directly */ |
| 166 | struct rpcrdma_mw { /* if registered from region */ | 209 | struct rpcrdma_mw *rl_mw; /* if registered from region */ |
| 167 | union { | ||
| 168 | struct ib_fmr *fmr; | ||
| 169 | struct { | ||
| 170 | struct ib_fast_reg_page_list *fr_pgl; | ||
| 171 | struct ib_mr *fr_mr; | ||
| 172 | enum { FRMR_IS_INVALID, FRMR_IS_VALID } state; | ||
| 173 | } frmr; | ||
| 174 | } r; | ||
| 175 | struct list_head mw_list; | ||
| 176 | } *rl_mw; | ||
| 177 | } mr_chunk; | 210 | } mr_chunk; |
| 178 | u64 mr_base; /* registration result */ | 211 | u64 mr_base; /* registration result */ |
| 179 | u32 mr_rkey; /* registration result */ | 212 | u32 mr_rkey; /* registration result */ |
| @@ -191,6 +224,7 @@ struct rpcrdma_req { | |||
| 191 | unsigned int rl_niovs; /* 0, 2 or 4 */ | 224 | unsigned int rl_niovs; /* 0, 2 or 4 */ |
| 192 | unsigned int rl_nchunks; /* non-zero if chunks */ | 225 | unsigned int rl_nchunks; /* non-zero if chunks */ |
| 193 | unsigned int rl_connect_cookie; /* retry detection */ | 226 | unsigned int rl_connect_cookie; /* retry detection */ |
| 227 | enum rpcrdma_chunktype rl_rtype, rl_wtype; | ||
| 194 | struct rpcrdma_buffer *rl_buffer; /* home base for this structure */ | 228 | struct rpcrdma_buffer *rl_buffer; /* home base for this structure */ |
| 195 | struct rpcrdma_rep *rl_reply;/* holder for reply buffer */ | 229 | struct rpcrdma_rep *rl_reply;/* holder for reply buffer */ |
| 196 | struct rpcrdma_mr_seg rl_segments[RPCRDMA_MAX_SEGS];/* chunk segments */ | 230 | struct rpcrdma_mr_seg rl_segments[RPCRDMA_MAX_SEGS];/* chunk segments */ |
| @@ -214,6 +248,7 @@ struct rpcrdma_buffer { | |||
| 214 | atomic_t rb_credits; /* most recent server credits */ | 248 | atomic_t rb_credits; /* most recent server credits */ |
| 215 | int rb_max_requests;/* client max requests */ | 249 | int rb_max_requests;/* client max requests */ |
| 216 | struct list_head rb_mws; /* optional memory windows/fmrs/frmrs */ | 250 | struct list_head rb_mws; /* optional memory windows/fmrs/frmrs */ |
| 251 | struct list_head rb_all; | ||
| 217 | int rb_send_index; | 252 | int rb_send_index; |
| 218 | struct rpcrdma_req **rb_send_bufs; | 253 | struct rpcrdma_req **rb_send_bufs; |
| 219 | int rb_recv_index; | 254 | int rb_recv_index; |
| @@ -306,7 +341,7 @@ int rpcrdma_ep_create(struct rpcrdma_ep *, struct rpcrdma_ia *, | |||
| 306 | struct rpcrdma_create_data_internal *); | 341 | struct rpcrdma_create_data_internal *); |
| 307 | void rpcrdma_ep_destroy(struct rpcrdma_ep *, struct rpcrdma_ia *); | 342 | void rpcrdma_ep_destroy(struct rpcrdma_ep *, struct rpcrdma_ia *); |
| 308 | int rpcrdma_ep_connect(struct rpcrdma_ep *, struct rpcrdma_ia *); | 343 | int rpcrdma_ep_connect(struct rpcrdma_ep *, struct rpcrdma_ia *); |
| 309 | int rpcrdma_ep_disconnect(struct rpcrdma_ep *, struct rpcrdma_ia *); | 344 | void rpcrdma_ep_disconnect(struct rpcrdma_ep *, struct rpcrdma_ia *); |
| 310 | 345 | ||
| 311 | int rpcrdma_ep_post(struct rpcrdma_ia *, struct rpcrdma_ep *, | 346 | int rpcrdma_ep_post(struct rpcrdma_ia *, struct rpcrdma_ep *, |
| 312 | struct rpcrdma_req *); | 347 | struct rpcrdma_req *); |
| @@ -346,7 +381,9 @@ void rpcrdma_reply_handler(struct rpcrdma_rep *); | |||
| 346 | /* | 381 | /* |
| 347 | * RPC/RDMA protocol calls - xprtrdma/rpc_rdma.c | 382 | * RPC/RDMA protocol calls - xprtrdma/rpc_rdma.c |
| 348 | */ | 383 | */ |
| 384 | ssize_t rpcrdma_marshal_chunks(struct rpc_rqst *, ssize_t); | ||
| 349 | int rpcrdma_marshal_req(struct rpc_rqst *); | 385 | int rpcrdma_marshal_req(struct rpc_rqst *); |
| 386 | size_t rpcrdma_max_payload(struct rpcrdma_xprt *); | ||
| 350 | 387 | ||
| 351 | /* Temporary NFS request map cache. Created in svc_rdma.c */ | 388 | /* Temporary NFS request map cache. Created in svc_rdma.c */ |
| 352 | extern struct kmem_cache *svc_rdma_map_cachep; | 389 | extern struct kmem_cache *svc_rdma_map_cachep; |
diff --git a/net/sunrpc/xprtsock.c b/net/sunrpc/xprtsock.c index be8bbd5d65ec..43cd89eacfab 100644 --- a/net/sunrpc/xprtsock.c +++ b/net/sunrpc/xprtsock.c | |||
| @@ -594,6 +594,7 @@ static int xs_local_send_request(struct rpc_task *task) | |||
| 594 | } | 594 | } |
| 595 | 595 | ||
| 596 | switch (status) { | 596 | switch (status) { |
| 597 | case -ENOBUFS: | ||
| 597 | case -EAGAIN: | 598 | case -EAGAIN: |
| 598 | status = xs_nospace(task); | 599 | status = xs_nospace(task); |
| 599 | break; | 600 | break; |
| @@ -661,6 +662,7 @@ static int xs_udp_send_request(struct rpc_task *task) | |||
| 661 | dprintk("RPC: sendmsg returned unrecognized error %d\n", | 662 | dprintk("RPC: sendmsg returned unrecognized error %d\n", |
| 662 | -status); | 663 | -status); |
| 663 | case -ENETUNREACH: | 664 | case -ENETUNREACH: |
| 665 | case -ENOBUFS: | ||
| 664 | case -EPIPE: | 666 | case -EPIPE: |
| 665 | case -ECONNREFUSED: | 667 | case -ECONNREFUSED: |
| 666 | /* When the server has died, an ICMP port unreachable message | 668 | /* When the server has died, an ICMP port unreachable message |
| @@ -758,6 +760,7 @@ static int xs_tcp_send_request(struct rpc_task *task) | |||
| 758 | status = -ENOTCONN; | 760 | status = -ENOTCONN; |
| 759 | /* Should we call xs_close() here? */ | 761 | /* Should we call xs_close() here? */ |
| 760 | break; | 762 | break; |
| 763 | case -ENOBUFS: | ||
| 761 | case -EAGAIN: | 764 | case -EAGAIN: |
| 762 | status = xs_nospace(task); | 765 | status = xs_nospace(task); |
| 763 | break; | 766 | break; |
| @@ -1946,6 +1949,7 @@ static int xs_local_setup_socket(struct sock_xprt *transport) | |||
| 1946 | dprintk("RPC: xprt %p connected to %s\n", | 1949 | dprintk("RPC: xprt %p connected to %s\n", |
| 1947 | xprt, xprt->address_strings[RPC_DISPLAY_ADDR]); | 1950 | xprt, xprt->address_strings[RPC_DISPLAY_ADDR]); |
| 1948 | xprt_set_connected(xprt); | 1951 | xprt_set_connected(xprt); |
| 1952 | case -ENOBUFS: | ||
| 1949 | break; | 1953 | break; |
| 1950 | case -ENOENT: | 1954 | case -ENOENT: |
| 1951 | dprintk("RPC: xprt %p: socket %s does not exist\n", | 1955 | dprintk("RPC: xprt %p: socket %s does not exist\n", |
| @@ -2281,6 +2285,7 @@ static void xs_tcp_setup_socket(struct work_struct *work) | |||
| 2281 | case -ECONNREFUSED: | 2285 | case -ECONNREFUSED: |
| 2282 | case -ECONNRESET: | 2286 | case -ECONNRESET: |
| 2283 | case -ENETUNREACH: | 2287 | case -ENETUNREACH: |
| 2288 | case -ENOBUFS: | ||
| 2284 | /* retry with existing socket, after a delay */ | 2289 | /* retry with existing socket, after a delay */ |
| 2285 | goto out; | 2290 | goto out; |
| 2286 | } | 2291 | } |
| @@ -3054,12 +3059,12 @@ static int param_set_uint_minmax(const char *val, | |||
| 3054 | const struct kernel_param *kp, | 3059 | const struct kernel_param *kp, |
| 3055 | unsigned int min, unsigned int max) | 3060 | unsigned int min, unsigned int max) |
| 3056 | { | 3061 | { |
| 3057 | unsigned long num; | 3062 | unsigned int num; |
| 3058 | int ret; | 3063 | int ret; |
| 3059 | 3064 | ||
| 3060 | if (!val) | 3065 | if (!val) |
| 3061 | return -EINVAL; | 3066 | return -EINVAL; |
| 3062 | ret = strict_strtoul(val, 0, &num); | 3067 | ret = kstrtouint(val, 0, &num); |
| 3063 | if (ret == -EINVAL || num < min || num > max) | 3068 | if (ret == -EINVAL || num < min || num > max) |
| 3064 | return -EINVAL; | 3069 | return -EINVAL; |
| 3065 | *((unsigned int *)kp->arg) = num; | 3070 | *((unsigned int *)kp->arg) = num; |
diff --git a/net/tipc/bcast.c b/net/tipc/bcast.c index 55c6c9d3e1ce..dd13bfa09333 100644 --- a/net/tipc/bcast.c +++ b/net/tipc/bcast.c | |||
| @@ -1,7 +1,7 @@ | |||
| 1 | /* | 1 | /* |
| 2 | * net/tipc/bcast.c: TIPC broadcast code | 2 | * net/tipc/bcast.c: TIPC broadcast code |
| 3 | * | 3 | * |
| 4 | * Copyright (c) 2004-2006, Ericsson AB | 4 | * Copyright (c) 2004-2006, 2014, Ericsson AB |
| 5 | * Copyright (c) 2004, Intel Corporation. | 5 | * Copyright (c) 2004, Intel Corporation. |
| 6 | * Copyright (c) 2005, 2010-2011, Wind River Systems | 6 | * Copyright (c) 2005, 2010-2011, Wind River Systems |
| 7 | * All rights reserved. | 7 | * All rights reserved. |
| @@ -38,6 +38,8 @@ | |||
| 38 | #include "core.h" | 38 | #include "core.h" |
| 39 | #include "link.h" | 39 | #include "link.h" |
| 40 | #include "port.h" | 40 | #include "port.h" |
| 41 | #include "socket.h" | ||
| 42 | #include "msg.h" | ||
| 41 | #include "bcast.h" | 43 | #include "bcast.h" |
| 42 | #include "name_distr.h" | 44 | #include "name_distr.h" |
| 43 | 45 | ||
| @@ -138,6 +140,11 @@ static void tipc_bclink_unlock(void) | |||
| 138 | tipc_link_reset_all(node); | 140 | tipc_link_reset_all(node); |
| 139 | } | 141 | } |
| 140 | 142 | ||
| 143 | uint tipc_bclink_get_mtu(void) | ||
| 144 | { | ||
| 145 | return MAX_PKT_DEFAULT_MCAST; | ||
| 146 | } | ||
| 147 | |||
| 141 | void tipc_bclink_set_flags(unsigned int flags) | 148 | void tipc_bclink_set_flags(unsigned int flags) |
| 142 | { | 149 | { |
| 143 | bclink->flags |= flags; | 150 | bclink->flags |= flags; |
| @@ -382,30 +389,50 @@ static void bclink_peek_nack(struct tipc_msg *msg) | |||
| 382 | tipc_node_unlock(n_ptr); | 389 | tipc_node_unlock(n_ptr); |
| 383 | } | 390 | } |
| 384 | 391 | ||
| 385 | /* | 392 | /* tipc_bclink_xmit - broadcast buffer chain to all nodes in cluster |
| 386 | * tipc_bclink_xmit - broadcast a packet to all nodes in cluster | 393 | * and to identified node local sockets |
| 394 | * @buf: chain of buffers containing message | ||
| 395 | * Consumes the buffer chain, except when returning -ELINKCONG | ||
| 396 | * Returns 0 if success, otherwise errno: -ELINKCONG,-EHOSTUNREACH,-EMSGSIZE | ||
| 387 | */ | 397 | */ |
| 388 | int tipc_bclink_xmit(struct sk_buff *buf) | 398 | int tipc_bclink_xmit(struct sk_buff *buf) |
| 389 | { | 399 | { |
| 390 | int res; | 400 | int rc = 0; |
| 401 | int bc = 0; | ||
| 402 | struct sk_buff *clbuf; | ||
| 391 | 403 | ||
| 392 | tipc_bclink_lock(); | 404 | /* Prepare clone of message for local node */ |
| 393 | 405 | clbuf = tipc_msg_reassemble(buf); | |
| 394 | if (!bclink->bcast_nodes.count) { | 406 | if (unlikely(!clbuf)) { |
| 395 | res = msg_data_sz(buf_msg(buf)); | 407 | kfree_skb_list(buf); |
| 396 | kfree_skb(buf); | 408 | return -EHOSTUNREACH; |
| 397 | goto exit; | ||
| 398 | } | 409 | } |
| 399 | 410 | ||
| 400 | res = __tipc_link_xmit(bcl, buf); | 411 | /* Broadcast to all other nodes */ |
| 401 | if (likely(res >= 0)) { | 412 | if (likely(bclink)) { |
| 402 | bclink_set_last_sent(); | 413 | tipc_bclink_lock(); |
| 403 | bcl->stats.queue_sz_counts++; | 414 | if (likely(bclink->bcast_nodes.count)) { |
| 404 | bcl->stats.accu_queue_sz += bcl->out_queue_size; | 415 | rc = __tipc_link_xmit(bcl, buf); |
| 416 | if (likely(!rc)) { | ||
| 417 | bclink_set_last_sent(); | ||
| 418 | bcl->stats.queue_sz_counts++; | ||
| 419 | bcl->stats.accu_queue_sz += bcl->out_queue_size; | ||
| 420 | } | ||
| 421 | bc = 1; | ||
| 422 | } | ||
| 423 | tipc_bclink_unlock(); | ||
| 405 | } | 424 | } |
| 406 | exit: | 425 | |
| 407 | tipc_bclink_unlock(); | 426 | if (unlikely(!bc)) |
| 408 | return res; | 427 | kfree_skb_list(buf); |
| 428 | |||
| 429 | /* Deliver message clone */ | ||
| 430 | if (likely(!rc)) | ||
| 431 | tipc_sk_mcast_rcv(clbuf); | ||
| 432 | else | ||
| 433 | kfree_skb(clbuf); | ||
| 434 | |||
| 435 | return rc; | ||
| 409 | } | 436 | } |
| 410 | 437 | ||
| 411 | /** | 438 | /** |
| @@ -443,7 +470,7 @@ void tipc_bclink_rcv(struct sk_buff *buf) | |||
| 443 | struct tipc_node *node; | 470 | struct tipc_node *node; |
| 444 | u32 next_in; | 471 | u32 next_in; |
| 445 | u32 seqno; | 472 | u32 seqno; |
| 446 | int deferred; | 473 | int deferred = 0; |
| 447 | 474 | ||
| 448 | /* Screen out unwanted broadcast messages */ | 475 | /* Screen out unwanted broadcast messages */ |
| 449 | 476 | ||
| @@ -494,7 +521,7 @@ receive: | |||
| 494 | tipc_bclink_unlock(); | 521 | tipc_bclink_unlock(); |
| 495 | tipc_node_unlock(node); | 522 | tipc_node_unlock(node); |
| 496 | if (likely(msg_mcast(msg))) | 523 | if (likely(msg_mcast(msg))) |
| 497 | tipc_port_mcast_rcv(buf, NULL); | 524 | tipc_sk_mcast_rcv(buf); |
| 498 | else | 525 | else |
| 499 | kfree_skb(buf); | 526 | kfree_skb(buf); |
| 500 | } else if (msg_user(msg) == MSG_BUNDLER) { | 527 | } else if (msg_user(msg) == MSG_BUNDLER) { |
| @@ -573,8 +600,7 @@ receive: | |||
| 573 | node->bclink.deferred_size += deferred; | 600 | node->bclink.deferred_size += deferred; |
| 574 | bclink_update_last_sent(node, seqno); | 601 | bclink_update_last_sent(node, seqno); |
| 575 | buf = NULL; | 602 | buf = NULL; |
| 576 | } else | 603 | } |
| 577 | deferred = 0; | ||
| 578 | 604 | ||
| 579 | tipc_bclink_lock(); | 605 | tipc_bclink_lock(); |
| 580 | 606 | ||
| @@ -611,6 +637,7 @@ static int tipc_bcbearer_send(struct sk_buff *buf, struct tipc_bearer *unused1, | |||
| 611 | struct tipc_media_addr *unused2) | 637 | struct tipc_media_addr *unused2) |
| 612 | { | 638 | { |
| 613 | int bp_index; | 639 | int bp_index; |
| 640 | struct tipc_msg *msg = buf_msg(buf); | ||
| 614 | 641 | ||
| 615 | /* Prepare broadcast link message for reliable transmission, | 642 | /* Prepare broadcast link message for reliable transmission, |
| 616 | * if first time trying to send it; | 643 | * if first time trying to send it; |
| @@ -618,10 +645,7 @@ static int tipc_bcbearer_send(struct sk_buff *buf, struct tipc_bearer *unused1, | |||
| 618 | * since they are sent in an unreliable manner and don't need it | 645 | * since they are sent in an unreliable manner and don't need it |
| 619 | */ | 646 | */ |
| 620 | if (likely(!msg_non_seq(buf_msg(buf)))) { | 647 | if (likely(!msg_non_seq(buf_msg(buf)))) { |
| 621 | struct tipc_msg *msg; | ||
| 622 | |||
| 623 | bcbuf_set_acks(buf, bclink->bcast_nodes.count); | 648 | bcbuf_set_acks(buf, bclink->bcast_nodes.count); |
| 624 | msg = buf_msg(buf); | ||
| 625 | msg_set_non_seq(msg, 1); | 649 | msg_set_non_seq(msg, 1); |
| 626 | msg_set_mc_netid(msg, tipc_net_id); | 650 | msg_set_mc_netid(msg, tipc_net_id); |
| 627 | bcl->stats.sent_info++; | 651 | bcl->stats.sent_info++; |
| @@ -638,12 +662,14 @@ static int tipc_bcbearer_send(struct sk_buff *buf, struct tipc_bearer *unused1, | |||
| 638 | for (bp_index = 0; bp_index < MAX_BEARERS; bp_index++) { | 662 | for (bp_index = 0; bp_index < MAX_BEARERS; bp_index++) { |
| 639 | struct tipc_bearer *p = bcbearer->bpairs[bp_index].primary; | 663 | struct tipc_bearer *p = bcbearer->bpairs[bp_index].primary; |
| 640 | struct tipc_bearer *s = bcbearer->bpairs[bp_index].secondary; | 664 | struct tipc_bearer *s = bcbearer->bpairs[bp_index].secondary; |
| 641 | struct tipc_bearer *b = p; | 665 | struct tipc_bearer *bp[2] = {p, s}; |
| 666 | struct tipc_bearer *b = bp[msg_link_selector(msg)]; | ||
| 642 | struct sk_buff *tbuf; | 667 | struct sk_buff *tbuf; |
| 643 | 668 | ||
| 644 | if (!p) | 669 | if (!p) |
| 645 | break; /* No more bearers to try */ | 670 | break; /* No more bearers to try */ |
| 646 | 671 | if (!b) | |
| 672 | b = p; | ||
| 647 | tipc_nmap_diff(&bcbearer->remains, &b->nodes, | 673 | tipc_nmap_diff(&bcbearer->remains, &b->nodes, |
| 648 | &bcbearer->remains_new); | 674 | &bcbearer->remains_new); |
| 649 | if (bcbearer->remains_new.count == bcbearer->remains.count) | 675 | if (bcbearer->remains_new.count == bcbearer->remains.count) |
| @@ -660,13 +686,6 @@ static int tipc_bcbearer_send(struct sk_buff *buf, struct tipc_bearer *unused1, | |||
| 660 | tipc_bearer_send(b->identity, tbuf, &b->bcast_addr); | 686 | tipc_bearer_send(b->identity, tbuf, &b->bcast_addr); |
| 661 | kfree_skb(tbuf); /* Bearer keeps a clone */ | 687 | kfree_skb(tbuf); /* Bearer keeps a clone */ |
| 662 | } | 688 | } |
| 663 | |||
| 664 | /* Swap bearers for next packet */ | ||
| 665 | if (s) { | ||
| 666 | bcbearer->bpairs[bp_index].primary = s; | ||
| 667 | bcbearer->bpairs[bp_index].secondary = p; | ||
| 668 | } | ||
| 669 | |||
| 670 | if (bcbearer->remains_new.count == 0) | 689 | if (bcbearer->remains_new.count == 0) |
| 671 | break; /* All targets reached */ | 690 | break; /* All targets reached */ |
| 672 | 691 | ||
diff --git a/net/tipc/bcast.h b/net/tipc/bcast.h index 00330c45df3e..4875d9536aee 100644 --- a/net/tipc/bcast.h +++ b/net/tipc/bcast.h | |||
| @@ -1,7 +1,7 @@ | |||
| 1 | /* | 1 | /* |
| 2 | * net/tipc/bcast.h: Include file for TIPC broadcast code | 2 | * net/tipc/bcast.h: Include file for TIPC broadcast code |
| 3 | * | 3 | * |
| 4 | * Copyright (c) 2003-2006, Ericsson AB | 4 | * Copyright (c) 2003-2006, 2014, Ericsson AB |
| 5 | * Copyright (c) 2005, 2010-2011, Wind River Systems | 5 | * Copyright (c) 2005, 2010-2011, Wind River Systems |
| 6 | * All rights reserved. | 6 | * All rights reserved. |
| 7 | * | 7 | * |
| @@ -89,7 +89,6 @@ void tipc_bclink_add_node(u32 addr); | |||
| 89 | void tipc_bclink_remove_node(u32 addr); | 89 | void tipc_bclink_remove_node(u32 addr); |
| 90 | struct tipc_node *tipc_bclink_retransmit_to(void); | 90 | struct tipc_node *tipc_bclink_retransmit_to(void); |
| 91 | void tipc_bclink_acknowledge(struct tipc_node *n_ptr, u32 acked); | 91 | void tipc_bclink_acknowledge(struct tipc_node *n_ptr, u32 acked); |
| 92 | int tipc_bclink_xmit(struct sk_buff *buf); | ||
| 93 | void tipc_bclink_rcv(struct sk_buff *buf); | 92 | void tipc_bclink_rcv(struct sk_buff *buf); |
| 94 | u32 tipc_bclink_get_last_sent(void); | 93 | u32 tipc_bclink_get_last_sent(void); |
| 95 | u32 tipc_bclink_acks_missing(struct tipc_node *n_ptr); | 94 | u32 tipc_bclink_acks_missing(struct tipc_node *n_ptr); |
| @@ -98,5 +97,7 @@ int tipc_bclink_stats(char *stats_buf, const u32 buf_size); | |||
| 98 | int tipc_bclink_reset_stats(void); | 97 | int tipc_bclink_reset_stats(void); |
| 99 | int tipc_bclink_set_queue_limits(u32 limit); | 98 | int tipc_bclink_set_queue_limits(u32 limit); |
| 100 | void tipc_bcbearer_sort(struct tipc_node_map *nm_ptr, u32 node, bool action); | 99 | void tipc_bcbearer_sort(struct tipc_node_map *nm_ptr, u32 node, bool action); |
| 100 | uint tipc_bclink_get_mtu(void); | ||
| 101 | int tipc_bclink_xmit(struct sk_buff *buf); | ||
| 101 | 102 | ||
| 102 | #endif | 103 | #endif |
diff --git a/net/tipc/link.c b/net/tipc/link.c index ad2c57f5868d..fb1485dc6736 100644 --- a/net/tipc/link.c +++ b/net/tipc/link.c | |||
| @@ -82,15 +82,13 @@ static void tipc_link_proto_rcv(struct tipc_link *l_ptr, struct sk_buff *buf); | |||
| 82 | static int tipc_link_tunnel_rcv(struct tipc_node *n_ptr, | 82 | static int tipc_link_tunnel_rcv(struct tipc_node *n_ptr, |
| 83 | struct sk_buff **buf); | 83 | struct sk_buff **buf); |
| 84 | static void link_set_supervision_props(struct tipc_link *l_ptr, u32 tolerance); | 84 | static void link_set_supervision_props(struct tipc_link *l_ptr, u32 tolerance); |
| 85 | static int tipc_link_iovec_long_xmit(struct tipc_port *sender, | ||
| 86 | struct iovec const *msg_sect, | ||
| 87 | unsigned int len, u32 destnode); | ||
| 88 | static void link_state_event(struct tipc_link *l_ptr, u32 event); | 85 | static void link_state_event(struct tipc_link *l_ptr, u32 event); |
| 89 | static void link_reset_statistics(struct tipc_link *l_ptr); | 86 | static void link_reset_statistics(struct tipc_link *l_ptr); |
| 90 | static void link_print(struct tipc_link *l_ptr, const char *str); | 87 | static void link_print(struct tipc_link *l_ptr, const char *str); |
| 91 | static int tipc_link_frag_xmit(struct tipc_link *l_ptr, struct sk_buff *buf); | ||
| 92 | static void tipc_link_sync_xmit(struct tipc_link *l); | 88 | static void tipc_link_sync_xmit(struct tipc_link *l); |
| 93 | static void tipc_link_sync_rcv(struct tipc_node *n, struct sk_buff *buf); | 89 | static void tipc_link_sync_rcv(struct tipc_node *n, struct sk_buff *buf); |
| 90 | static int tipc_link_input(struct tipc_link *l, struct sk_buff *buf); | ||
| 91 | static int tipc_link_prepare_input(struct tipc_link *l, struct sk_buff **buf); | ||
| 94 | 92 | ||
| 95 | /* | 93 | /* |
| 96 | * Simple link routines | 94 | * Simple link routines |
| @@ -335,13 +333,15 @@ void tipc_link_delete_list(unsigned int bearer_id, bool shutting_down) | |||
| 335 | static int link_schedule_port(struct tipc_link *l_ptr, u32 origport, u32 sz) | 333 | static int link_schedule_port(struct tipc_link *l_ptr, u32 origport, u32 sz) |
| 336 | { | 334 | { |
| 337 | struct tipc_port *p_ptr; | 335 | struct tipc_port *p_ptr; |
| 336 | struct tipc_sock *tsk; | ||
| 338 | 337 | ||
| 339 | spin_lock_bh(&tipc_port_list_lock); | 338 | spin_lock_bh(&tipc_port_list_lock); |
| 340 | p_ptr = tipc_port_lock(origport); | 339 | p_ptr = tipc_port_lock(origport); |
| 341 | if (p_ptr) { | 340 | if (p_ptr) { |
| 342 | if (!list_empty(&p_ptr->wait_list)) | 341 | if (!list_empty(&p_ptr->wait_list)) |
| 343 | goto exit; | 342 | goto exit; |
| 344 | p_ptr->congested = 1; | 343 | tsk = tipc_port_to_sock(p_ptr); |
| 344 | tsk->link_cong = 1; | ||
| 345 | p_ptr->waiting_pkts = 1 + ((sz - 1) / l_ptr->max_pkt); | 345 | p_ptr->waiting_pkts = 1 + ((sz - 1) / l_ptr->max_pkt); |
| 346 | list_add_tail(&p_ptr->wait_list, &l_ptr->waiting_ports); | 346 | list_add_tail(&p_ptr->wait_list, &l_ptr->waiting_ports); |
| 347 | l_ptr->stats.link_congs++; | 347 | l_ptr->stats.link_congs++; |
| @@ -355,6 +355,7 @@ exit: | |||
| 355 | void tipc_link_wakeup_ports(struct tipc_link *l_ptr, int all) | 355 | void tipc_link_wakeup_ports(struct tipc_link *l_ptr, int all) |
| 356 | { | 356 | { |
| 357 | struct tipc_port *p_ptr; | 357 | struct tipc_port *p_ptr; |
| 358 | struct tipc_sock *tsk; | ||
| 358 | struct tipc_port *temp_p_ptr; | 359 | struct tipc_port *temp_p_ptr; |
| 359 | int win = l_ptr->queue_limit[0] - l_ptr->out_queue_size; | 360 | int win = l_ptr->queue_limit[0] - l_ptr->out_queue_size; |
| 360 | 361 | ||
| @@ -370,10 +371,11 @@ void tipc_link_wakeup_ports(struct tipc_link *l_ptr, int all) | |||
| 370 | wait_list) { | 371 | wait_list) { |
| 371 | if (win <= 0) | 372 | if (win <= 0) |
| 372 | break; | 373 | break; |
| 374 | tsk = tipc_port_to_sock(p_ptr); | ||
| 373 | list_del_init(&p_ptr->wait_list); | 375 | list_del_init(&p_ptr->wait_list); |
| 374 | spin_lock_bh(p_ptr->lock); | 376 | spin_lock_bh(p_ptr->lock); |
| 375 | p_ptr->congested = 0; | 377 | tsk->link_cong = 0; |
| 376 | tipc_port_wakeup(p_ptr); | 378 | tipc_sock_wakeup(tsk); |
| 377 | win -= p_ptr->waiting_pkts; | 379 | win -= p_ptr->waiting_pkts; |
| 378 | spin_unlock_bh(p_ptr->lock); | 380 | spin_unlock_bh(p_ptr->lock); |
| 379 | } | 381 | } |
| @@ -676,178 +678,142 @@ static void link_state_event(struct tipc_link *l_ptr, unsigned int event) | |||
| 676 | } | 678 | } |
| 677 | } | 679 | } |
| 678 | 680 | ||
| 679 | /* | 681 | /* tipc_link_cong: determine return value and how to treat the |
| 680 | * link_bundle_buf(): Append contents of a buffer to | 682 | * sent buffer during link congestion. |
| 681 | * the tail of an existing one. | 683 | * - For plain, errorless user data messages we keep the buffer and |
| 684 | * return -ELINKONG. | ||
| 685 | * - For all other messages we discard the buffer and return -EHOSTUNREACH | ||
| 686 | * - For TIPC internal messages we also reset the link | ||
| 682 | */ | 687 | */ |
| 683 | static int link_bundle_buf(struct tipc_link *l_ptr, struct sk_buff *bundler, | 688 | static int tipc_link_cong(struct tipc_link *link, struct sk_buff *buf) |
| 684 | struct sk_buff *buf) | ||
| 685 | { | 689 | { |
| 686 | struct tipc_msg *bundler_msg = buf_msg(bundler); | ||
| 687 | struct tipc_msg *msg = buf_msg(buf); | 690 | struct tipc_msg *msg = buf_msg(buf); |
| 688 | u32 size = msg_size(msg); | 691 | uint psz = msg_size(msg); |
| 689 | u32 bundle_size = msg_size(bundler_msg); | 692 | uint imp = tipc_msg_tot_importance(msg); |
| 690 | u32 to_pos = align(bundle_size); | 693 | u32 oport = msg_tot_origport(msg); |
| 691 | u32 pad = to_pos - bundle_size; | ||
| 692 | |||
| 693 | if (msg_user(bundler_msg) != MSG_BUNDLER) | ||
| 694 | return 0; | ||
| 695 | if (msg_type(bundler_msg) != OPEN_MSG) | ||
| 696 | return 0; | ||
| 697 | if (skb_tailroom(bundler) < (pad + size)) | ||
| 698 | return 0; | ||
| 699 | if (l_ptr->max_pkt < (to_pos + size)) | ||
| 700 | return 0; | ||
| 701 | |||
| 702 | skb_put(bundler, pad + size); | ||
| 703 | skb_copy_to_linear_data_offset(bundler, to_pos, buf->data, size); | ||
| 704 | msg_set_size(bundler_msg, to_pos + size); | ||
| 705 | msg_set_msgcnt(bundler_msg, msg_msgcnt(bundler_msg) + 1); | ||
| 706 | kfree_skb(buf); | ||
| 707 | l_ptr->stats.sent_bundled++; | ||
| 708 | return 1; | ||
| 709 | } | ||
| 710 | |||
| 711 | static void link_add_to_outqueue(struct tipc_link *l_ptr, | ||
| 712 | struct sk_buff *buf, | ||
| 713 | struct tipc_msg *msg) | ||
| 714 | { | ||
| 715 | u32 ack = mod(l_ptr->next_in_no - 1); | ||
| 716 | u32 seqno = mod(l_ptr->next_out_no++); | ||
| 717 | 694 | ||
| 718 | msg_set_word(msg, 2, ((ack << 16) | seqno)); | 695 | if (likely(imp <= TIPC_CRITICAL_IMPORTANCE)) { |
| 719 | msg_set_bcast_ack(msg, l_ptr->owner->bclink.last_in); | 696 | if (!msg_errcode(msg) && !msg_reroute_cnt(msg)) { |
| 720 | buf->next = NULL; | 697 | link_schedule_port(link, oport, psz); |
| 721 | if (l_ptr->first_out) { | 698 | return -ELINKCONG; |
| 722 | l_ptr->last_out->next = buf; | 699 | } |
| 723 | l_ptr->last_out = buf; | 700 | } else { |
| 724 | } else | 701 | pr_warn("%s<%s>, send queue full", link_rst_msg, link->name); |
| 725 | l_ptr->first_out = l_ptr->last_out = buf; | 702 | tipc_link_reset(link); |
| 726 | |||
| 727 | l_ptr->out_queue_size++; | ||
| 728 | if (l_ptr->out_queue_size > l_ptr->stats.max_queue_sz) | ||
| 729 | l_ptr->stats.max_queue_sz = l_ptr->out_queue_size; | ||
| 730 | } | ||
| 731 | |||
| 732 | static void link_add_chain_to_outqueue(struct tipc_link *l_ptr, | ||
| 733 | struct sk_buff *buf_chain, | ||
| 734 | u32 long_msgno) | ||
| 735 | { | ||
| 736 | struct sk_buff *buf; | ||
| 737 | struct tipc_msg *msg; | ||
| 738 | |||
| 739 | if (!l_ptr->next_out) | ||
| 740 | l_ptr->next_out = buf_chain; | ||
| 741 | while (buf_chain) { | ||
| 742 | buf = buf_chain; | ||
| 743 | buf_chain = buf_chain->next; | ||
| 744 | |||
| 745 | msg = buf_msg(buf); | ||
| 746 | msg_set_long_msgno(msg, long_msgno); | ||
| 747 | link_add_to_outqueue(l_ptr, buf, msg); | ||
| 748 | } | 703 | } |
| 704 | kfree_skb_list(buf); | ||
| 705 | return -EHOSTUNREACH; | ||
| 749 | } | 706 | } |
| 750 | 707 | ||
| 751 | /* | 708 | /** |
| 752 | * tipc_link_xmit() is the 'full path' for messages, called from | 709 | * __tipc_link_xmit(): same as tipc_link_xmit, but destlink is known & locked |
| 753 | * inside TIPC when the 'fast path' in tipc_send_xmit | 710 | * @link: link to use |
| 754 | * has failed, and from link_send() | 711 | * @buf: chain of buffers containing message |
| 712 | * Consumes the buffer chain, except when returning -ELINKCONG | ||
| 713 | * Returns 0 if success, otherwise errno: -ELINKCONG, -EMSGSIZE (plain socket | ||
| 714 | * user data messages) or -EHOSTUNREACH (all other messages/senders) | ||
| 715 | * Only the socket functions tipc_send_stream() and tipc_send_packet() need | ||
| 716 | * to act on the return value, since they may need to do more send attempts. | ||
| 755 | */ | 717 | */ |
| 756 | int __tipc_link_xmit(struct tipc_link *l_ptr, struct sk_buff *buf) | 718 | int __tipc_link_xmit(struct tipc_link *link, struct sk_buff *buf) |
| 757 | { | 719 | { |
| 758 | struct tipc_msg *msg = buf_msg(buf); | 720 | struct tipc_msg *msg = buf_msg(buf); |
| 759 | u32 size = msg_size(msg); | 721 | uint psz = msg_size(msg); |
| 760 | u32 dsz = msg_data_sz(msg); | 722 | uint qsz = link->out_queue_size; |
| 761 | u32 queue_size = l_ptr->out_queue_size; | 723 | uint sndlim = link->queue_limit[0]; |
| 762 | u32 imp = tipc_msg_tot_importance(msg); | 724 | uint imp = tipc_msg_tot_importance(msg); |
| 763 | u32 queue_limit = l_ptr->queue_limit[imp]; | 725 | uint mtu = link->max_pkt; |
| 764 | u32 max_packet = l_ptr->max_pkt; | 726 | uint ack = mod(link->next_in_no - 1); |
| 765 | 727 | uint seqno = link->next_out_no; | |
| 766 | /* Match msg importance against queue limits: */ | 728 | uint bc_last_in = link->owner->bclink.last_in; |
| 767 | if (unlikely(queue_size >= queue_limit)) { | 729 | struct tipc_media_addr *addr = &link->media_addr; |
| 768 | if (imp <= TIPC_CRITICAL_IMPORTANCE) { | 730 | struct sk_buff *next = buf->next; |
| 769 | link_schedule_port(l_ptr, msg_origport(msg), size); | 731 | |
| 770 | kfree_skb(buf); | 732 | /* Match queue limits against msg importance: */ |
| 771 | return -ELINKCONG; | 733 | if (unlikely(qsz >= link->queue_limit[imp])) |
| 772 | } | 734 | return tipc_link_cong(link, buf); |
| 773 | kfree_skb(buf); | 735 | |
| 774 | if (imp > CONN_MANAGER) { | 736 | /* Has valid packet limit been used ? */ |
| 775 | pr_warn("%s<%s>, send queue full", link_rst_msg, | 737 | if (unlikely(psz > mtu)) { |
| 776 | l_ptr->name); | 738 | kfree_skb_list(buf); |
| 777 | tipc_link_reset(l_ptr); | 739 | return -EMSGSIZE; |
| 778 | } | ||
| 779 | return dsz; | ||
| 780 | } | 740 | } |
| 781 | 741 | ||
| 782 | /* Fragmentation needed ? */ | 742 | /* Prepare each packet for sending, and add to outqueue: */ |
| 783 | if (size > max_packet) | 743 | while (buf) { |
| 784 | return tipc_link_frag_xmit(l_ptr, buf); | 744 | next = buf->next; |
| 785 | 745 | msg = buf_msg(buf); | |
| 786 | /* Packet can be queued or sent. */ | 746 | msg_set_word(msg, 2, ((ack << 16) | mod(seqno))); |
| 787 | if (likely(!link_congested(l_ptr))) { | 747 | msg_set_bcast_ack(msg, bc_last_in); |
| 788 | link_add_to_outqueue(l_ptr, buf, msg); | 748 | |
| 749 | if (!link->first_out) { | ||
| 750 | link->first_out = buf; | ||
| 751 | } else if (qsz < sndlim) { | ||
| 752 | link->last_out->next = buf; | ||
| 753 | } else if (tipc_msg_bundle(link->last_out, buf, mtu)) { | ||
| 754 | link->stats.sent_bundled++; | ||
| 755 | buf = next; | ||
| 756 | next = buf->next; | ||
| 757 | continue; | ||
| 758 | } else if (tipc_msg_make_bundle(&buf, mtu, link->addr)) { | ||
| 759 | link->stats.sent_bundled++; | ||
| 760 | link->stats.sent_bundles++; | ||
| 761 | link->last_out->next = buf; | ||
| 762 | if (!link->next_out) | ||
| 763 | link->next_out = buf; | ||
| 764 | } else { | ||
| 765 | link->last_out->next = buf; | ||
| 766 | if (!link->next_out) | ||
| 767 | link->next_out = buf; | ||
| 768 | } | ||
| 789 | 769 | ||
| 790 | tipc_bearer_send(l_ptr->bearer_id, buf, &l_ptr->media_addr); | 770 | /* Send packet if possible: */ |
| 791 | l_ptr->unacked_window = 0; | 771 | if (likely(++qsz <= sndlim)) { |
| 792 | return dsz; | 772 | tipc_bearer_send(link->bearer_id, buf, addr); |
| 793 | } | 773 | link->next_out = next; |
| 794 | /* Congestion: can message be bundled ? */ | 774 | link->unacked_window = 0; |
| 795 | if ((msg_user(msg) != CHANGEOVER_PROTOCOL) && | ||
| 796 | (msg_user(msg) != MSG_FRAGMENTER)) { | ||
| 797 | |||
| 798 | /* Try adding message to an existing bundle */ | ||
| 799 | if (l_ptr->next_out && | ||
| 800 | link_bundle_buf(l_ptr, l_ptr->last_out, buf)) | ||
| 801 | return dsz; | ||
| 802 | |||
| 803 | /* Try creating a new bundle */ | ||
| 804 | if (size <= max_packet * 2 / 3) { | ||
| 805 | struct sk_buff *bundler = tipc_buf_acquire(max_packet); | ||
| 806 | struct tipc_msg bundler_hdr; | ||
| 807 | |||
| 808 | if (bundler) { | ||
| 809 | tipc_msg_init(&bundler_hdr, MSG_BUNDLER, OPEN_MSG, | ||
| 810 | INT_H_SIZE, l_ptr->addr); | ||
| 811 | skb_copy_to_linear_data(bundler, &bundler_hdr, | ||
| 812 | INT_H_SIZE); | ||
| 813 | skb_trim(bundler, INT_H_SIZE); | ||
| 814 | link_bundle_buf(l_ptr, bundler, buf); | ||
| 815 | buf = bundler; | ||
| 816 | msg = buf_msg(buf); | ||
| 817 | l_ptr->stats.sent_bundles++; | ||
| 818 | } | ||
| 819 | } | 775 | } |
| 776 | seqno++; | ||
| 777 | link->last_out = buf; | ||
| 778 | buf = next; | ||
| 820 | } | 779 | } |
| 821 | if (!l_ptr->next_out) | 780 | link->next_out_no = seqno; |
| 822 | l_ptr->next_out = buf; | 781 | link->out_queue_size = qsz; |
| 823 | link_add_to_outqueue(l_ptr, buf, msg); | 782 | return 0; |
| 824 | return dsz; | ||
| 825 | } | 783 | } |
| 826 | 784 | ||
| 827 | /* | 785 | /** |
| 828 | * tipc_link_xmit(): same as __tipc_link_xmit(), but the link to use | 786 | * tipc_link_xmit() is the general link level function for message sending |
| 829 | * has not been selected yet, and the the owner node is not locked | 787 | * @buf: chain of buffers containing message |
| 830 | * Called by TIPC internal users, e.g. the name distributor | 788 | * @dsz: amount of user data to be sent |
| 789 | * @dnode: address of destination node | ||
| 790 | * @selector: a number used for deterministic link selection | ||
| 791 | * Consumes the buffer chain, except when returning -ELINKCONG | ||
| 792 | * Returns 0 if success, otherwise errno: -ELINKCONG,-EHOSTUNREACH,-EMSGSIZE | ||
| 831 | */ | 793 | */ |
| 832 | int tipc_link_xmit(struct sk_buff *buf, u32 dest, u32 selector) | 794 | int tipc_link_xmit(struct sk_buff *buf, u32 dnode, u32 selector) |
| 833 | { | 795 | { |
| 834 | struct tipc_link *l_ptr; | 796 | struct tipc_link *link = NULL; |
| 835 | struct tipc_node *n_ptr; | 797 | struct tipc_node *node; |
| 836 | int res = -ELINKCONG; | 798 | int rc = -EHOSTUNREACH; |
| 837 | 799 | ||
| 838 | n_ptr = tipc_node_find(dest); | 800 | node = tipc_node_find(dnode); |
| 839 | if (n_ptr) { | 801 | if (node) { |
| 840 | tipc_node_lock(n_ptr); | 802 | tipc_node_lock(node); |
| 841 | l_ptr = n_ptr->active_links[selector & 1]; | 803 | link = node->active_links[selector & 1]; |
| 842 | if (l_ptr) | 804 | if (link) |
| 843 | res = __tipc_link_xmit(l_ptr, buf); | 805 | rc = __tipc_link_xmit(link, buf); |
| 844 | else | 806 | tipc_node_unlock(node); |
| 845 | kfree_skb(buf); | ||
| 846 | tipc_node_unlock(n_ptr); | ||
| 847 | } else { | ||
| 848 | kfree_skb(buf); | ||
| 849 | } | 807 | } |
| 850 | return res; | 808 | |
| 809 | if (link) | ||
| 810 | return rc; | ||
| 811 | |||
| 812 | if (likely(in_own_node(dnode))) | ||
| 813 | return tipc_sk_rcv(buf); | ||
| 814 | |||
| 815 | kfree_skb_list(buf); | ||
| 816 | return rc; | ||
| 851 | } | 817 | } |
| 852 | 818 | ||
| 853 | /* | 819 | /* |
| @@ -858,7 +824,7 @@ int tipc_link_xmit(struct sk_buff *buf, u32 dest, u32 selector) | |||
| 858 | * | 824 | * |
| 859 | * Called with node locked | 825 | * Called with node locked |
| 860 | */ | 826 | */ |
| 861 | static void tipc_link_sync_xmit(struct tipc_link *l) | 827 | static void tipc_link_sync_xmit(struct tipc_link *link) |
| 862 | { | 828 | { |
| 863 | struct sk_buff *buf; | 829 | struct sk_buff *buf; |
| 864 | struct tipc_msg *msg; | 830 | struct tipc_msg *msg; |
| @@ -868,10 +834,9 @@ static void tipc_link_sync_xmit(struct tipc_link *l) | |||
| 868 | return; | 834 | return; |
| 869 | 835 | ||
| 870 | msg = buf_msg(buf); | 836 | msg = buf_msg(buf); |
| 871 | tipc_msg_init(msg, BCAST_PROTOCOL, STATE_MSG, INT_H_SIZE, l->addr); | 837 | tipc_msg_init(msg, BCAST_PROTOCOL, STATE_MSG, INT_H_SIZE, link->addr); |
| 872 | msg_set_last_bcast(msg, l->owner->bclink.acked); | 838 | msg_set_last_bcast(msg, link->owner->bclink.acked); |
| 873 | link_add_chain_to_outqueue(l, buf, 0); | 839 | __tipc_link_xmit(link, buf); |
| 874 | tipc_link_push_queue(l); | ||
| 875 | } | 840 | } |
| 876 | 841 | ||
| 877 | /* | 842 | /* |
| @@ -892,293 +857,6 @@ static void tipc_link_sync_rcv(struct tipc_node *n, struct sk_buff *buf) | |||
| 892 | } | 857 | } |
| 893 | 858 | ||
| 894 | /* | 859 | /* |
| 895 | * tipc_link_names_xmit - send name table entries to new neighbor | ||
| 896 | * | ||
| 897 | * Send routine for bulk delivery of name table messages when contact | ||
| 898 | * with a new neighbor occurs. No link congestion checking is performed | ||
| 899 | * because name table messages *must* be delivered. The messages must be | ||
| 900 | * small enough not to require fragmentation. | ||
| 901 | * Called without any locks held. | ||
| 902 | */ | ||
| 903 | void tipc_link_names_xmit(struct list_head *message_list, u32 dest) | ||
| 904 | { | ||
| 905 | struct tipc_node *n_ptr; | ||
| 906 | struct tipc_link *l_ptr; | ||
| 907 | struct sk_buff *buf; | ||
| 908 | struct sk_buff *temp_buf; | ||
| 909 | |||
| 910 | if (list_empty(message_list)) | ||
| 911 | return; | ||
| 912 | |||
| 913 | n_ptr = tipc_node_find(dest); | ||
| 914 | if (n_ptr) { | ||
| 915 | tipc_node_lock(n_ptr); | ||
| 916 | l_ptr = n_ptr->active_links[0]; | ||
| 917 | if (l_ptr) { | ||
| 918 | /* convert circular list to linear list */ | ||
| 919 | ((struct sk_buff *)message_list->prev)->next = NULL; | ||
| 920 | link_add_chain_to_outqueue(l_ptr, | ||
| 921 | (struct sk_buff *)message_list->next, 0); | ||
| 922 | tipc_link_push_queue(l_ptr); | ||
| 923 | INIT_LIST_HEAD(message_list); | ||
| 924 | } | ||
| 925 | tipc_node_unlock(n_ptr); | ||
| 926 | } | ||
| 927 | |||
| 928 | /* discard the messages if they couldn't be sent */ | ||
| 929 | list_for_each_safe(buf, temp_buf, ((struct sk_buff *)message_list)) { | ||
| 930 | list_del((struct list_head *)buf); | ||
| 931 | kfree_skb(buf); | ||
| 932 | } | ||
| 933 | } | ||
| 934 | |||
| 935 | /* | ||
| 936 | * tipc_link_xmit_fast: Entry for data messages where the | ||
| 937 | * destination link is known and the header is complete, | ||
| 938 | * inclusive total message length. Very time critical. | ||
| 939 | * Link is locked. Returns user data length. | ||
| 940 | */ | ||
| 941 | static int tipc_link_xmit_fast(struct tipc_link *l_ptr, struct sk_buff *buf, | ||
| 942 | u32 *used_max_pkt) | ||
| 943 | { | ||
| 944 | struct tipc_msg *msg = buf_msg(buf); | ||
| 945 | int res = msg_data_sz(msg); | ||
| 946 | |||
| 947 | if (likely(!link_congested(l_ptr))) { | ||
| 948 | if (likely(msg_size(msg) <= l_ptr->max_pkt)) { | ||
| 949 | link_add_to_outqueue(l_ptr, buf, msg); | ||
| 950 | tipc_bearer_send(l_ptr->bearer_id, buf, | ||
| 951 | &l_ptr->media_addr); | ||
| 952 | l_ptr->unacked_window = 0; | ||
| 953 | return res; | ||
| 954 | } | ||
| 955 | else | ||
| 956 | *used_max_pkt = l_ptr->max_pkt; | ||
| 957 | } | ||
| 958 | return __tipc_link_xmit(l_ptr, buf); /* All other cases */ | ||
| 959 | } | ||
| 960 | |||
| 961 | /* | ||
| 962 | * tipc_link_iovec_xmit_fast: Entry for messages where the | ||
| 963 | * destination processor is known and the header is complete, | ||
| 964 | * except for total message length. | ||
| 965 | * Returns user data length or errno. | ||
| 966 | */ | ||
| 967 | int tipc_link_iovec_xmit_fast(struct tipc_port *sender, | ||
| 968 | struct iovec const *msg_sect, | ||
| 969 | unsigned int len, u32 destaddr) | ||
| 970 | { | ||
| 971 | struct tipc_msg *hdr = &sender->phdr; | ||
| 972 | struct tipc_link *l_ptr; | ||
| 973 | struct sk_buff *buf; | ||
| 974 | struct tipc_node *node; | ||
| 975 | int res; | ||
| 976 | u32 selector = msg_origport(hdr) & 1; | ||
| 977 | |||
| 978 | again: | ||
| 979 | /* | ||
| 980 | * Try building message using port's max_pkt hint. | ||
| 981 | * (Must not hold any locks while building message.) | ||
| 982 | */ | ||
| 983 | res = tipc_msg_build(hdr, msg_sect, len, sender->max_pkt, &buf); | ||
| 984 | /* Exit if build request was invalid */ | ||
| 985 | if (unlikely(res < 0)) | ||
| 986 | return res; | ||
| 987 | |||
| 988 | node = tipc_node_find(destaddr); | ||
| 989 | if (likely(node)) { | ||
| 990 | tipc_node_lock(node); | ||
| 991 | l_ptr = node->active_links[selector]; | ||
| 992 | if (likely(l_ptr)) { | ||
| 993 | if (likely(buf)) { | ||
| 994 | res = tipc_link_xmit_fast(l_ptr, buf, | ||
| 995 | &sender->max_pkt); | ||
| 996 | exit: | ||
| 997 | tipc_node_unlock(node); | ||
| 998 | return res; | ||
| 999 | } | ||
| 1000 | |||
| 1001 | /* Exit if link (or bearer) is congested */ | ||
| 1002 | if (link_congested(l_ptr)) { | ||
| 1003 | res = link_schedule_port(l_ptr, | ||
| 1004 | sender->ref, res); | ||
| 1005 | goto exit; | ||
| 1006 | } | ||
| 1007 | |||
| 1008 | /* | ||
| 1009 | * Message size exceeds max_pkt hint; update hint, | ||
| 1010 | * then re-try fast path or fragment the message | ||
| 1011 | */ | ||
| 1012 | sender->max_pkt = l_ptr->max_pkt; | ||
| 1013 | tipc_node_unlock(node); | ||
| 1014 | |||
| 1015 | |||
| 1016 | if ((msg_hdr_sz(hdr) + res) <= sender->max_pkt) | ||
| 1017 | goto again; | ||
| 1018 | |||
| 1019 | return tipc_link_iovec_long_xmit(sender, msg_sect, | ||
| 1020 | len, destaddr); | ||
| 1021 | } | ||
| 1022 | tipc_node_unlock(node); | ||
| 1023 | } | ||
| 1024 | |||
| 1025 | /* Couldn't find a link to the destination node */ | ||
| 1026 | kfree_skb(buf); | ||
| 1027 | tipc_port_iovec_reject(sender, hdr, msg_sect, len, TIPC_ERR_NO_NODE); | ||
| 1028 | return -ENETUNREACH; | ||
| 1029 | } | ||
| 1030 | |||
| 1031 | /* | ||
| 1032 | * tipc_link_iovec_long_xmit(): Entry for long messages where the | ||
| 1033 | * destination node is known and the header is complete, | ||
| 1034 | * inclusive total message length. | ||
| 1035 | * Link and bearer congestion status have been checked to be ok, | ||
| 1036 | * and are ignored if they change. | ||
| 1037 | * | ||
| 1038 | * Note that fragments do not use the full link MTU so that they won't have | ||
| 1039 | * to undergo refragmentation if link changeover causes them to be sent | ||
| 1040 | * over another link with an additional tunnel header added as prefix. | ||
| 1041 | * (Refragmentation will still occur if the other link has a smaller MTU.) | ||
| 1042 | * | ||
| 1043 | * Returns user data length or errno. | ||
| 1044 | */ | ||
| 1045 | static int tipc_link_iovec_long_xmit(struct tipc_port *sender, | ||
| 1046 | struct iovec const *msg_sect, | ||
| 1047 | unsigned int len, u32 destaddr) | ||
| 1048 | { | ||
| 1049 | struct tipc_link *l_ptr; | ||
| 1050 | struct tipc_node *node; | ||
| 1051 | struct tipc_msg *hdr = &sender->phdr; | ||
| 1052 | u32 dsz = len; | ||
| 1053 | u32 max_pkt, fragm_sz, rest; | ||
| 1054 | struct tipc_msg fragm_hdr; | ||
| 1055 | struct sk_buff *buf, *buf_chain, *prev; | ||
| 1056 | u32 fragm_crs, fragm_rest, hsz, sect_rest; | ||
| 1057 | const unchar __user *sect_crs; | ||
| 1058 | int curr_sect; | ||
| 1059 | u32 fragm_no; | ||
| 1060 | int res = 0; | ||
| 1061 | |||
| 1062 | again: | ||
| 1063 | fragm_no = 1; | ||
| 1064 | max_pkt = sender->max_pkt - INT_H_SIZE; | ||
| 1065 | /* leave room for tunnel header in case of link changeover */ | ||
| 1066 | fragm_sz = max_pkt - INT_H_SIZE; | ||
| 1067 | /* leave room for fragmentation header in each fragment */ | ||
| 1068 | rest = dsz; | ||
| 1069 | fragm_crs = 0; | ||
| 1070 | fragm_rest = 0; | ||
| 1071 | sect_rest = 0; | ||
| 1072 | sect_crs = NULL; | ||
| 1073 | curr_sect = -1; | ||
| 1074 | |||
| 1075 | /* Prepare reusable fragment header */ | ||
| 1076 | tipc_msg_init(&fragm_hdr, MSG_FRAGMENTER, FIRST_FRAGMENT, | ||
| 1077 | INT_H_SIZE, msg_destnode(hdr)); | ||
| 1078 | msg_set_size(&fragm_hdr, max_pkt); | ||
| 1079 | msg_set_fragm_no(&fragm_hdr, 1); | ||
| 1080 | |||
| 1081 | /* Prepare header of first fragment */ | ||
| 1082 | buf_chain = buf = tipc_buf_acquire(max_pkt); | ||
| 1083 | if (!buf) | ||
| 1084 | return -ENOMEM; | ||
| 1085 | buf->next = NULL; | ||
| 1086 | skb_copy_to_linear_data(buf, &fragm_hdr, INT_H_SIZE); | ||
| 1087 | hsz = msg_hdr_sz(hdr); | ||
| 1088 | skb_copy_to_linear_data_offset(buf, INT_H_SIZE, hdr, hsz); | ||
| 1089 | |||
| 1090 | /* Chop up message */ | ||
| 1091 | fragm_crs = INT_H_SIZE + hsz; | ||
| 1092 | fragm_rest = fragm_sz - hsz; | ||
| 1093 | |||
| 1094 | do { /* For all sections */ | ||
| 1095 | u32 sz; | ||
| 1096 | |||
| 1097 | if (!sect_rest) { | ||
| 1098 | sect_rest = msg_sect[++curr_sect].iov_len; | ||
| 1099 | sect_crs = msg_sect[curr_sect].iov_base; | ||
| 1100 | } | ||
| 1101 | |||
| 1102 | if (sect_rest < fragm_rest) | ||
| 1103 | sz = sect_rest; | ||
| 1104 | else | ||
| 1105 | sz = fragm_rest; | ||
| 1106 | |||
| 1107 | if (copy_from_user(buf->data + fragm_crs, sect_crs, sz)) { | ||
| 1108 | res = -EFAULT; | ||
| 1109 | error: | ||
| 1110 | kfree_skb_list(buf_chain); | ||
| 1111 | return res; | ||
| 1112 | } | ||
| 1113 | sect_crs += sz; | ||
| 1114 | sect_rest -= sz; | ||
| 1115 | fragm_crs += sz; | ||
| 1116 | fragm_rest -= sz; | ||
| 1117 | rest -= sz; | ||
| 1118 | |||
| 1119 | if (!fragm_rest && rest) { | ||
| 1120 | |||
| 1121 | /* Initiate new fragment: */ | ||
| 1122 | if (rest <= fragm_sz) { | ||
| 1123 | fragm_sz = rest; | ||
| 1124 | msg_set_type(&fragm_hdr, LAST_FRAGMENT); | ||
| 1125 | } else { | ||
| 1126 | msg_set_type(&fragm_hdr, FRAGMENT); | ||
| 1127 | } | ||
| 1128 | msg_set_size(&fragm_hdr, fragm_sz + INT_H_SIZE); | ||
| 1129 | msg_set_fragm_no(&fragm_hdr, ++fragm_no); | ||
| 1130 | prev = buf; | ||
| 1131 | buf = tipc_buf_acquire(fragm_sz + INT_H_SIZE); | ||
| 1132 | if (!buf) { | ||
| 1133 | res = -ENOMEM; | ||
| 1134 | goto error; | ||
| 1135 | } | ||
| 1136 | |||
| 1137 | buf->next = NULL; | ||
| 1138 | prev->next = buf; | ||
| 1139 | skb_copy_to_linear_data(buf, &fragm_hdr, INT_H_SIZE); | ||
| 1140 | fragm_crs = INT_H_SIZE; | ||
| 1141 | fragm_rest = fragm_sz; | ||
| 1142 | } | ||
| 1143 | } while (rest > 0); | ||
| 1144 | |||
| 1145 | /* | ||
| 1146 | * Now we have a buffer chain. Select a link and check | ||
| 1147 | * that packet size is still OK | ||
| 1148 | */ | ||
| 1149 | node = tipc_node_find(destaddr); | ||
| 1150 | if (likely(node)) { | ||
| 1151 | tipc_node_lock(node); | ||
| 1152 | l_ptr = node->active_links[sender->ref & 1]; | ||
| 1153 | if (!l_ptr) { | ||
| 1154 | tipc_node_unlock(node); | ||
| 1155 | goto reject; | ||
| 1156 | } | ||
| 1157 | if (l_ptr->max_pkt < max_pkt) { | ||
| 1158 | sender->max_pkt = l_ptr->max_pkt; | ||
| 1159 | tipc_node_unlock(node); | ||
| 1160 | kfree_skb_list(buf_chain); | ||
| 1161 | goto again; | ||
| 1162 | } | ||
| 1163 | } else { | ||
| 1164 | reject: | ||
| 1165 | kfree_skb_list(buf_chain); | ||
| 1166 | tipc_port_iovec_reject(sender, hdr, msg_sect, len, | ||
| 1167 | TIPC_ERR_NO_NODE); | ||
| 1168 | return -ENETUNREACH; | ||
| 1169 | } | ||
| 1170 | |||
| 1171 | /* Append chain of fragments to send queue & send them */ | ||
| 1172 | l_ptr->long_msg_seq_no++; | ||
| 1173 | link_add_chain_to_outqueue(l_ptr, buf_chain, l_ptr->long_msg_seq_no); | ||
| 1174 | l_ptr->stats.sent_fragments += fragm_no; | ||
| 1175 | l_ptr->stats.sent_fragmented++; | ||
| 1176 | tipc_link_push_queue(l_ptr); | ||
| 1177 | tipc_node_unlock(node); | ||
| 1178 | return dsz; | ||
| 1179 | } | ||
| 1180 | |||
| 1181 | /* | ||
| 1182 | * tipc_link_push_packet: Push one unsent packet to the media | 860 | * tipc_link_push_packet: Push one unsent packet to the media |
| 1183 | */ | 861 | */ |
| 1184 | static u32 tipc_link_push_packet(struct tipc_link *l_ptr) | 862 | static u32 tipc_link_push_packet(struct tipc_link *l_ptr) |
| @@ -1238,7 +916,7 @@ static u32 tipc_link_push_packet(struct tipc_link *l_ptr) | |||
| 1238 | tipc_bearer_send(l_ptr->bearer_id, buf, | 916 | tipc_bearer_send(l_ptr->bearer_id, buf, |
| 1239 | &l_ptr->media_addr); | 917 | &l_ptr->media_addr); |
| 1240 | if (msg_user(msg) == MSG_BUNDLER) | 918 | if (msg_user(msg) == MSG_BUNDLER) |
| 1241 | msg_set_type(msg, CLOSED_MSG); | 919 | msg_set_type(msg, BUNDLE_CLOSED); |
| 1242 | l_ptr->next_out = buf->next; | 920 | l_ptr->next_out = buf->next; |
| 1243 | return 0; | 921 | return 0; |
| 1244 | } | 922 | } |
| @@ -1527,11 +1205,6 @@ void tipc_rcv(struct sk_buff *head, struct tipc_bearer *b_ptr) | |||
| 1527 | if (unlikely(!list_empty(&l_ptr->waiting_ports))) | 1205 | if (unlikely(!list_empty(&l_ptr->waiting_ports))) |
| 1528 | tipc_link_wakeup_ports(l_ptr, 0); | 1206 | tipc_link_wakeup_ports(l_ptr, 0); |
| 1529 | 1207 | ||
| 1530 | if (unlikely(++l_ptr->unacked_window >= TIPC_MIN_LINK_WIN)) { | ||
| 1531 | l_ptr->stats.sent_acks++; | ||
| 1532 | tipc_link_proto_xmit(l_ptr, STATE_MSG, 0, 0, 0, 0, 0); | ||
| 1533 | } | ||
| 1534 | |||
| 1535 | /* Process the incoming packet */ | 1208 | /* Process the incoming packet */ |
| 1536 | if (unlikely(!link_working_working(l_ptr))) { | 1209 | if (unlikely(!link_working_working(l_ptr))) { |
| 1537 | if (msg_user(msg) == LINK_PROTOCOL) { | 1210 | if (msg_user(msg) == LINK_PROTOCOL) { |
| @@ -1565,57 +1238,19 @@ void tipc_rcv(struct sk_buff *head, struct tipc_bearer *b_ptr) | |||
| 1565 | if (unlikely(l_ptr->oldest_deferred_in)) | 1238 | if (unlikely(l_ptr->oldest_deferred_in)) |
| 1566 | head = link_insert_deferred_queue(l_ptr, head); | 1239 | head = link_insert_deferred_queue(l_ptr, head); |
| 1567 | 1240 | ||
| 1568 | /* Deliver packet/message to correct user: */ | 1241 | if (unlikely(++l_ptr->unacked_window >= TIPC_MIN_LINK_WIN)) { |
| 1569 | if (unlikely(msg_user(msg) == CHANGEOVER_PROTOCOL)) { | 1242 | l_ptr->stats.sent_acks++; |
| 1570 | if (!tipc_link_tunnel_rcv(n_ptr, &buf)) { | 1243 | tipc_link_proto_xmit(l_ptr, STATE_MSG, 0, 0, 0, 0, 0); |
| 1571 | tipc_node_unlock(n_ptr); | ||
| 1572 | continue; | ||
| 1573 | } | ||
| 1574 | msg = buf_msg(buf); | ||
| 1575 | } else if (msg_user(msg) == MSG_FRAGMENTER) { | ||
| 1576 | l_ptr->stats.recv_fragments++; | ||
| 1577 | if (tipc_buf_append(&l_ptr->reasm_buf, &buf)) { | ||
| 1578 | l_ptr->stats.recv_fragmented++; | ||
| 1579 | msg = buf_msg(buf); | ||
| 1580 | } else { | ||
| 1581 | if (!l_ptr->reasm_buf) | ||
| 1582 | tipc_link_reset(l_ptr); | ||
| 1583 | tipc_node_unlock(n_ptr); | ||
| 1584 | continue; | ||
| 1585 | } | ||
| 1586 | } | 1244 | } |
| 1587 | 1245 | ||
| 1588 | switch (msg_user(msg)) { | 1246 | if (tipc_link_prepare_input(l_ptr, &buf)) { |
| 1589 | case TIPC_LOW_IMPORTANCE: | ||
| 1590 | case TIPC_MEDIUM_IMPORTANCE: | ||
| 1591 | case TIPC_HIGH_IMPORTANCE: | ||
| 1592 | case TIPC_CRITICAL_IMPORTANCE: | ||
| 1593 | tipc_node_unlock(n_ptr); | 1247 | tipc_node_unlock(n_ptr); |
| 1594 | tipc_sk_rcv(buf); | ||
| 1595 | continue; | 1248 | continue; |
| 1596 | case MSG_BUNDLER: | ||
| 1597 | l_ptr->stats.recv_bundles++; | ||
| 1598 | l_ptr->stats.recv_bundled += msg_msgcnt(msg); | ||
| 1599 | tipc_node_unlock(n_ptr); | ||
| 1600 | tipc_link_bundle_rcv(buf); | ||
| 1601 | continue; | ||
| 1602 | case NAME_DISTRIBUTOR: | ||
| 1603 | n_ptr->bclink.recv_permitted = true; | ||
| 1604 | tipc_node_unlock(n_ptr); | ||
| 1605 | tipc_named_rcv(buf); | ||
| 1606 | continue; | ||
| 1607 | case CONN_MANAGER: | ||
| 1608 | tipc_node_unlock(n_ptr); | ||
| 1609 | tipc_port_proto_rcv(buf); | ||
| 1610 | continue; | ||
| 1611 | case BCAST_PROTOCOL: | ||
| 1612 | tipc_link_sync_rcv(n_ptr, buf); | ||
| 1613 | break; | ||
| 1614 | default: | ||
| 1615 | kfree_skb(buf); | ||
| 1616 | break; | ||
| 1617 | } | 1249 | } |
| 1618 | tipc_node_unlock(n_ptr); | 1250 | tipc_node_unlock(n_ptr); |
| 1251 | msg = buf_msg(buf); | ||
| 1252 | if (tipc_link_input(l_ptr, buf) != 0) | ||
| 1253 | goto discard; | ||
| 1619 | continue; | 1254 | continue; |
| 1620 | unlock_discard: | 1255 | unlock_discard: |
| 1621 | tipc_node_unlock(n_ptr); | 1256 | tipc_node_unlock(n_ptr); |
| @@ -1625,6 +1260,80 @@ discard: | |||
| 1625 | } | 1260 | } |
| 1626 | 1261 | ||
| 1627 | /** | 1262 | /** |
| 1263 | * tipc_link_prepare_input - process TIPC link messages | ||
| 1264 | * | ||
| 1265 | * returns nonzero if the message was consumed | ||
| 1266 | * | ||
| 1267 | * Node lock must be held | ||
| 1268 | */ | ||
| 1269 | static int tipc_link_prepare_input(struct tipc_link *l, struct sk_buff **buf) | ||
| 1270 | { | ||
| 1271 | struct tipc_node *n; | ||
| 1272 | struct tipc_msg *msg; | ||
| 1273 | int res = -EINVAL; | ||
| 1274 | |||
| 1275 | n = l->owner; | ||
| 1276 | msg = buf_msg(*buf); | ||
| 1277 | switch (msg_user(msg)) { | ||
| 1278 | case CHANGEOVER_PROTOCOL: | ||
| 1279 | if (tipc_link_tunnel_rcv(n, buf)) | ||
| 1280 | res = 0; | ||
| 1281 | break; | ||
| 1282 | case MSG_FRAGMENTER: | ||
| 1283 | l->stats.recv_fragments++; | ||
| 1284 | if (tipc_buf_append(&l->reasm_buf, buf)) { | ||
| 1285 | l->stats.recv_fragmented++; | ||
| 1286 | res = 0; | ||
| 1287 | } else if (!l->reasm_buf) { | ||
| 1288 | tipc_link_reset(l); | ||
| 1289 | } | ||
| 1290 | break; | ||
| 1291 | case MSG_BUNDLER: | ||
| 1292 | l->stats.recv_bundles++; | ||
| 1293 | l->stats.recv_bundled += msg_msgcnt(msg); | ||
| 1294 | res = 0; | ||
| 1295 | break; | ||
| 1296 | case NAME_DISTRIBUTOR: | ||
| 1297 | n->bclink.recv_permitted = true; | ||
| 1298 | res = 0; | ||
| 1299 | break; | ||
| 1300 | case BCAST_PROTOCOL: | ||
| 1301 | tipc_link_sync_rcv(n, *buf); | ||
| 1302 | break; | ||
| 1303 | default: | ||
| 1304 | res = 0; | ||
| 1305 | } | ||
| 1306 | return res; | ||
| 1307 | } | ||
| 1308 | /** | ||
| 1309 | * tipc_link_input - Deliver message too higher layers | ||
| 1310 | */ | ||
| 1311 | static int tipc_link_input(struct tipc_link *l, struct sk_buff *buf) | ||
| 1312 | { | ||
| 1313 | struct tipc_msg *msg = buf_msg(buf); | ||
| 1314 | int res = 0; | ||
| 1315 | |||
| 1316 | switch (msg_user(msg)) { | ||
| 1317 | case TIPC_LOW_IMPORTANCE: | ||
| 1318 | case TIPC_MEDIUM_IMPORTANCE: | ||
| 1319 | case TIPC_HIGH_IMPORTANCE: | ||
| 1320 | case TIPC_CRITICAL_IMPORTANCE: | ||
| 1321 | case CONN_MANAGER: | ||
| 1322 | tipc_sk_rcv(buf); | ||
| 1323 | break; | ||
| 1324 | case NAME_DISTRIBUTOR: | ||
| 1325 | tipc_named_rcv(buf); | ||
| 1326 | break; | ||
| 1327 | case MSG_BUNDLER: | ||
| 1328 | tipc_link_bundle_rcv(buf); | ||
| 1329 | break; | ||
| 1330 | default: | ||
| 1331 | res = -EINVAL; | ||
| 1332 | } | ||
| 1333 | return res; | ||
| 1334 | } | ||
| 1335 | |||
| 1336 | /** | ||
| 1628 | * tipc_link_defer_pkt - Add out-of-sequence message to deferred reception queue | 1337 | * tipc_link_defer_pkt - Add out-of-sequence message to deferred reception queue |
| 1629 | * | 1338 | * |
| 1630 | * Returns increase in queue length (i.e. 0 or 1) | 1339 | * Returns increase in queue length (i.e. 0 or 1) |
| @@ -2217,6 +1926,7 @@ void tipc_link_bundle_rcv(struct sk_buff *buf) | |||
| 2217 | u32 msgcount = msg_msgcnt(buf_msg(buf)); | 1926 | u32 msgcount = msg_msgcnt(buf_msg(buf)); |
| 2218 | u32 pos = INT_H_SIZE; | 1927 | u32 pos = INT_H_SIZE; |
| 2219 | struct sk_buff *obuf; | 1928 | struct sk_buff *obuf; |
| 1929 | struct tipc_msg *omsg; | ||
| 2220 | 1930 | ||
| 2221 | while (msgcount--) { | 1931 | while (msgcount--) { |
| 2222 | obuf = buf_extract(buf, pos); | 1932 | obuf = buf_extract(buf, pos); |
| @@ -2224,82 +1934,18 @@ void tipc_link_bundle_rcv(struct sk_buff *buf) | |||
| 2224 | pr_warn("Link unable to unbundle message(s)\n"); | 1934 | pr_warn("Link unable to unbundle message(s)\n"); |
| 2225 | break; | 1935 | break; |
| 2226 | } | 1936 | } |
| 2227 | pos += align(msg_size(buf_msg(obuf))); | 1937 | omsg = buf_msg(obuf); |
| 2228 | tipc_net_route_msg(obuf); | 1938 | pos += align(msg_size(omsg)); |
| 2229 | } | 1939 | if (msg_isdata(omsg) || (msg_user(omsg) == CONN_MANAGER)) { |
| 2230 | kfree_skb(buf); | 1940 | tipc_sk_rcv(obuf); |
| 2231 | } | 1941 | } else if (msg_user(omsg) == NAME_DISTRIBUTOR) { |
| 2232 | 1942 | tipc_named_rcv(obuf); | |
| 2233 | /* | 1943 | } else { |
| 2234 | * Fragmentation/defragmentation: | 1944 | pr_warn("Illegal bundled msg: %u\n", msg_user(omsg)); |
| 2235 | */ | 1945 | kfree_skb(obuf); |
| 2236 | |||
| 2237 | /* | ||
| 2238 | * tipc_link_frag_xmit: Entry for buffers needing fragmentation. | ||
| 2239 | * The buffer is complete, inclusive total message length. | ||
| 2240 | * Returns user data length. | ||
| 2241 | */ | ||
| 2242 | static int tipc_link_frag_xmit(struct tipc_link *l_ptr, struct sk_buff *buf) | ||
| 2243 | { | ||
| 2244 | struct sk_buff *buf_chain = NULL; | ||
| 2245 | struct sk_buff *buf_chain_tail = (struct sk_buff *)&buf_chain; | ||
| 2246 | struct tipc_msg *inmsg = buf_msg(buf); | ||
| 2247 | struct tipc_msg fragm_hdr; | ||
| 2248 | u32 insize = msg_size(inmsg); | ||
| 2249 | u32 dsz = msg_data_sz(inmsg); | ||
| 2250 | unchar *crs = buf->data; | ||
| 2251 | u32 rest = insize; | ||
| 2252 | u32 pack_sz = l_ptr->max_pkt; | ||
| 2253 | u32 fragm_sz = pack_sz - INT_H_SIZE; | ||
| 2254 | u32 fragm_no = 0; | ||
| 2255 | u32 destaddr; | ||
| 2256 | |||
| 2257 | if (msg_short(inmsg)) | ||
| 2258 | destaddr = l_ptr->addr; | ||
| 2259 | else | ||
| 2260 | destaddr = msg_destnode(inmsg); | ||
| 2261 | |||
| 2262 | /* Prepare reusable fragment header: */ | ||
| 2263 | tipc_msg_init(&fragm_hdr, MSG_FRAGMENTER, FIRST_FRAGMENT, | ||
| 2264 | INT_H_SIZE, destaddr); | ||
| 2265 | |||
| 2266 | /* Chop up message: */ | ||
| 2267 | while (rest > 0) { | ||
| 2268 | struct sk_buff *fragm; | ||
| 2269 | |||
| 2270 | if (rest <= fragm_sz) { | ||
| 2271 | fragm_sz = rest; | ||
| 2272 | msg_set_type(&fragm_hdr, LAST_FRAGMENT); | ||
| 2273 | } | ||
| 2274 | fragm = tipc_buf_acquire(fragm_sz + INT_H_SIZE); | ||
| 2275 | if (fragm == NULL) { | ||
| 2276 | kfree_skb(buf); | ||
| 2277 | kfree_skb_list(buf_chain); | ||
| 2278 | return -ENOMEM; | ||
| 2279 | } | 1946 | } |
| 2280 | msg_set_size(&fragm_hdr, fragm_sz + INT_H_SIZE); | ||
| 2281 | fragm_no++; | ||
| 2282 | msg_set_fragm_no(&fragm_hdr, fragm_no); | ||
| 2283 | skb_copy_to_linear_data(fragm, &fragm_hdr, INT_H_SIZE); | ||
| 2284 | skb_copy_to_linear_data_offset(fragm, INT_H_SIZE, crs, | ||
| 2285 | fragm_sz); | ||
| 2286 | buf_chain_tail->next = fragm; | ||
| 2287 | buf_chain_tail = fragm; | ||
| 2288 | |||
| 2289 | rest -= fragm_sz; | ||
| 2290 | crs += fragm_sz; | ||
| 2291 | msg_set_type(&fragm_hdr, FRAGMENT); | ||
| 2292 | } | 1947 | } |
| 2293 | kfree_skb(buf); | 1948 | kfree_skb(buf); |
| 2294 | |||
| 2295 | /* Append chain of fragments to send queue & send them */ | ||
| 2296 | l_ptr->long_msg_seq_no++; | ||
| 2297 | link_add_chain_to_outqueue(l_ptr, buf_chain, l_ptr->long_msg_seq_no); | ||
| 2298 | l_ptr->stats.sent_fragments += fragm_no; | ||
| 2299 | l_ptr->stats.sent_fragmented++; | ||
| 2300 | tipc_link_push_queue(l_ptr); | ||
| 2301 | |||
| 2302 | return dsz; | ||
| 2303 | } | 1949 | } |
| 2304 | 1950 | ||
| 2305 | static void link_set_supervision_props(struct tipc_link *l_ptr, u32 tolerance) | 1951 | static void link_set_supervision_props(struct tipc_link *l_ptr, u32 tolerance) |
diff --git a/net/tipc/link.h b/net/tipc/link.h index 200d518b218e..782983ccd323 100644 --- a/net/tipc/link.h +++ b/net/tipc/link.h | |||
| @@ -227,13 +227,8 @@ void tipc_link_reset_all(struct tipc_node *node); | |||
| 227 | void tipc_link_reset(struct tipc_link *l_ptr); | 227 | void tipc_link_reset(struct tipc_link *l_ptr); |
| 228 | void tipc_link_reset_list(unsigned int bearer_id); | 228 | void tipc_link_reset_list(unsigned int bearer_id); |
| 229 | int tipc_link_xmit(struct sk_buff *buf, u32 dest, u32 selector); | 229 | int tipc_link_xmit(struct sk_buff *buf, u32 dest, u32 selector); |
| 230 | void tipc_link_names_xmit(struct list_head *message_list, u32 dest); | 230 | int __tipc_link_xmit(struct tipc_link *link, struct sk_buff *buf); |
| 231 | int __tipc_link_xmit(struct tipc_link *l_ptr, struct sk_buff *buf); | ||
| 232 | int tipc_link_send_buf(struct tipc_link *l_ptr, struct sk_buff *buf); | ||
| 233 | u32 tipc_link_get_max_pkt(u32 dest, u32 selector); | 231 | u32 tipc_link_get_max_pkt(u32 dest, u32 selector); |
| 234 | int tipc_link_iovec_xmit_fast(struct tipc_port *sender, | ||
| 235 | struct iovec const *msg_sect, | ||
| 236 | unsigned int len, u32 destnode); | ||
| 237 | void tipc_link_bundle_rcv(struct sk_buff *buf); | 232 | void tipc_link_bundle_rcv(struct sk_buff *buf); |
| 238 | void tipc_link_proto_xmit(struct tipc_link *l_ptr, u32 msg_typ, int prob, | 233 | void tipc_link_proto_xmit(struct tipc_link *l_ptr, u32 msg_typ, int prob, |
| 239 | u32 gap, u32 tolerance, u32 priority, u32 acked_mtu); | 234 | u32 gap, u32 tolerance, u32 priority, u32 acked_mtu); |
diff --git a/net/tipc/msg.c b/net/tipc/msg.c index 0a37a472c29f..9680be6d388a 100644 --- a/net/tipc/msg.c +++ b/net/tipc/msg.c | |||
| @@ -36,21 +36,16 @@ | |||
| 36 | 36 | ||
| 37 | #include "core.h" | 37 | #include "core.h" |
| 38 | #include "msg.h" | 38 | #include "msg.h" |
| 39 | #include "addr.h" | ||
| 40 | #include "name_table.h" | ||
| 39 | 41 | ||
| 40 | u32 tipc_msg_tot_importance(struct tipc_msg *m) | 42 | #define MAX_FORWARD_SIZE 1024 |
| 43 | |||
| 44 | static unsigned int align(unsigned int i) | ||
| 41 | { | 45 | { |
| 42 | if (likely(msg_isdata(m))) { | 46 | return (i + 3) & ~3u; |
| 43 | if (likely(msg_orignode(m) == tipc_own_addr)) | ||
| 44 | return msg_importance(m); | ||
| 45 | return msg_importance(m) + 4; | ||
| 46 | } | ||
| 47 | if ((msg_user(m) == MSG_FRAGMENTER) && | ||
| 48 | (msg_type(m) == FIRST_FRAGMENT)) | ||
| 49 | return msg_importance(msg_get_wrapped(m)); | ||
| 50 | return msg_importance(m); | ||
| 51 | } | 47 | } |
| 52 | 48 | ||
| 53 | |||
| 54 | void tipc_msg_init(struct tipc_msg *m, u32 user, u32 type, u32 hsize, | 49 | void tipc_msg_init(struct tipc_msg *m, u32 user, u32 type, u32 hsize, |
| 55 | u32 destnode) | 50 | u32 destnode) |
| 56 | { | 51 | { |
| @@ -65,41 +60,6 @@ void tipc_msg_init(struct tipc_msg *m, u32 user, u32 type, u32 hsize, | |||
| 65 | msg_set_destnode(m, destnode); | 60 | msg_set_destnode(m, destnode); |
| 66 | } | 61 | } |
| 67 | 62 | ||
| 68 | /** | ||
| 69 | * tipc_msg_build - create message using specified header and data | ||
| 70 | * | ||
| 71 | * Note: Caller must not hold any locks in case copy_from_user() is interrupted! | ||
| 72 | * | ||
| 73 | * Returns message data size or errno | ||
| 74 | */ | ||
| 75 | int tipc_msg_build(struct tipc_msg *hdr, struct iovec const *msg_sect, | ||
| 76 | unsigned int len, int max_size, struct sk_buff **buf) | ||
| 77 | { | ||
| 78 | int dsz, sz, hsz; | ||
| 79 | unsigned char *to; | ||
| 80 | |||
| 81 | dsz = len; | ||
| 82 | hsz = msg_hdr_sz(hdr); | ||
| 83 | sz = hsz + dsz; | ||
| 84 | msg_set_size(hdr, sz); | ||
| 85 | if (unlikely(sz > max_size)) { | ||
| 86 | *buf = NULL; | ||
| 87 | return dsz; | ||
| 88 | } | ||
| 89 | |||
| 90 | *buf = tipc_buf_acquire(sz); | ||
| 91 | if (!(*buf)) | ||
| 92 | return -ENOMEM; | ||
| 93 | skb_copy_to_linear_data(*buf, hdr, hsz); | ||
| 94 | to = (*buf)->data + hsz; | ||
| 95 | if (len && memcpy_fromiovecend(to, msg_sect, 0, dsz)) { | ||
| 96 | kfree_skb(*buf); | ||
| 97 | *buf = NULL; | ||
| 98 | return -EFAULT; | ||
| 99 | } | ||
| 100 | return dsz; | ||
| 101 | } | ||
| 102 | |||
| 103 | /* tipc_buf_append(): Append a buffer to the fragment list of another buffer | 63 | /* tipc_buf_append(): Append a buffer to the fragment list of another buffer |
| 104 | * @*headbuf: in: NULL for first frag, otherwise value returned from prev call | 64 | * @*headbuf: in: NULL for first frag, otherwise value returned from prev call |
| 105 | * out: set when successful non-complete reassembly, otherwise NULL | 65 | * out: set when successful non-complete reassembly, otherwise NULL |
| @@ -112,27 +72,38 @@ int tipc_buf_append(struct sk_buff **headbuf, struct sk_buff **buf) | |||
| 112 | struct sk_buff *head = *headbuf; | 72 | struct sk_buff *head = *headbuf; |
| 113 | struct sk_buff *frag = *buf; | 73 | struct sk_buff *frag = *buf; |
| 114 | struct sk_buff *tail; | 74 | struct sk_buff *tail; |
| 115 | struct tipc_msg *msg = buf_msg(frag); | 75 | struct tipc_msg *msg; |
| 116 | u32 fragid = msg_type(msg); | 76 | u32 fragid; |
| 117 | bool headstolen; | ||
| 118 | int delta; | 77 | int delta; |
| 78 | bool headstolen; | ||
| 119 | 79 | ||
| 80 | if (!frag) | ||
| 81 | goto err; | ||
| 82 | |||
| 83 | msg = buf_msg(frag); | ||
| 84 | fragid = msg_type(msg); | ||
| 85 | frag->next = NULL; | ||
| 120 | skb_pull(frag, msg_hdr_sz(msg)); | 86 | skb_pull(frag, msg_hdr_sz(msg)); |
| 121 | 87 | ||
| 122 | if (fragid == FIRST_FRAGMENT) { | 88 | if (fragid == FIRST_FRAGMENT) { |
| 123 | if (head || skb_unclone(frag, GFP_ATOMIC)) | 89 | if (unlikely(head)) |
| 124 | goto out_free; | 90 | goto err; |
| 91 | if (unlikely(skb_unclone(frag, GFP_ATOMIC))) | ||
| 92 | goto err; | ||
| 125 | head = *headbuf = frag; | 93 | head = *headbuf = frag; |
| 126 | skb_frag_list_init(head); | 94 | skb_frag_list_init(head); |
| 95 | TIPC_SKB_CB(head)->tail = NULL; | ||
| 127 | *buf = NULL; | 96 | *buf = NULL; |
| 128 | return 0; | 97 | return 0; |
| 129 | } | 98 | } |
| 99 | |||
| 130 | if (!head) | 100 | if (!head) |
| 131 | goto out_free; | 101 | goto err; |
| 132 | tail = TIPC_SKB_CB(head)->tail; | 102 | |
| 133 | if (skb_try_coalesce(head, frag, &headstolen, &delta)) { | 103 | if (skb_try_coalesce(head, frag, &headstolen, &delta)) { |
| 134 | kfree_skb_partial(frag, headstolen); | 104 | kfree_skb_partial(frag, headstolen); |
| 135 | } else { | 105 | } else { |
| 106 | tail = TIPC_SKB_CB(head)->tail; | ||
| 136 | if (!skb_has_frag_list(head)) | 107 | if (!skb_has_frag_list(head)) |
| 137 | skb_shinfo(head)->frag_list = frag; | 108 | skb_shinfo(head)->frag_list = frag; |
| 138 | else | 109 | else |
| @@ -142,6 +113,7 @@ int tipc_buf_append(struct sk_buff **headbuf, struct sk_buff **buf) | |||
| 142 | head->len += frag->len; | 113 | head->len += frag->len; |
| 143 | TIPC_SKB_CB(head)->tail = frag; | 114 | TIPC_SKB_CB(head)->tail = frag; |
| 144 | } | 115 | } |
| 116 | |||
| 145 | if (fragid == LAST_FRAGMENT) { | 117 | if (fragid == LAST_FRAGMENT) { |
| 146 | *buf = head; | 118 | *buf = head; |
| 147 | TIPC_SKB_CB(head)->tail = NULL; | 119 | TIPC_SKB_CB(head)->tail = NULL; |
| @@ -150,10 +122,311 @@ int tipc_buf_append(struct sk_buff **headbuf, struct sk_buff **buf) | |||
| 150 | } | 122 | } |
| 151 | *buf = NULL; | 123 | *buf = NULL; |
| 152 | return 0; | 124 | return 0; |
| 153 | out_free: | 125 | |
| 126 | err: | ||
| 154 | pr_warn_ratelimited("Unable to build fragment list\n"); | 127 | pr_warn_ratelimited("Unable to build fragment list\n"); |
| 155 | kfree_skb(*buf); | 128 | kfree_skb(*buf); |
| 156 | kfree_skb(*headbuf); | 129 | kfree_skb(*headbuf); |
| 157 | *buf = *headbuf = NULL; | 130 | *buf = *headbuf = NULL; |
| 158 | return 0; | 131 | return 0; |
| 159 | } | 132 | } |
| 133 | |||
| 134 | |||
| 135 | /** | ||
| 136 | * tipc_msg_build - create buffer chain containing specified header and data | ||
| 137 | * @mhdr: Message header, to be prepended to data | ||
| 138 | * @iov: User data | ||
| 139 | * @offset: Posision in iov to start copying from | ||
| 140 | * @dsz: Total length of user data | ||
| 141 | * @pktmax: Max packet size that can be used | ||
| 142 | * @chain: Buffer or chain of buffers to be returned to caller | ||
| 143 | * Returns message data size or errno: -ENOMEM, -EFAULT | ||
| 144 | */ | ||
| 145 | int tipc_msg_build(struct tipc_msg *mhdr, struct iovec const *iov, | ||
| 146 | int offset, int dsz, int pktmax , struct sk_buff **chain) | ||
| 147 | { | ||
| 148 | int mhsz = msg_hdr_sz(mhdr); | ||
| 149 | int msz = mhsz + dsz; | ||
| 150 | int pktno = 1; | ||
| 151 | int pktsz; | ||
| 152 | int pktrem = pktmax; | ||
| 153 | int drem = dsz; | ||
| 154 | struct tipc_msg pkthdr; | ||
| 155 | struct sk_buff *buf, *prev; | ||
| 156 | char *pktpos; | ||
| 157 | int rc; | ||
| 158 | |||
| 159 | msg_set_size(mhdr, msz); | ||
| 160 | |||
| 161 | /* No fragmentation needed? */ | ||
| 162 | if (likely(msz <= pktmax)) { | ||
| 163 | buf = tipc_buf_acquire(msz); | ||
| 164 | *chain = buf; | ||
| 165 | if (unlikely(!buf)) | ||
| 166 | return -ENOMEM; | ||
| 167 | skb_copy_to_linear_data(buf, mhdr, mhsz); | ||
| 168 | pktpos = buf->data + mhsz; | ||
| 169 | if (!dsz || !memcpy_fromiovecend(pktpos, iov, offset, dsz)) | ||
| 170 | return dsz; | ||
| 171 | rc = -EFAULT; | ||
| 172 | goto error; | ||
| 173 | } | ||
| 174 | |||
| 175 | /* Prepare reusable fragment header */ | ||
| 176 | tipc_msg_init(&pkthdr, MSG_FRAGMENTER, FIRST_FRAGMENT, | ||
| 177 | INT_H_SIZE, msg_destnode(mhdr)); | ||
| 178 | msg_set_size(&pkthdr, pktmax); | ||
| 179 | msg_set_fragm_no(&pkthdr, pktno); | ||
| 180 | |||
| 181 | /* Prepare first fragment */ | ||
| 182 | *chain = buf = tipc_buf_acquire(pktmax); | ||
| 183 | if (!buf) | ||
| 184 | return -ENOMEM; | ||
| 185 | pktpos = buf->data; | ||
| 186 | skb_copy_to_linear_data(buf, &pkthdr, INT_H_SIZE); | ||
| 187 | pktpos += INT_H_SIZE; | ||
| 188 | pktrem -= INT_H_SIZE; | ||
| 189 | skb_copy_to_linear_data_offset(buf, INT_H_SIZE, mhdr, mhsz); | ||
| 190 | pktpos += mhsz; | ||
| 191 | pktrem -= mhsz; | ||
| 192 | |||
| 193 | do { | ||
| 194 | if (drem < pktrem) | ||
| 195 | pktrem = drem; | ||
| 196 | |||
| 197 | if (memcpy_fromiovecend(pktpos, iov, offset, pktrem)) { | ||
| 198 | rc = -EFAULT; | ||
| 199 | goto error; | ||
| 200 | } | ||
| 201 | drem -= pktrem; | ||
| 202 | offset += pktrem; | ||
| 203 | |||
| 204 | if (!drem) | ||
| 205 | break; | ||
| 206 | |||
| 207 | /* Prepare new fragment: */ | ||
| 208 | if (drem < (pktmax - INT_H_SIZE)) | ||
| 209 | pktsz = drem + INT_H_SIZE; | ||
| 210 | else | ||
| 211 | pktsz = pktmax; | ||
| 212 | prev = buf; | ||
| 213 | buf = tipc_buf_acquire(pktsz); | ||
| 214 | if (!buf) { | ||
| 215 | rc = -ENOMEM; | ||
| 216 | goto error; | ||
| 217 | } | ||
| 218 | prev->next = buf; | ||
| 219 | msg_set_type(&pkthdr, FRAGMENT); | ||
| 220 | msg_set_size(&pkthdr, pktsz); | ||
| 221 | msg_set_fragm_no(&pkthdr, ++pktno); | ||
| 222 | skb_copy_to_linear_data(buf, &pkthdr, INT_H_SIZE); | ||
| 223 | pktpos = buf->data + INT_H_SIZE; | ||
| 224 | pktrem = pktsz - INT_H_SIZE; | ||
| 225 | |||
| 226 | } while (1); | ||
| 227 | |||
| 228 | msg_set_type(buf_msg(buf), LAST_FRAGMENT); | ||
| 229 | return dsz; | ||
| 230 | error: | ||
| 231 | kfree_skb_list(*chain); | ||
| 232 | *chain = NULL; | ||
| 233 | return rc; | ||
| 234 | } | ||
| 235 | |||
| 236 | /** | ||
| 237 | * tipc_msg_bundle(): Append contents of a buffer to tail of an existing one | ||
| 238 | * @bbuf: the existing buffer ("bundle") | ||
| 239 | * @buf: buffer to be appended | ||
| 240 | * @mtu: max allowable size for the bundle buffer | ||
| 241 | * Consumes buffer if successful | ||
| 242 | * Returns true if bundling could be performed, otherwise false | ||
| 243 | */ | ||
| 244 | bool tipc_msg_bundle(struct sk_buff *bbuf, struct sk_buff *buf, u32 mtu) | ||
| 245 | { | ||
| 246 | struct tipc_msg *bmsg = buf_msg(bbuf); | ||
| 247 | struct tipc_msg *msg = buf_msg(buf); | ||
| 248 | unsigned int bsz = msg_size(bmsg); | ||
| 249 | unsigned int msz = msg_size(msg); | ||
| 250 | u32 start = align(bsz); | ||
| 251 | u32 max = mtu - INT_H_SIZE; | ||
| 252 | u32 pad = start - bsz; | ||
| 253 | |||
| 254 | if (likely(msg_user(msg) == MSG_FRAGMENTER)) | ||
| 255 | return false; | ||
| 256 | if (unlikely(msg_user(msg) == CHANGEOVER_PROTOCOL)) | ||
| 257 | return false; | ||
| 258 | if (unlikely(msg_user(msg) == BCAST_PROTOCOL)) | ||
| 259 | return false; | ||
| 260 | if (likely(msg_user(bmsg) != MSG_BUNDLER)) | ||
| 261 | return false; | ||
| 262 | if (likely(msg_type(bmsg) != BUNDLE_OPEN)) | ||
| 263 | return false; | ||
| 264 | if (unlikely(skb_tailroom(bbuf) < (pad + msz))) | ||
| 265 | return false; | ||
| 266 | if (unlikely(max < (start + msz))) | ||
| 267 | return false; | ||
| 268 | |||
| 269 | skb_put(bbuf, pad + msz); | ||
| 270 | skb_copy_to_linear_data_offset(bbuf, start, buf->data, msz); | ||
| 271 | msg_set_size(bmsg, start + msz); | ||
| 272 | msg_set_msgcnt(bmsg, msg_msgcnt(bmsg) + 1); | ||
| 273 | bbuf->next = buf->next; | ||
| 274 | kfree_skb(buf); | ||
| 275 | return true; | ||
| 276 | } | ||
| 277 | |||
| 278 | /** | ||
| 279 | * tipc_msg_make_bundle(): Create bundle buf and append message to its tail | ||
| 280 | * @buf: buffer to be appended and replaced | ||
| 281 | * @mtu: max allowable size for the bundle buffer, inclusive header | ||
| 282 | * @dnode: destination node for message. (Not always present in header) | ||
| 283 | * Replaces buffer if successful | ||
| 284 | * Returns true if sucess, otherwise false | ||
| 285 | */ | ||
| 286 | bool tipc_msg_make_bundle(struct sk_buff **buf, u32 mtu, u32 dnode) | ||
| 287 | { | ||
| 288 | struct sk_buff *bbuf; | ||
| 289 | struct tipc_msg *bmsg; | ||
| 290 | struct tipc_msg *msg = buf_msg(*buf); | ||
| 291 | u32 msz = msg_size(msg); | ||
| 292 | u32 max = mtu - INT_H_SIZE; | ||
| 293 | |||
| 294 | if (msg_user(msg) == MSG_FRAGMENTER) | ||
| 295 | return false; | ||
| 296 | if (msg_user(msg) == CHANGEOVER_PROTOCOL) | ||
| 297 | return false; | ||
| 298 | if (msg_user(msg) == BCAST_PROTOCOL) | ||
| 299 | return false; | ||
| 300 | if (msz > (max / 2)) | ||
| 301 | return false; | ||
| 302 | |||
| 303 | bbuf = tipc_buf_acquire(max); | ||
| 304 | if (!bbuf) | ||
| 305 | return false; | ||
| 306 | |||
| 307 | skb_trim(bbuf, INT_H_SIZE); | ||
| 308 | bmsg = buf_msg(bbuf); | ||
| 309 | tipc_msg_init(bmsg, MSG_BUNDLER, BUNDLE_OPEN, INT_H_SIZE, dnode); | ||
| 310 | msg_set_seqno(bmsg, msg_seqno(msg)); | ||
| 311 | msg_set_ack(bmsg, msg_ack(msg)); | ||
| 312 | msg_set_bcast_ack(bmsg, msg_bcast_ack(msg)); | ||
| 313 | bbuf->next = (*buf)->next; | ||
| 314 | tipc_msg_bundle(bbuf, *buf, mtu); | ||
| 315 | *buf = bbuf; | ||
| 316 | return true; | ||
| 317 | } | ||
| 318 | |||
| 319 | /** | ||
| 320 | * tipc_msg_reverse(): swap source and destination addresses and add error code | ||
| 321 | * @buf: buffer containing message to be reversed | ||
| 322 | * @dnode: return value: node where to send message after reversal | ||
| 323 | * @err: error code to be set in message | ||
| 324 | * Consumes buffer if failure | ||
| 325 | * Returns true if success, otherwise false | ||
| 326 | */ | ||
| 327 | bool tipc_msg_reverse(struct sk_buff *buf, u32 *dnode, int err) | ||
| 328 | { | ||
| 329 | struct tipc_msg *msg = buf_msg(buf); | ||
| 330 | uint imp = msg_importance(msg); | ||
| 331 | struct tipc_msg ohdr; | ||
| 332 | uint rdsz = min_t(uint, msg_data_sz(msg), MAX_FORWARD_SIZE); | ||
| 333 | |||
| 334 | if (skb_linearize(buf)) | ||
| 335 | goto exit; | ||
| 336 | if (msg_dest_droppable(msg)) | ||
| 337 | goto exit; | ||
| 338 | if (msg_errcode(msg)) | ||
| 339 | goto exit; | ||
| 340 | |||
| 341 | memcpy(&ohdr, msg, msg_hdr_sz(msg)); | ||
| 342 | imp = min_t(uint, imp + 1, TIPC_CRITICAL_IMPORTANCE); | ||
| 343 | if (msg_isdata(msg)) | ||
| 344 | msg_set_importance(msg, imp); | ||
| 345 | msg_set_errcode(msg, err); | ||
| 346 | msg_set_origport(msg, msg_destport(&ohdr)); | ||
| 347 | msg_set_destport(msg, msg_origport(&ohdr)); | ||
| 348 | msg_set_prevnode(msg, tipc_own_addr); | ||
| 349 | if (!msg_short(msg)) { | ||
| 350 | msg_set_orignode(msg, msg_destnode(&ohdr)); | ||
| 351 | msg_set_destnode(msg, msg_orignode(&ohdr)); | ||
| 352 | } | ||
| 353 | msg_set_size(msg, msg_hdr_sz(msg) + rdsz); | ||
| 354 | skb_trim(buf, msg_size(msg)); | ||
| 355 | skb_orphan(buf); | ||
| 356 | *dnode = msg_orignode(&ohdr); | ||
| 357 | return true; | ||
| 358 | exit: | ||
| 359 | kfree_skb(buf); | ||
| 360 | return false; | ||
| 361 | } | ||
| 362 | |||
| 363 | /** | ||
| 364 | * tipc_msg_eval: determine fate of message that found no destination | ||
| 365 | * @buf: the buffer containing the message. | ||
| 366 | * @dnode: return value: next-hop node, if message to be forwarded | ||
| 367 | * @err: error code to use, if message to be rejected | ||
| 368 | * | ||
| 369 | * Does not consume buffer | ||
| 370 | * Returns 0 (TIPC_OK) if message ok and we can try again, -TIPC error | ||
| 371 | * code if message to be rejected | ||
| 372 | */ | ||
| 373 | int tipc_msg_eval(struct sk_buff *buf, u32 *dnode) | ||
| 374 | { | ||
| 375 | struct tipc_msg *msg = buf_msg(buf); | ||
| 376 | u32 dport; | ||
| 377 | |||
| 378 | if (msg_type(msg) != TIPC_NAMED_MSG) | ||
| 379 | return -TIPC_ERR_NO_PORT; | ||
| 380 | if (skb_linearize(buf)) | ||
| 381 | return -TIPC_ERR_NO_NAME; | ||
| 382 | if (msg_data_sz(msg) > MAX_FORWARD_SIZE) | ||
| 383 | return -TIPC_ERR_NO_NAME; | ||
| 384 | if (msg_reroute_cnt(msg) > 0) | ||
| 385 | return -TIPC_ERR_NO_NAME; | ||
| 386 | |||
| 387 | *dnode = addr_domain(msg_lookup_scope(msg)); | ||
| 388 | dport = tipc_nametbl_translate(msg_nametype(msg), | ||
| 389 | msg_nameinst(msg), | ||
| 390 | dnode); | ||
| 391 | if (!dport) | ||
| 392 | return -TIPC_ERR_NO_NAME; | ||
| 393 | msg_incr_reroute_cnt(msg); | ||
| 394 | msg_set_destnode(msg, *dnode); | ||
| 395 | msg_set_destport(msg, dport); | ||
| 396 | return TIPC_OK; | ||
| 397 | } | ||
| 398 | |||
| 399 | /* tipc_msg_reassemble() - clone a buffer chain of fragments and | ||
| 400 | * reassemble the clones into one message | ||
| 401 | */ | ||
| 402 | struct sk_buff *tipc_msg_reassemble(struct sk_buff *chain) | ||
| 403 | { | ||
| 404 | struct sk_buff *buf = chain; | ||
| 405 | struct sk_buff *frag = buf; | ||
| 406 | struct sk_buff *head = NULL; | ||
| 407 | int hdr_sz; | ||
| 408 | |||
| 409 | /* Copy header if single buffer */ | ||
| 410 | if (!buf->next) { | ||
| 411 | hdr_sz = skb_headroom(buf) + msg_hdr_sz(buf_msg(buf)); | ||
| 412 | return __pskb_copy(buf, hdr_sz, GFP_ATOMIC); | ||
| 413 | } | ||
| 414 | |||
| 415 | /* Clone all fragments and reassemble */ | ||
| 416 | while (buf) { | ||
| 417 | frag = skb_clone(buf, GFP_ATOMIC); | ||
| 418 | if (!frag) | ||
| 419 | goto error; | ||
| 420 | frag->next = NULL; | ||
| 421 | if (tipc_buf_append(&head, &frag)) | ||
| 422 | break; | ||
| 423 | if (!head) | ||
| 424 | goto error; | ||
| 425 | buf = buf->next; | ||
| 426 | } | ||
| 427 | return frag; | ||
| 428 | error: | ||
| 429 | pr_warn("Failed do clone local mcast rcv buffer\n"); | ||
| 430 | kfree_skb(head); | ||
| 431 | return NULL; | ||
| 432 | } | ||
diff --git a/net/tipc/msg.h b/net/tipc/msg.h index 503511903d1d..462fa194a6af 100644 --- a/net/tipc/msg.h +++ b/net/tipc/msg.h | |||
| @@ -463,6 +463,11 @@ static inline struct tipc_msg *msg_get_wrapped(struct tipc_msg *m) | |||
| 463 | #define FRAGMENT 1 | 463 | #define FRAGMENT 1 |
| 464 | #define LAST_FRAGMENT 2 | 464 | #define LAST_FRAGMENT 2 |
| 465 | 465 | ||
| 466 | /* Bundling protocol message types | ||
| 467 | */ | ||
| 468 | #define BUNDLE_OPEN 0 | ||
| 469 | #define BUNDLE_CLOSED 1 | ||
| 470 | |||
| 466 | /* | 471 | /* |
| 467 | * Link management protocol message types | 472 | * Link management protocol message types |
| 468 | */ | 473 | */ |
| @@ -706,12 +711,36 @@ static inline void msg_set_link_tolerance(struct tipc_msg *m, u32 n) | |||
| 706 | msg_set_bits(m, 9, 0, 0xffff, n); | 711 | msg_set_bits(m, 9, 0, 0xffff, n); |
| 707 | } | 712 | } |
| 708 | 713 | ||
| 709 | u32 tipc_msg_tot_importance(struct tipc_msg *m); | 714 | static inline u32 tipc_msg_tot_importance(struct tipc_msg *m) |
| 715 | { | ||
| 716 | if ((msg_user(m) == MSG_FRAGMENTER) && (msg_type(m) == FIRST_FRAGMENT)) | ||
| 717 | return msg_importance(msg_get_wrapped(m)); | ||
| 718 | return msg_importance(m); | ||
| 719 | } | ||
| 720 | |||
| 721 | static inline u32 msg_tot_origport(struct tipc_msg *m) | ||
| 722 | { | ||
| 723 | if ((msg_user(m) == MSG_FRAGMENTER) && (msg_type(m) == FIRST_FRAGMENT)) | ||
| 724 | return msg_origport(msg_get_wrapped(m)); | ||
| 725 | return msg_origport(m); | ||
| 726 | } | ||
| 727 | |||
| 728 | bool tipc_msg_reverse(struct sk_buff *buf, u32 *dnode, int err); | ||
| 729 | |||
| 730 | int tipc_msg_eval(struct sk_buff *buf, u32 *dnode); | ||
| 731 | |||
| 710 | void tipc_msg_init(struct tipc_msg *m, u32 user, u32 type, u32 hsize, | 732 | void tipc_msg_init(struct tipc_msg *m, u32 user, u32 type, u32 hsize, |
| 711 | u32 destnode); | 733 | u32 destnode); |
| 712 | int tipc_msg_build(struct tipc_msg *hdr, struct iovec const *msg_sect, | ||
| 713 | unsigned int len, int max_size, struct sk_buff **buf); | ||
| 714 | 734 | ||
| 715 | int tipc_buf_append(struct sk_buff **headbuf, struct sk_buff **buf); | 735 | int tipc_buf_append(struct sk_buff **headbuf, struct sk_buff **buf); |
| 716 | 736 | ||
| 737 | bool tipc_msg_bundle(struct sk_buff *bbuf, struct sk_buff *buf, u32 mtu); | ||
| 738 | |||
| 739 | bool tipc_msg_make_bundle(struct sk_buff **buf, u32 mtu, u32 dnode); | ||
| 740 | |||
| 741 | int tipc_msg_build(struct tipc_msg *mhdr, struct iovec const *iov, | ||
| 742 | int offset, int dsz, int mtu , struct sk_buff **chain); | ||
| 743 | |||
| 744 | struct sk_buff *tipc_msg_reassemble(struct sk_buff *chain); | ||
| 745 | |||
| 717 | #endif | 746 | #endif |
diff --git a/net/tipc/name_distr.c b/net/tipc/name_distr.c index 8ce730984aa1..dcc15bcd5692 100644 --- a/net/tipc/name_distr.c +++ b/net/tipc/name_distr.c | |||
| @@ -101,24 +101,22 @@ static struct sk_buff *named_prepare_buf(u32 type, u32 size, u32 dest) | |||
| 101 | 101 | ||
| 102 | void named_cluster_distribute(struct sk_buff *buf) | 102 | void named_cluster_distribute(struct sk_buff *buf) |
| 103 | { | 103 | { |
| 104 | struct sk_buff *buf_copy; | 104 | struct sk_buff *obuf; |
| 105 | struct tipc_node *n_ptr; | 105 | struct tipc_node *node; |
| 106 | struct tipc_link *l_ptr; | 106 | u32 dnode; |
| 107 | 107 | ||
| 108 | rcu_read_lock(); | 108 | rcu_read_lock(); |
| 109 | list_for_each_entry_rcu(n_ptr, &tipc_node_list, list) { | 109 | list_for_each_entry_rcu(node, &tipc_node_list, list) { |
| 110 | tipc_node_lock(n_ptr); | 110 | dnode = node->addr; |
| 111 | l_ptr = n_ptr->active_links[n_ptr->addr & 1]; | 111 | if (in_own_node(dnode)) |
| 112 | if (l_ptr) { | 112 | continue; |
| 113 | buf_copy = skb_copy(buf, GFP_ATOMIC); | 113 | if (!tipc_node_active_links(node)) |
| 114 | if (!buf_copy) { | 114 | continue; |
| 115 | tipc_node_unlock(n_ptr); | 115 | obuf = skb_copy(buf, GFP_ATOMIC); |
| 116 | break; | 116 | if (!obuf) |
| 117 | } | 117 | break; |
| 118 | msg_set_destnode(buf_msg(buf_copy), n_ptr->addr); | 118 | msg_set_destnode(buf_msg(obuf), dnode); |
| 119 | __tipc_link_xmit(l_ptr, buf_copy); | 119 | tipc_link_xmit(obuf, dnode, dnode); |
| 120 | } | ||
| 121 | tipc_node_unlock(n_ptr); | ||
| 122 | } | 120 | } |
| 123 | rcu_read_unlock(); | 121 | rcu_read_unlock(); |
| 124 | 122 | ||
| @@ -175,34 +173,44 @@ struct sk_buff *tipc_named_withdraw(struct publication *publ) | |||
| 175 | return buf; | 173 | return buf; |
| 176 | } | 174 | } |
| 177 | 175 | ||
| 178 | /* | 176 | /** |
| 179 | * named_distribute - prepare name info for bulk distribution to another node | 177 | * named_distribute - prepare name info for bulk distribution to another node |
| 178 | * @msg_list: list of messages (buffers) to be returned from this function | ||
| 179 | * @dnode: node to be updated | ||
| 180 | * @pls: linked list of publication items to be packed into buffer chain | ||
| 180 | */ | 181 | */ |
| 181 | static void named_distribute(struct list_head *message_list, u32 node, | 182 | static void named_distribute(struct list_head *msg_list, u32 dnode, |
| 182 | struct publ_list *pls, u32 max_item_buf) | 183 | struct publ_list *pls) |
| 183 | { | 184 | { |
| 184 | struct publication *publ; | 185 | struct publication *publ; |
| 185 | struct sk_buff *buf = NULL; | 186 | struct sk_buff *buf = NULL; |
| 186 | struct distr_item *item = NULL; | 187 | struct distr_item *item = NULL; |
| 187 | u32 left = 0; | 188 | uint dsz = pls->size * ITEM_SIZE; |
| 188 | u32 rest = pls->size * ITEM_SIZE; | 189 | uint msg_dsz = (tipc_node_get_mtu(dnode, 0) / ITEM_SIZE) * ITEM_SIZE; |
| 190 | uint rem = dsz; | ||
| 191 | uint msg_rem = 0; | ||
| 189 | 192 | ||
| 190 | list_for_each_entry(publ, &pls->list, local_list) { | 193 | list_for_each_entry(publ, &pls->list, local_list) { |
| 194 | /* Prepare next buffer: */ | ||
| 191 | if (!buf) { | 195 | if (!buf) { |
| 192 | left = (rest <= max_item_buf) ? rest : max_item_buf; | 196 | msg_rem = min_t(uint, rem, msg_dsz); |
| 193 | rest -= left; | 197 | rem -= msg_rem; |
| 194 | buf = named_prepare_buf(PUBLICATION, left, node); | 198 | buf = named_prepare_buf(PUBLICATION, msg_rem, dnode); |
| 195 | if (!buf) { | 199 | if (!buf) { |
| 196 | pr_warn("Bulk publication failure\n"); | 200 | pr_warn("Bulk publication failure\n"); |
| 197 | return; | 201 | return; |
| 198 | } | 202 | } |
| 199 | item = (struct distr_item *)msg_data(buf_msg(buf)); | 203 | item = (struct distr_item *)msg_data(buf_msg(buf)); |
| 200 | } | 204 | } |
| 205 | |||
| 206 | /* Pack publication into message: */ | ||
| 201 | publ_to_item(item, publ); | 207 | publ_to_item(item, publ); |
| 202 | item++; | 208 | item++; |
| 203 | left -= ITEM_SIZE; | 209 | msg_rem -= ITEM_SIZE; |
| 204 | if (!left) { | 210 | |
| 205 | list_add_tail((struct list_head *)buf, message_list); | 211 | /* Append full buffer to list: */ |
| 212 | if (!msg_rem) { | ||
| 213 | list_add_tail((struct list_head *)buf, msg_list); | ||
| 206 | buf = NULL; | 214 | buf = NULL; |
| 207 | } | 215 | } |
| 208 | } | 216 | } |
| @@ -211,16 +219,20 @@ static void named_distribute(struct list_head *message_list, u32 node, | |||
| 211 | /** | 219 | /** |
| 212 | * tipc_named_node_up - tell specified node about all publications by this node | 220 | * tipc_named_node_up - tell specified node about all publications by this node |
| 213 | */ | 221 | */ |
| 214 | void tipc_named_node_up(u32 max_item_buf, u32 node) | 222 | void tipc_named_node_up(u32 dnode) |
| 215 | { | 223 | { |
| 216 | LIST_HEAD(message_list); | 224 | LIST_HEAD(msg_list); |
| 225 | struct sk_buff *buf_chain; | ||
| 217 | 226 | ||
| 218 | read_lock_bh(&tipc_nametbl_lock); | 227 | read_lock_bh(&tipc_nametbl_lock); |
| 219 | named_distribute(&message_list, node, &publ_cluster, max_item_buf); | 228 | named_distribute(&msg_list, dnode, &publ_cluster); |
| 220 | named_distribute(&message_list, node, &publ_zone, max_item_buf); | 229 | named_distribute(&msg_list, dnode, &publ_zone); |
| 221 | read_unlock_bh(&tipc_nametbl_lock); | 230 | read_unlock_bh(&tipc_nametbl_lock); |
| 222 | 231 | ||
| 223 | tipc_link_names_xmit(&message_list, node); | 232 | /* Convert circular list to linear list and send: */ |
| 233 | buf_chain = (struct sk_buff *)msg_list.next; | ||
| 234 | ((struct sk_buff *)msg_list.prev)->next = NULL; | ||
| 235 | tipc_link_xmit(buf_chain, dnode, dnode); | ||
| 224 | } | 236 | } |
| 225 | 237 | ||
| 226 | /** | 238 | /** |
diff --git a/net/tipc/name_distr.h b/net/tipc/name_distr.h index b2eed4ec1526..8afe32b7fc9a 100644 --- a/net/tipc/name_distr.h +++ b/net/tipc/name_distr.h | |||
| @@ -70,7 +70,7 @@ struct distr_item { | |||
| 70 | struct sk_buff *tipc_named_publish(struct publication *publ); | 70 | struct sk_buff *tipc_named_publish(struct publication *publ); |
| 71 | struct sk_buff *tipc_named_withdraw(struct publication *publ); | 71 | struct sk_buff *tipc_named_withdraw(struct publication *publ); |
| 72 | void named_cluster_distribute(struct sk_buff *buf); | 72 | void named_cluster_distribute(struct sk_buff *buf); |
| 73 | void tipc_named_node_up(u32 max_item_buf, u32 node); | 73 | void tipc_named_node_up(u32 dnode); |
| 74 | void tipc_named_rcv(struct sk_buff *buf); | 74 | void tipc_named_rcv(struct sk_buff *buf); |
| 75 | void tipc_named_reinit(void); | 75 | void tipc_named_reinit(void); |
| 76 | 76 | ||
diff --git a/net/tipc/net.c b/net/tipc/net.c index f64375e7f99f..7fcc94998fea 100644 --- a/net/tipc/net.c +++ b/net/tipc/net.c | |||
| @@ -1,7 +1,7 @@ | |||
| 1 | /* | 1 | /* |
| 2 | * net/tipc/net.c: TIPC network routing code | 2 | * net/tipc/net.c: TIPC network routing code |
| 3 | * | 3 | * |
| 4 | * Copyright (c) 1995-2006, Ericsson AB | 4 | * Copyright (c) 1995-2006, 2014, Ericsson AB |
| 5 | * Copyright (c) 2005, 2010-2011, Wind River Systems | 5 | * Copyright (c) 2005, 2010-2011, Wind River Systems |
| 6 | * All rights reserved. | 6 | * All rights reserved. |
| 7 | * | 7 | * |
| @@ -104,67 +104,6 @@ | |||
| 104 | * - A local spin_lock protecting the queue of subscriber events. | 104 | * - A local spin_lock protecting the queue of subscriber events. |
| 105 | */ | 105 | */ |
| 106 | 106 | ||
| 107 | static void net_route_named_msg(struct sk_buff *buf) | ||
| 108 | { | ||
| 109 | struct tipc_msg *msg = buf_msg(buf); | ||
| 110 | u32 dnode; | ||
| 111 | u32 dport; | ||
| 112 | |||
| 113 | if (!msg_named(msg)) { | ||
| 114 | kfree_skb(buf); | ||
| 115 | return; | ||
| 116 | } | ||
| 117 | |||
| 118 | dnode = addr_domain(msg_lookup_scope(msg)); | ||
| 119 | dport = tipc_nametbl_translate(msg_nametype(msg), msg_nameinst(msg), &dnode); | ||
| 120 | if (dport) { | ||
| 121 | msg_set_destnode(msg, dnode); | ||
| 122 | msg_set_destport(msg, dport); | ||
| 123 | tipc_net_route_msg(buf); | ||
| 124 | return; | ||
| 125 | } | ||
| 126 | tipc_reject_msg(buf, TIPC_ERR_NO_NAME); | ||
| 127 | } | ||
| 128 | |||
| 129 | void tipc_net_route_msg(struct sk_buff *buf) | ||
| 130 | { | ||
| 131 | struct tipc_msg *msg; | ||
| 132 | u32 dnode; | ||
| 133 | |||
| 134 | if (!buf) | ||
| 135 | return; | ||
| 136 | msg = buf_msg(buf); | ||
| 137 | |||
| 138 | /* Handle message for this node */ | ||
| 139 | dnode = msg_short(msg) ? tipc_own_addr : msg_destnode(msg); | ||
| 140 | if (tipc_in_scope(dnode, tipc_own_addr)) { | ||
| 141 | if (msg_isdata(msg)) { | ||
| 142 | if (msg_mcast(msg)) | ||
| 143 | tipc_port_mcast_rcv(buf, NULL); | ||
| 144 | else if (msg_destport(msg)) | ||
| 145 | tipc_sk_rcv(buf); | ||
| 146 | else | ||
| 147 | net_route_named_msg(buf); | ||
| 148 | return; | ||
| 149 | } | ||
| 150 | switch (msg_user(msg)) { | ||
| 151 | case NAME_DISTRIBUTOR: | ||
| 152 | tipc_named_rcv(buf); | ||
| 153 | break; | ||
| 154 | case CONN_MANAGER: | ||
| 155 | tipc_port_proto_rcv(buf); | ||
| 156 | break; | ||
| 157 | default: | ||
| 158 | kfree_skb(buf); | ||
| 159 | } | ||
| 160 | return; | ||
| 161 | } | ||
| 162 | |||
| 163 | /* Handle message for another node */ | ||
| 164 | skb_trim(buf, msg_size(msg)); | ||
| 165 | tipc_link_xmit(buf, dnode, msg_link_selector(msg)); | ||
| 166 | } | ||
| 167 | |||
| 168 | int tipc_net_start(u32 addr) | 107 | int tipc_net_start(u32 addr) |
| 169 | { | 108 | { |
| 170 | char addr_string[16]; | 109 | char addr_string[16]; |
diff --git a/net/tipc/net.h b/net/tipc/net.h index c6c2b46f7c28..59ef3388be2c 100644 --- a/net/tipc/net.h +++ b/net/tipc/net.h | |||
| @@ -37,8 +37,6 @@ | |||
| 37 | #ifndef _TIPC_NET_H | 37 | #ifndef _TIPC_NET_H |
| 38 | #define _TIPC_NET_H | 38 | #define _TIPC_NET_H |
| 39 | 39 | ||
| 40 | void tipc_net_route_msg(struct sk_buff *buf); | ||
| 41 | |||
| 42 | int tipc_net_start(u32 addr); | 40 | int tipc_net_start(u32 addr); |
| 43 | void tipc_net_stop(void); | 41 | void tipc_net_stop(void); |
| 44 | 42 | ||
diff --git a/net/tipc/node.c b/net/tipc/node.c index 5b44c3041be4..f7069299943f 100644 --- a/net/tipc/node.c +++ b/net/tipc/node.c | |||
| @@ -1,7 +1,7 @@ | |||
| 1 | /* | 1 | /* |
| 2 | * net/tipc/node.c: TIPC node management routines | 2 | * net/tipc/node.c: TIPC node management routines |
| 3 | * | 3 | * |
| 4 | * Copyright (c) 2000-2006, 2012 Ericsson AB | 4 | * Copyright (c) 2000-2006, 2012-2014, Ericsson AB |
| 5 | * Copyright (c) 2005-2006, 2010-2014, Wind River Systems | 5 | * Copyright (c) 2005-2006, 2010-2014, Wind River Systems |
| 6 | * All rights reserved. | 6 | * All rights reserved. |
| 7 | * | 7 | * |
| @@ -155,21 +155,25 @@ void tipc_node_link_up(struct tipc_node *n_ptr, struct tipc_link *l_ptr) | |||
| 155 | if (!active[0]) { | 155 | if (!active[0]) { |
| 156 | active[0] = active[1] = l_ptr; | 156 | active[0] = active[1] = l_ptr; |
| 157 | node_established_contact(n_ptr); | 157 | node_established_contact(n_ptr); |
| 158 | return; | 158 | goto exit; |
| 159 | } | 159 | } |
| 160 | if (l_ptr->priority < active[0]->priority) { | 160 | if (l_ptr->priority < active[0]->priority) { |
| 161 | pr_info("New link <%s> becomes standby\n", l_ptr->name); | 161 | pr_info("New link <%s> becomes standby\n", l_ptr->name); |
| 162 | return; | 162 | goto exit; |
| 163 | } | 163 | } |
| 164 | tipc_link_dup_queue_xmit(active[0], l_ptr); | 164 | tipc_link_dup_queue_xmit(active[0], l_ptr); |
| 165 | if (l_ptr->priority == active[0]->priority) { | 165 | if (l_ptr->priority == active[0]->priority) { |
| 166 | active[0] = l_ptr; | 166 | active[0] = l_ptr; |
| 167 | return; | 167 | goto exit; |
| 168 | } | 168 | } |
| 169 | pr_info("Old link <%s> becomes standby\n", active[0]->name); | 169 | pr_info("Old link <%s> becomes standby\n", active[0]->name); |
| 170 | if (active[1] != active[0]) | 170 | if (active[1] != active[0]) |
| 171 | pr_info("Old link <%s> becomes standby\n", active[1]->name); | 171 | pr_info("Old link <%s> becomes standby\n", active[1]->name); |
| 172 | active[0] = active[1] = l_ptr; | 172 | active[0] = active[1] = l_ptr; |
| 173 | exit: | ||
| 174 | /* Leave room for changeover header when returning 'mtu' to users: */ | ||
| 175 | n_ptr->act_mtus[0] = active[0]->max_pkt - INT_H_SIZE; | ||
| 176 | n_ptr->act_mtus[1] = active[1]->max_pkt - INT_H_SIZE; | ||
| 173 | } | 177 | } |
| 174 | 178 | ||
| 175 | /** | 179 | /** |
| @@ -229,6 +233,19 @@ void tipc_node_link_down(struct tipc_node *n_ptr, struct tipc_link *l_ptr) | |||
| 229 | tipc_link_failover_send_queue(l_ptr); | 233 | tipc_link_failover_send_queue(l_ptr); |
| 230 | else | 234 | else |
| 231 | node_lost_contact(n_ptr); | 235 | node_lost_contact(n_ptr); |
| 236 | |||
| 237 | /* Leave room for changeover header when returning 'mtu' to users: */ | ||
| 238 | if (active[0]) { | ||
| 239 | n_ptr->act_mtus[0] = active[0]->max_pkt - INT_H_SIZE; | ||
| 240 | n_ptr->act_mtus[1] = active[1]->max_pkt - INT_H_SIZE; | ||
| 241 | return; | ||
| 242 | } | ||
| 243 | |||
| 244 | /* Loopback link went down? No fragmentation needed from now on. */ | ||
| 245 | if (n_ptr->addr == tipc_own_addr) { | ||
| 246 | n_ptr->act_mtus[0] = MAX_MSG_SIZE; | ||
| 247 | n_ptr->act_mtus[1] = MAX_MSG_SIZE; | ||
| 248 | } | ||
| 232 | } | 249 | } |
| 233 | 250 | ||
| 234 | int tipc_node_active_links(struct tipc_node *n_ptr) | 251 | int tipc_node_active_links(struct tipc_node *n_ptr) |
| @@ -457,8 +474,6 @@ int tipc_node_get_linkname(u32 bearer_id, u32 addr, char *linkname, size_t len) | |||
| 457 | void tipc_node_unlock(struct tipc_node *node) | 474 | void tipc_node_unlock(struct tipc_node *node) |
| 458 | { | 475 | { |
| 459 | LIST_HEAD(nsub_list); | 476 | LIST_HEAD(nsub_list); |
| 460 | struct tipc_link *link; | ||
| 461 | int pkt_sz = 0; | ||
| 462 | u32 addr = 0; | 477 | u32 addr = 0; |
| 463 | 478 | ||
| 464 | if (likely(!node->action_flags)) { | 479 | if (likely(!node->action_flags)) { |
| @@ -471,18 +486,13 @@ void tipc_node_unlock(struct tipc_node *node) | |||
| 471 | node->action_flags &= ~TIPC_NOTIFY_NODE_DOWN; | 486 | node->action_flags &= ~TIPC_NOTIFY_NODE_DOWN; |
| 472 | } | 487 | } |
| 473 | if (node->action_flags & TIPC_NOTIFY_NODE_UP) { | 488 | if (node->action_flags & TIPC_NOTIFY_NODE_UP) { |
| 474 | link = node->active_links[0]; | ||
| 475 | node->action_flags &= ~TIPC_NOTIFY_NODE_UP; | 489 | node->action_flags &= ~TIPC_NOTIFY_NODE_UP; |
| 476 | if (link) { | 490 | addr = node->addr; |
| 477 | pkt_sz = ((link->max_pkt - INT_H_SIZE) / ITEM_SIZE) * | ||
| 478 | ITEM_SIZE; | ||
| 479 | addr = node->addr; | ||
| 480 | } | ||
| 481 | } | 491 | } |
| 482 | spin_unlock_bh(&node->lock); | 492 | spin_unlock_bh(&node->lock); |
| 483 | 493 | ||
| 484 | if (!list_empty(&nsub_list)) | 494 | if (!list_empty(&nsub_list)) |
| 485 | tipc_nodesub_notify(&nsub_list); | 495 | tipc_nodesub_notify(&nsub_list); |
| 486 | if (pkt_sz) | 496 | if (addr) |
| 487 | tipc_named_node_up(pkt_sz, addr); | 497 | tipc_named_node_up(addr); |
| 488 | } | 498 | } |
diff --git a/net/tipc/node.h b/net/tipc/node.h index 9087063793f2..b61716a8218e 100644 --- a/net/tipc/node.h +++ b/net/tipc/node.h | |||
| @@ -41,6 +41,7 @@ | |||
| 41 | #include "addr.h" | 41 | #include "addr.h" |
| 42 | #include "net.h" | 42 | #include "net.h" |
| 43 | #include "bearer.h" | 43 | #include "bearer.h" |
| 44 | #include "msg.h" | ||
| 44 | 45 | ||
| 45 | /* | 46 | /* |
| 46 | * Out-of-range value for node signature | 47 | * Out-of-range value for node signature |
| @@ -105,6 +106,7 @@ struct tipc_node { | |||
| 105 | spinlock_t lock; | 106 | spinlock_t lock; |
| 106 | struct hlist_node hash; | 107 | struct hlist_node hash; |
| 107 | struct tipc_link *active_links[2]; | 108 | struct tipc_link *active_links[2]; |
| 109 | u32 act_mtus[2]; | ||
| 108 | struct tipc_link *links[MAX_BEARERS]; | 110 | struct tipc_link *links[MAX_BEARERS]; |
| 109 | unsigned int action_flags; | 111 | unsigned int action_flags; |
| 110 | struct tipc_node_bclink bclink; | 112 | struct tipc_node_bclink bclink; |
| @@ -143,4 +145,19 @@ static inline bool tipc_node_blocked(struct tipc_node *node) | |||
| 143 | TIPC_NOTIFY_NODE_DOWN | TIPC_WAIT_OWN_LINKS_DOWN)); | 145 | TIPC_NOTIFY_NODE_DOWN | TIPC_WAIT_OWN_LINKS_DOWN)); |
| 144 | } | 146 | } |
| 145 | 147 | ||
| 148 | static inline uint tipc_node_get_mtu(u32 addr, u32 selector) | ||
| 149 | { | ||
| 150 | struct tipc_node *node; | ||
| 151 | u32 mtu; | ||
| 152 | |||
| 153 | node = tipc_node_find(addr); | ||
| 154 | |||
| 155 | if (likely(node)) | ||
| 156 | mtu = node->act_mtus[selector & 1]; | ||
| 157 | else | ||
| 158 | mtu = MAX_MSG_SIZE; | ||
| 159 | |||
| 160 | return mtu; | ||
| 161 | } | ||
| 162 | |||
| 146 | #endif | 163 | #endif |
diff --git a/net/tipc/node_subscr.c b/net/tipc/node_subscr.c index 7c59ab1d6ecb..2d13eea8574a 100644 --- a/net/tipc/node_subscr.c +++ b/net/tipc/node_subscr.c | |||
| @@ -84,11 +84,13 @@ void tipc_nodesub_unsubscribe(struct tipc_node_subscr *node_sub) | |||
| 84 | void tipc_nodesub_notify(struct list_head *nsub_list) | 84 | void tipc_nodesub_notify(struct list_head *nsub_list) |
| 85 | { | 85 | { |
| 86 | struct tipc_node_subscr *ns, *safe; | 86 | struct tipc_node_subscr *ns, *safe; |
| 87 | net_ev_handler handle_node_down; | ||
| 87 | 88 | ||
| 88 | list_for_each_entry_safe(ns, safe, nsub_list, nodesub_list) { | 89 | list_for_each_entry_safe(ns, safe, nsub_list, nodesub_list) { |
| 89 | if (ns->handle_node_down) { | 90 | handle_node_down = ns->handle_node_down; |
| 90 | ns->handle_node_down(ns->usr_handle); | 91 | if (handle_node_down) { |
| 91 | ns->handle_node_down = NULL; | 92 | ns->handle_node_down = NULL; |
| 93 | handle_node_down(ns->usr_handle); | ||
| 92 | } | 94 | } |
| 93 | } | 95 | } |
| 94 | } | 96 | } |
diff --git a/net/tipc/port.c b/net/tipc/port.c index 5fd7acce01ea..7e096a5e7701 100644 --- a/net/tipc/port.c +++ b/net/tipc/port.c | |||
| @@ -42,8 +42,6 @@ | |||
| 42 | 42 | ||
| 43 | /* Connection management: */ | 43 | /* Connection management: */ |
| 44 | #define PROBING_INTERVAL 3600000 /* [ms] => 1 h */ | 44 | #define PROBING_INTERVAL 3600000 /* [ms] => 1 h */ |
| 45 | #define CONFIRMED 0 | ||
| 46 | #define PROBING 1 | ||
| 47 | 45 | ||
| 48 | #define MAX_REJECT_SIZE 1024 | 46 | #define MAX_REJECT_SIZE 1024 |
| 49 | 47 | ||
| @@ -76,124 +74,6 @@ int tipc_port_peer_msg(struct tipc_port *p_ptr, struct tipc_msg *msg) | |||
| 76 | (!peernode && (orignode == tipc_own_addr)); | 74 | (!peernode && (orignode == tipc_own_addr)); |
| 77 | } | 75 | } |
| 78 | 76 | ||
| 79 | /** | ||
| 80 | * tipc_port_mcast_xmit - send a multicast message to local and remote | ||
| 81 | * destinations | ||
| 82 | */ | ||
| 83 | int tipc_port_mcast_xmit(struct tipc_port *oport, | ||
| 84 | struct tipc_name_seq const *seq, | ||
| 85 | struct iovec const *msg_sect, | ||
| 86 | unsigned int len) | ||
| 87 | { | ||
| 88 | struct tipc_msg *hdr; | ||
| 89 | struct sk_buff *buf; | ||
| 90 | struct sk_buff *ibuf = NULL; | ||
| 91 | struct tipc_port_list dports = {0, NULL, }; | ||
| 92 | int ext_targets; | ||
| 93 | int res; | ||
| 94 | |||
| 95 | /* Create multicast message */ | ||
| 96 | hdr = &oport->phdr; | ||
| 97 | msg_set_type(hdr, TIPC_MCAST_MSG); | ||
| 98 | msg_set_lookup_scope(hdr, TIPC_CLUSTER_SCOPE); | ||
| 99 | msg_set_destport(hdr, 0); | ||
| 100 | msg_set_destnode(hdr, 0); | ||
| 101 | msg_set_nametype(hdr, seq->type); | ||
| 102 | msg_set_namelower(hdr, seq->lower); | ||
| 103 | msg_set_nameupper(hdr, seq->upper); | ||
| 104 | msg_set_hdr_sz(hdr, MCAST_H_SIZE); | ||
| 105 | res = tipc_msg_build(hdr, msg_sect, len, MAX_MSG_SIZE, &buf); | ||
| 106 | if (unlikely(!buf)) | ||
| 107 | return res; | ||
| 108 | |||
| 109 | /* Figure out where to send multicast message */ | ||
| 110 | ext_targets = tipc_nametbl_mc_translate(seq->type, seq->lower, seq->upper, | ||
| 111 | TIPC_NODE_SCOPE, &dports); | ||
| 112 | |||
| 113 | /* Send message to destinations (duplicate it only if necessary) */ | ||
| 114 | if (ext_targets) { | ||
| 115 | if (dports.count != 0) { | ||
| 116 | ibuf = skb_copy(buf, GFP_ATOMIC); | ||
| 117 | if (ibuf == NULL) { | ||
| 118 | tipc_port_list_free(&dports); | ||
| 119 | kfree_skb(buf); | ||
| 120 | return -ENOMEM; | ||
| 121 | } | ||
| 122 | } | ||
| 123 | res = tipc_bclink_xmit(buf); | ||
| 124 | if ((res < 0) && (dports.count != 0)) | ||
| 125 | kfree_skb(ibuf); | ||
| 126 | } else { | ||
| 127 | ibuf = buf; | ||
| 128 | } | ||
| 129 | |||
| 130 | if (res >= 0) { | ||
| 131 | if (ibuf) | ||
| 132 | tipc_port_mcast_rcv(ibuf, &dports); | ||
| 133 | } else { | ||
| 134 | tipc_port_list_free(&dports); | ||
| 135 | } | ||
| 136 | return res; | ||
| 137 | } | ||
| 138 | |||
| 139 | /** | ||
| 140 | * tipc_port_mcast_rcv - deliver multicast message to all destination ports | ||
| 141 | * | ||
| 142 | * If there is no port list, perform a lookup to create one | ||
| 143 | */ | ||
| 144 | void tipc_port_mcast_rcv(struct sk_buff *buf, struct tipc_port_list *dp) | ||
| 145 | { | ||
| 146 | struct tipc_msg *msg; | ||
| 147 | struct tipc_port_list dports = {0, NULL, }; | ||
| 148 | struct tipc_port_list *item = dp; | ||
| 149 | int cnt = 0; | ||
| 150 | |||
| 151 | msg = buf_msg(buf); | ||
| 152 | |||
| 153 | /* Create destination port list, if one wasn't supplied */ | ||
| 154 | if (dp == NULL) { | ||
| 155 | tipc_nametbl_mc_translate(msg_nametype(msg), | ||
| 156 | msg_namelower(msg), | ||
| 157 | msg_nameupper(msg), | ||
| 158 | TIPC_CLUSTER_SCOPE, | ||
| 159 | &dports); | ||
| 160 | item = dp = &dports; | ||
| 161 | } | ||
| 162 | |||
| 163 | /* Deliver a copy of message to each destination port */ | ||
| 164 | if (dp->count != 0) { | ||
| 165 | msg_set_destnode(msg, tipc_own_addr); | ||
| 166 | if (dp->count == 1) { | ||
| 167 | msg_set_destport(msg, dp->ports[0]); | ||
| 168 | tipc_sk_rcv(buf); | ||
| 169 | tipc_port_list_free(dp); | ||
| 170 | return; | ||
| 171 | } | ||
| 172 | for (; cnt < dp->count; cnt++) { | ||
| 173 | int index = cnt % PLSIZE; | ||
| 174 | struct sk_buff *b = skb_clone(buf, GFP_ATOMIC); | ||
| 175 | |||
| 176 | if (b == NULL) { | ||
| 177 | pr_warn("Unable to deliver multicast message(s)\n"); | ||
| 178 | goto exit; | ||
| 179 | } | ||
| 180 | if ((index == 0) && (cnt != 0)) | ||
| 181 | item = item->next; | ||
| 182 | msg_set_destport(buf_msg(b), item->ports[index]); | ||
| 183 | tipc_sk_rcv(b); | ||
| 184 | } | ||
| 185 | } | ||
| 186 | exit: | ||
| 187 | kfree_skb(buf); | ||
| 188 | tipc_port_list_free(dp); | ||
| 189 | } | ||
| 190 | |||
| 191 | |||
| 192 | void tipc_port_wakeup(struct tipc_port *port) | ||
| 193 | { | ||
| 194 | tipc_sock_wakeup(tipc_port_to_sock(port)); | ||
| 195 | } | ||
| 196 | |||
| 197 | /* tipc_port_init - intiate TIPC port and lock it | 77 | /* tipc_port_init - intiate TIPC port and lock it |
| 198 | * | 78 | * |
| 199 | * Returns obtained reference if initialization is successful, zero otherwise | 79 | * Returns obtained reference if initialization is successful, zero otherwise |
| @@ -235,6 +115,8 @@ u32 tipc_port_init(struct tipc_port *p_ptr, | |||
| 235 | void tipc_port_destroy(struct tipc_port *p_ptr) | 115 | void tipc_port_destroy(struct tipc_port *p_ptr) |
| 236 | { | 116 | { |
| 237 | struct sk_buff *buf = NULL; | 117 | struct sk_buff *buf = NULL; |
| 118 | struct tipc_msg *msg = NULL; | ||
| 119 | u32 peer; | ||
| 238 | 120 | ||
| 239 | tipc_withdraw(p_ptr, 0, NULL); | 121 | tipc_withdraw(p_ptr, 0, NULL); |
| 240 | 122 | ||
| @@ -246,14 +128,15 @@ void tipc_port_destroy(struct tipc_port *p_ptr) | |||
| 246 | if (p_ptr->connected) { | 128 | if (p_ptr->connected) { |
| 247 | buf = port_build_peer_abort_msg(p_ptr, TIPC_ERR_NO_PORT); | 129 | buf = port_build_peer_abort_msg(p_ptr, TIPC_ERR_NO_PORT); |
| 248 | tipc_nodesub_unsubscribe(&p_ptr->subscription); | 130 | tipc_nodesub_unsubscribe(&p_ptr->subscription); |
| 131 | msg = buf_msg(buf); | ||
| 132 | peer = msg_destnode(msg); | ||
| 133 | tipc_link_xmit(buf, peer, msg_link_selector(msg)); | ||
| 249 | } | 134 | } |
| 250 | |||
| 251 | spin_lock_bh(&tipc_port_list_lock); | 135 | spin_lock_bh(&tipc_port_list_lock); |
| 252 | list_del(&p_ptr->port_list); | 136 | list_del(&p_ptr->port_list); |
| 253 | list_del(&p_ptr->wait_list); | 137 | list_del(&p_ptr->wait_list); |
| 254 | spin_unlock_bh(&tipc_port_list_lock); | 138 | spin_unlock_bh(&tipc_port_list_lock); |
| 255 | k_term_timer(&p_ptr->timer); | 139 | k_term_timer(&p_ptr->timer); |
| 256 | tipc_net_route_msg(buf); | ||
| 257 | } | 140 | } |
| 258 | 141 | ||
| 259 | /* | 142 | /* |
| @@ -275,100 +158,16 @@ static struct sk_buff *port_build_proto_msg(struct tipc_port *p_ptr, | |||
| 275 | msg_set_destport(msg, tipc_port_peerport(p_ptr)); | 158 | msg_set_destport(msg, tipc_port_peerport(p_ptr)); |
| 276 | msg_set_origport(msg, p_ptr->ref); | 159 | msg_set_origport(msg, p_ptr->ref); |
| 277 | msg_set_msgcnt(msg, ack); | 160 | msg_set_msgcnt(msg, ack); |
| 161 | buf->next = NULL; | ||
| 278 | } | 162 | } |
| 279 | return buf; | 163 | return buf; |
| 280 | } | 164 | } |
| 281 | 165 | ||
| 282 | int tipc_reject_msg(struct sk_buff *buf, u32 err) | ||
| 283 | { | ||
| 284 | struct tipc_msg *msg = buf_msg(buf); | ||
| 285 | struct sk_buff *rbuf; | ||
| 286 | struct tipc_msg *rmsg; | ||
| 287 | int hdr_sz; | ||
| 288 | u32 imp; | ||
| 289 | u32 data_sz = msg_data_sz(msg); | ||
| 290 | u32 src_node; | ||
| 291 | u32 rmsg_sz; | ||
| 292 | |||
| 293 | /* discard rejected message if it shouldn't be returned to sender */ | ||
| 294 | if (WARN(!msg_isdata(msg), | ||
| 295 | "attempt to reject message with user=%u", msg_user(msg))) { | ||
| 296 | dump_stack(); | ||
| 297 | goto exit; | ||
| 298 | } | ||
| 299 | if (msg_errcode(msg) || msg_dest_droppable(msg)) | ||
| 300 | goto exit; | ||
| 301 | |||
| 302 | /* | ||
| 303 | * construct returned message by copying rejected message header and | ||
| 304 | * data (or subset), then updating header fields that need adjusting | ||
| 305 | */ | ||
| 306 | hdr_sz = msg_hdr_sz(msg); | ||
| 307 | rmsg_sz = hdr_sz + min_t(u32, data_sz, MAX_REJECT_SIZE); | ||
| 308 | |||
| 309 | rbuf = tipc_buf_acquire(rmsg_sz); | ||
| 310 | if (rbuf == NULL) | ||
| 311 | goto exit; | ||
| 312 | |||
| 313 | rmsg = buf_msg(rbuf); | ||
| 314 | skb_copy_to_linear_data(rbuf, msg, rmsg_sz); | ||
| 315 | |||
| 316 | if (msg_connected(rmsg)) { | ||
| 317 | imp = msg_importance(rmsg); | ||
| 318 | if (imp < TIPC_CRITICAL_IMPORTANCE) | ||
| 319 | msg_set_importance(rmsg, ++imp); | ||
| 320 | } | ||
| 321 | msg_set_non_seq(rmsg, 0); | ||
| 322 | msg_set_size(rmsg, rmsg_sz); | ||
| 323 | msg_set_errcode(rmsg, err); | ||
| 324 | msg_set_prevnode(rmsg, tipc_own_addr); | ||
| 325 | msg_swap_words(rmsg, 4, 5); | ||
| 326 | if (!msg_short(rmsg)) | ||
| 327 | msg_swap_words(rmsg, 6, 7); | ||
| 328 | |||
| 329 | /* send self-abort message when rejecting on a connected port */ | ||
| 330 | if (msg_connected(msg)) { | ||
| 331 | struct tipc_port *p_ptr = tipc_port_lock(msg_destport(msg)); | ||
| 332 | |||
| 333 | if (p_ptr) { | ||
| 334 | struct sk_buff *abuf = NULL; | ||
| 335 | |||
| 336 | if (p_ptr->connected) | ||
| 337 | abuf = port_build_self_abort_msg(p_ptr, err); | ||
| 338 | tipc_port_unlock(p_ptr); | ||
| 339 | tipc_net_route_msg(abuf); | ||
| 340 | } | ||
| 341 | } | ||
| 342 | |||
| 343 | /* send returned message & dispose of rejected message */ | ||
| 344 | src_node = msg_prevnode(msg); | ||
| 345 | if (in_own_node(src_node)) | ||
| 346 | tipc_sk_rcv(rbuf); | ||
| 347 | else | ||
| 348 | tipc_link_xmit(rbuf, src_node, msg_link_selector(rmsg)); | ||
| 349 | exit: | ||
| 350 | kfree_skb(buf); | ||
| 351 | return data_sz; | ||
| 352 | } | ||
| 353 | |||
| 354 | int tipc_port_iovec_reject(struct tipc_port *p_ptr, struct tipc_msg *hdr, | ||
| 355 | struct iovec const *msg_sect, unsigned int len, | ||
| 356 | int err) | ||
| 357 | { | ||
| 358 | struct sk_buff *buf; | ||
| 359 | int res; | ||
| 360 | |||
| 361 | res = tipc_msg_build(hdr, msg_sect, len, MAX_MSG_SIZE, &buf); | ||
| 362 | if (!buf) | ||
| 363 | return res; | ||
| 364 | |||
| 365 | return tipc_reject_msg(buf, err); | ||
| 366 | } | ||
| 367 | |||
| 368 | static void port_timeout(unsigned long ref) | 166 | static void port_timeout(unsigned long ref) |
| 369 | { | 167 | { |
| 370 | struct tipc_port *p_ptr = tipc_port_lock(ref); | 168 | struct tipc_port *p_ptr = tipc_port_lock(ref); |
| 371 | struct sk_buff *buf = NULL; | 169 | struct sk_buff *buf = NULL; |
| 170 | struct tipc_msg *msg = NULL; | ||
| 372 | 171 | ||
| 373 | if (!p_ptr) | 172 | if (!p_ptr) |
| 374 | return; | 173 | return; |
| @@ -379,15 +178,16 @@ static void port_timeout(unsigned long ref) | |||
| 379 | } | 178 | } |
| 380 | 179 | ||
| 381 | /* Last probe answered ? */ | 180 | /* Last probe answered ? */ |
| 382 | if (p_ptr->probing_state == PROBING) { | 181 | if (p_ptr->probing_state == TIPC_CONN_PROBING) { |
| 383 | buf = port_build_self_abort_msg(p_ptr, TIPC_ERR_NO_PORT); | 182 | buf = port_build_self_abort_msg(p_ptr, TIPC_ERR_NO_PORT); |
| 384 | } else { | 183 | } else { |
| 385 | buf = port_build_proto_msg(p_ptr, CONN_PROBE, 0); | 184 | buf = port_build_proto_msg(p_ptr, CONN_PROBE, 0); |
| 386 | p_ptr->probing_state = PROBING; | 185 | p_ptr->probing_state = TIPC_CONN_PROBING; |
| 387 | k_start_timer(&p_ptr->timer, p_ptr->probing_interval); | 186 | k_start_timer(&p_ptr->timer, p_ptr->probing_interval); |
| 388 | } | 187 | } |
| 389 | tipc_port_unlock(p_ptr); | 188 | tipc_port_unlock(p_ptr); |
| 390 | tipc_net_route_msg(buf); | 189 | msg = buf_msg(buf); |
| 190 | tipc_link_xmit(buf, msg_destnode(msg), msg_link_selector(msg)); | ||
| 391 | } | 191 | } |
| 392 | 192 | ||
| 393 | 193 | ||
| @@ -395,12 +195,14 @@ static void port_handle_node_down(unsigned long ref) | |||
| 395 | { | 195 | { |
| 396 | struct tipc_port *p_ptr = tipc_port_lock(ref); | 196 | struct tipc_port *p_ptr = tipc_port_lock(ref); |
| 397 | struct sk_buff *buf = NULL; | 197 | struct sk_buff *buf = NULL; |
| 198 | struct tipc_msg *msg = NULL; | ||
| 398 | 199 | ||
| 399 | if (!p_ptr) | 200 | if (!p_ptr) |
| 400 | return; | 201 | return; |
| 401 | buf = port_build_self_abort_msg(p_ptr, TIPC_ERR_NO_NODE); | 202 | buf = port_build_self_abort_msg(p_ptr, TIPC_ERR_NO_NODE); |
| 402 | tipc_port_unlock(p_ptr); | 203 | tipc_port_unlock(p_ptr); |
| 403 | tipc_net_route_msg(buf); | 204 | msg = buf_msg(buf); |
| 205 | tipc_link_xmit(buf, msg_destnode(msg), msg_link_selector(msg)); | ||
| 404 | } | 206 | } |
| 405 | 207 | ||
| 406 | 208 | ||
| @@ -412,6 +214,7 @@ static struct sk_buff *port_build_self_abort_msg(struct tipc_port *p_ptr, u32 er | |||
| 412 | struct tipc_msg *msg = buf_msg(buf); | 214 | struct tipc_msg *msg = buf_msg(buf); |
| 413 | msg_swap_words(msg, 4, 5); | 215 | msg_swap_words(msg, 4, 5); |
| 414 | msg_swap_words(msg, 6, 7); | 216 | msg_swap_words(msg, 6, 7); |
| 217 | buf->next = NULL; | ||
| 415 | } | 218 | } |
| 416 | return buf; | 219 | return buf; |
| 417 | } | 220 | } |
| @@ -436,60 +239,11 @@ static struct sk_buff *port_build_peer_abort_msg(struct tipc_port *p_ptr, u32 er | |||
| 436 | if (imp < TIPC_CRITICAL_IMPORTANCE) | 239 | if (imp < TIPC_CRITICAL_IMPORTANCE) |
| 437 | msg_set_importance(msg, ++imp); | 240 | msg_set_importance(msg, ++imp); |
| 438 | msg_set_errcode(msg, err); | 241 | msg_set_errcode(msg, err); |
| 242 | buf->next = NULL; | ||
| 439 | } | 243 | } |
| 440 | return buf; | 244 | return buf; |
| 441 | } | 245 | } |
| 442 | 246 | ||
| 443 | void tipc_port_proto_rcv(struct sk_buff *buf) | ||
| 444 | { | ||
| 445 | struct tipc_msg *msg = buf_msg(buf); | ||
| 446 | struct tipc_port *p_ptr; | ||
| 447 | struct sk_buff *r_buf = NULL; | ||
| 448 | u32 destport = msg_destport(msg); | ||
| 449 | int wakeable; | ||
| 450 | |||
| 451 | /* Validate connection */ | ||
| 452 | p_ptr = tipc_port_lock(destport); | ||
| 453 | if (!p_ptr || !p_ptr->connected || !tipc_port_peer_msg(p_ptr, msg)) { | ||
| 454 | r_buf = tipc_buf_acquire(BASIC_H_SIZE); | ||
| 455 | if (r_buf) { | ||
| 456 | msg = buf_msg(r_buf); | ||
| 457 | tipc_msg_init(msg, TIPC_HIGH_IMPORTANCE, TIPC_CONN_MSG, | ||
| 458 | BASIC_H_SIZE, msg_orignode(msg)); | ||
| 459 | msg_set_errcode(msg, TIPC_ERR_NO_PORT); | ||
| 460 | msg_set_origport(msg, destport); | ||
| 461 | msg_set_destport(msg, msg_origport(msg)); | ||
| 462 | } | ||
| 463 | if (p_ptr) | ||
| 464 | tipc_port_unlock(p_ptr); | ||
| 465 | goto exit; | ||
| 466 | } | ||
| 467 | |||
| 468 | /* Process protocol message sent by peer */ | ||
| 469 | switch (msg_type(msg)) { | ||
| 470 | case CONN_ACK: | ||
| 471 | wakeable = tipc_port_congested(p_ptr) && p_ptr->congested; | ||
| 472 | p_ptr->acked += msg_msgcnt(msg); | ||
| 473 | if (!tipc_port_congested(p_ptr)) { | ||
| 474 | p_ptr->congested = 0; | ||
| 475 | if (wakeable) | ||
| 476 | tipc_port_wakeup(p_ptr); | ||
| 477 | } | ||
| 478 | break; | ||
| 479 | case CONN_PROBE: | ||
| 480 | r_buf = port_build_proto_msg(p_ptr, CONN_PROBE_REPLY, 0); | ||
| 481 | break; | ||
| 482 | default: | ||
| 483 | /* CONN_PROBE_REPLY or unrecognized - no action required */ | ||
| 484 | break; | ||
| 485 | } | ||
| 486 | p_ptr->probing_state = CONFIRMED; | ||
| 487 | tipc_port_unlock(p_ptr); | ||
| 488 | exit: | ||
| 489 | tipc_net_route_msg(r_buf); | ||
| 490 | kfree_skb(buf); | ||
| 491 | } | ||
| 492 | |||
| 493 | static int port_print(struct tipc_port *p_ptr, char *buf, int len, int full_id) | 247 | static int port_print(struct tipc_port *p_ptr, char *buf, int len, int full_id) |
| 494 | { | 248 | { |
| 495 | struct publication *publ; | 249 | struct publication *publ; |
| @@ -581,16 +335,19 @@ void tipc_acknowledge(u32 ref, u32 ack) | |||
| 581 | { | 335 | { |
| 582 | struct tipc_port *p_ptr; | 336 | struct tipc_port *p_ptr; |
| 583 | struct sk_buff *buf = NULL; | 337 | struct sk_buff *buf = NULL; |
| 338 | struct tipc_msg *msg; | ||
| 584 | 339 | ||
| 585 | p_ptr = tipc_port_lock(ref); | 340 | p_ptr = tipc_port_lock(ref); |
| 586 | if (!p_ptr) | 341 | if (!p_ptr) |
| 587 | return; | 342 | return; |
| 588 | if (p_ptr->connected) { | 343 | if (p_ptr->connected) |
| 589 | p_ptr->conn_unacked -= ack; | ||
| 590 | buf = port_build_proto_msg(p_ptr, CONN_ACK, ack); | 344 | buf = port_build_proto_msg(p_ptr, CONN_ACK, ack); |
| 591 | } | 345 | |
| 592 | tipc_port_unlock(p_ptr); | 346 | tipc_port_unlock(p_ptr); |
| 593 | tipc_net_route_msg(buf); | 347 | if (!buf) |
| 348 | return; | ||
| 349 | msg = buf_msg(buf); | ||
| 350 | tipc_link_xmit(buf, msg_destnode(msg), msg_link_selector(msg)); | ||
| 594 | } | 351 | } |
| 595 | 352 | ||
| 596 | int tipc_publish(struct tipc_port *p_ptr, unsigned int scope, | 353 | int tipc_publish(struct tipc_port *p_ptr, unsigned int scope, |
| @@ -689,7 +446,7 @@ int __tipc_port_connect(u32 ref, struct tipc_port *p_ptr, | |||
| 689 | msg_set_hdr_sz(msg, SHORT_H_SIZE); | 446 | msg_set_hdr_sz(msg, SHORT_H_SIZE); |
| 690 | 447 | ||
| 691 | p_ptr->probing_interval = PROBING_INTERVAL; | 448 | p_ptr->probing_interval = PROBING_INTERVAL; |
| 692 | p_ptr->probing_state = CONFIRMED; | 449 | p_ptr->probing_state = TIPC_CONN_OK; |
| 693 | p_ptr->connected = 1; | 450 | p_ptr->connected = 1; |
| 694 | k_start_timer(&p_ptr->timer, p_ptr->probing_interval); | 451 | k_start_timer(&p_ptr->timer, p_ptr->probing_interval); |
| 695 | 452 | ||
| @@ -698,7 +455,7 @@ int __tipc_port_connect(u32 ref, struct tipc_port *p_ptr, | |||
| 698 | (net_ev_handler)port_handle_node_down); | 455 | (net_ev_handler)port_handle_node_down); |
| 699 | res = 0; | 456 | res = 0; |
| 700 | exit: | 457 | exit: |
| 701 | p_ptr->max_pkt = tipc_link_get_max_pkt(peer->node, ref); | 458 | p_ptr->max_pkt = tipc_node_get_mtu(peer->node, ref); |
| 702 | return res; | 459 | return res; |
| 703 | } | 460 | } |
| 704 | 461 | ||
| @@ -741,6 +498,7 @@ int tipc_port_disconnect(u32 ref) | |||
| 741 | */ | 498 | */ |
| 742 | int tipc_port_shutdown(u32 ref) | 499 | int tipc_port_shutdown(u32 ref) |
| 743 | { | 500 | { |
| 501 | struct tipc_msg *msg; | ||
| 744 | struct tipc_port *p_ptr; | 502 | struct tipc_port *p_ptr; |
| 745 | struct sk_buff *buf = NULL; | 503 | struct sk_buff *buf = NULL; |
| 746 | 504 | ||
| @@ -750,149 +508,7 @@ int tipc_port_shutdown(u32 ref) | |||
| 750 | 508 | ||
| 751 | buf = port_build_peer_abort_msg(p_ptr, TIPC_CONN_SHUTDOWN); | 509 | buf = port_build_peer_abort_msg(p_ptr, TIPC_CONN_SHUTDOWN); |
| 752 | tipc_port_unlock(p_ptr); | 510 | tipc_port_unlock(p_ptr); |
| 753 | tipc_net_route_msg(buf); | 511 | msg = buf_msg(buf); |
| 512 | tipc_link_xmit(buf, msg_destnode(msg), msg_link_selector(msg)); | ||
| 754 | return tipc_port_disconnect(ref); | 513 | return tipc_port_disconnect(ref); |
| 755 | } | 514 | } |
| 756 | |||
| 757 | /* | ||
| 758 | * tipc_port_iovec_rcv: Concatenate and deliver sectioned | ||
| 759 | * message for this node. | ||
| 760 | */ | ||
| 761 | static int tipc_port_iovec_rcv(struct tipc_port *sender, | ||
| 762 | struct iovec const *msg_sect, | ||
| 763 | unsigned int len) | ||
| 764 | { | ||
| 765 | struct sk_buff *buf; | ||
| 766 | int res; | ||
| 767 | |||
| 768 | res = tipc_msg_build(&sender->phdr, msg_sect, len, MAX_MSG_SIZE, &buf); | ||
| 769 | if (likely(buf)) | ||
| 770 | tipc_sk_rcv(buf); | ||
| 771 | return res; | ||
| 772 | } | ||
| 773 | |||
| 774 | /** | ||
| 775 | * tipc_send - send message sections on connection | ||
| 776 | */ | ||
| 777 | int tipc_send(struct tipc_port *p_ptr, | ||
| 778 | struct iovec const *msg_sect, | ||
| 779 | unsigned int len) | ||
| 780 | { | ||
| 781 | u32 destnode; | ||
| 782 | int res; | ||
| 783 | |||
| 784 | if (!p_ptr->connected) | ||
| 785 | return -EINVAL; | ||
| 786 | |||
| 787 | p_ptr->congested = 1; | ||
| 788 | if (!tipc_port_congested(p_ptr)) { | ||
| 789 | destnode = tipc_port_peernode(p_ptr); | ||
| 790 | if (likely(!in_own_node(destnode))) | ||
| 791 | res = tipc_link_iovec_xmit_fast(p_ptr, msg_sect, len, | ||
| 792 | destnode); | ||
| 793 | else | ||
| 794 | res = tipc_port_iovec_rcv(p_ptr, msg_sect, len); | ||
| 795 | |||
| 796 | if (likely(res != -ELINKCONG)) { | ||
| 797 | p_ptr->congested = 0; | ||
| 798 | if (res > 0) | ||
| 799 | p_ptr->sent++; | ||
| 800 | return res; | ||
| 801 | } | ||
| 802 | } | ||
| 803 | if (tipc_port_unreliable(p_ptr)) { | ||
| 804 | p_ptr->congested = 0; | ||
| 805 | return len; | ||
| 806 | } | ||
| 807 | return -ELINKCONG; | ||
| 808 | } | ||
| 809 | |||
| 810 | /** | ||
| 811 | * tipc_send2name - send message sections to port name | ||
| 812 | */ | ||
| 813 | int tipc_send2name(struct tipc_port *p_ptr, | ||
| 814 | struct tipc_name const *name, | ||
| 815 | unsigned int domain, | ||
| 816 | struct iovec const *msg_sect, | ||
| 817 | unsigned int len) | ||
| 818 | { | ||
| 819 | struct tipc_msg *msg; | ||
| 820 | u32 destnode = domain; | ||
| 821 | u32 destport; | ||
| 822 | int res; | ||
| 823 | |||
| 824 | if (p_ptr->connected) | ||
| 825 | return -EINVAL; | ||
| 826 | |||
| 827 | msg = &p_ptr->phdr; | ||
| 828 | msg_set_type(msg, TIPC_NAMED_MSG); | ||
| 829 | msg_set_hdr_sz(msg, NAMED_H_SIZE); | ||
| 830 | msg_set_nametype(msg, name->type); | ||
| 831 | msg_set_nameinst(msg, name->instance); | ||
| 832 | msg_set_lookup_scope(msg, tipc_addr_scope(domain)); | ||
| 833 | destport = tipc_nametbl_translate(name->type, name->instance, &destnode); | ||
| 834 | msg_set_destnode(msg, destnode); | ||
| 835 | msg_set_destport(msg, destport); | ||
| 836 | |||
| 837 | if (likely(destport || destnode)) { | ||
| 838 | if (likely(in_own_node(destnode))) | ||
| 839 | res = tipc_port_iovec_rcv(p_ptr, msg_sect, len); | ||
| 840 | else if (tipc_own_addr) | ||
| 841 | res = tipc_link_iovec_xmit_fast(p_ptr, msg_sect, len, | ||
| 842 | destnode); | ||
| 843 | else | ||
| 844 | res = tipc_port_iovec_reject(p_ptr, msg, msg_sect, | ||
| 845 | len, TIPC_ERR_NO_NODE); | ||
| 846 | if (likely(res != -ELINKCONG)) { | ||
| 847 | if (res > 0) | ||
| 848 | p_ptr->sent++; | ||
| 849 | return res; | ||
| 850 | } | ||
| 851 | if (tipc_port_unreliable(p_ptr)) | ||
| 852 | return len; | ||
| 853 | |||
| 854 | return -ELINKCONG; | ||
| 855 | } | ||
| 856 | return tipc_port_iovec_reject(p_ptr, msg, msg_sect, len, | ||
| 857 | TIPC_ERR_NO_NAME); | ||
| 858 | } | ||
| 859 | |||
| 860 | /** | ||
| 861 | * tipc_send2port - send message sections to port identity | ||
| 862 | */ | ||
| 863 | int tipc_send2port(struct tipc_port *p_ptr, | ||
| 864 | struct tipc_portid const *dest, | ||
| 865 | struct iovec const *msg_sect, | ||
| 866 | unsigned int len) | ||
| 867 | { | ||
| 868 | struct tipc_msg *msg; | ||
| 869 | int res; | ||
| 870 | |||
| 871 | if (p_ptr->connected) | ||
| 872 | return -EINVAL; | ||
| 873 | |||
| 874 | msg = &p_ptr->phdr; | ||
| 875 | msg_set_type(msg, TIPC_DIRECT_MSG); | ||
| 876 | msg_set_lookup_scope(msg, 0); | ||
| 877 | msg_set_destnode(msg, dest->node); | ||
| 878 | msg_set_destport(msg, dest->ref); | ||
| 879 | msg_set_hdr_sz(msg, BASIC_H_SIZE); | ||
| 880 | |||
| 881 | if (in_own_node(dest->node)) | ||
| 882 | res = tipc_port_iovec_rcv(p_ptr, msg_sect, len); | ||
| 883 | else if (tipc_own_addr) | ||
| 884 | res = tipc_link_iovec_xmit_fast(p_ptr, msg_sect, len, | ||
| 885 | dest->node); | ||
| 886 | else | ||
| 887 | res = tipc_port_iovec_reject(p_ptr, msg, msg_sect, len, | ||
| 888 | TIPC_ERR_NO_NODE); | ||
| 889 | if (likely(res != -ELINKCONG)) { | ||
| 890 | if (res > 0) | ||
| 891 | p_ptr->sent++; | ||
| 892 | return res; | ||
| 893 | } | ||
| 894 | if (tipc_port_unreliable(p_ptr)) | ||
| 895 | return len; | ||
| 896 | |||
| 897 | return -ELINKCONG; | ||
| 898 | } | ||
diff --git a/net/tipc/port.h b/net/tipc/port.h index cf4ca5b1d9a4..3f93454592b6 100644 --- a/net/tipc/port.h +++ b/net/tipc/port.h | |||
| @@ -53,17 +53,13 @@ | |||
| 53 | * @connected: non-zero if port is currently connected to a peer port | 53 | * @connected: non-zero if port is currently connected to a peer port |
| 54 | * @conn_type: TIPC type used when connection was established | 54 | * @conn_type: TIPC type used when connection was established |
| 55 | * @conn_instance: TIPC instance used when connection was established | 55 | * @conn_instance: TIPC instance used when connection was established |
| 56 | * @conn_unacked: number of unacknowledged messages received from peer port | ||
| 57 | * @published: non-zero if port has one or more associated names | 56 | * @published: non-zero if port has one or more associated names |
| 58 | * @congested: non-zero if cannot send because of link or port congestion | ||
| 59 | * @max_pkt: maximum packet size "hint" used when building messages sent by port | 57 | * @max_pkt: maximum packet size "hint" used when building messages sent by port |
| 60 | * @ref: unique reference to port in TIPC object registry | 58 | * @ref: unique reference to port in TIPC object registry |
| 61 | * @phdr: preformatted message header used when sending messages | 59 | * @phdr: preformatted message header used when sending messages |
| 62 | * @port_list: adjacent ports in TIPC's global list of ports | 60 | * @port_list: adjacent ports in TIPC's global list of ports |
| 63 | * @wait_list: adjacent ports in list of ports waiting on link congestion | 61 | * @wait_list: adjacent ports in list of ports waiting on link congestion |
| 64 | * @waiting_pkts: | 62 | * @waiting_pkts: |
| 65 | * @sent: # of non-empty messages sent by port | ||
| 66 | * @acked: # of non-empty message acknowledgements from connected port's peer | ||
| 67 | * @publications: list of publications for port | 63 | * @publications: list of publications for port |
| 68 | * @pub_count: total # of publications port has made during its lifetime | 64 | * @pub_count: total # of publications port has made during its lifetime |
| 69 | * @probing_state: | 65 | * @probing_state: |
| @@ -76,17 +72,13 @@ struct tipc_port { | |||
| 76 | int connected; | 72 | int connected; |
| 77 | u32 conn_type; | 73 | u32 conn_type; |
| 78 | u32 conn_instance; | 74 | u32 conn_instance; |
| 79 | u32 conn_unacked; | ||
| 80 | int published; | 75 | int published; |
| 81 | u32 congested; | ||
| 82 | u32 max_pkt; | 76 | u32 max_pkt; |
| 83 | u32 ref; | 77 | u32 ref; |
| 84 | struct tipc_msg phdr; | 78 | struct tipc_msg phdr; |
| 85 | struct list_head port_list; | 79 | struct list_head port_list; |
| 86 | struct list_head wait_list; | 80 | struct list_head wait_list; |
| 87 | u32 waiting_pkts; | 81 | u32 waiting_pkts; |
| 88 | u32 sent; | ||
| 89 | u32 acked; | ||
| 90 | struct list_head publications; | 82 | struct list_head publications; |
| 91 | u32 pub_count; | 83 | u32 pub_count; |
| 92 | u32 probing_state; | 84 | u32 probing_state; |
| @@ -104,8 +96,6 @@ struct tipc_port_list; | |||
| 104 | u32 tipc_port_init(struct tipc_port *p_ptr, | 96 | u32 tipc_port_init(struct tipc_port *p_ptr, |
| 105 | const unsigned int importance); | 97 | const unsigned int importance); |
| 106 | 98 | ||
| 107 | int tipc_reject_msg(struct sk_buff *buf, u32 err); | ||
| 108 | |||
| 109 | void tipc_acknowledge(u32 port_ref, u32 ack); | 99 | void tipc_acknowledge(u32 port_ref, u32 ack); |
| 110 | 100 | ||
| 111 | void tipc_port_destroy(struct tipc_port *p_ptr); | 101 | void tipc_port_destroy(struct tipc_port *p_ptr); |
| @@ -122,8 +112,6 @@ int tipc_port_disconnect(u32 portref); | |||
| 122 | 112 | ||
| 123 | int tipc_port_shutdown(u32 ref); | 113 | int tipc_port_shutdown(u32 ref); |
| 124 | 114 | ||
| 125 | void tipc_port_wakeup(struct tipc_port *port); | ||
| 126 | |||
| 127 | /* | 115 | /* |
| 128 | * The following routines require that the port be locked on entry | 116 | * The following routines require that the port be locked on entry |
| 129 | */ | 117 | */ |
| @@ -132,39 +120,7 @@ int __tipc_port_connect(u32 ref, struct tipc_port *p_ptr, | |||
| 132 | struct tipc_portid const *peer); | 120 | struct tipc_portid const *peer); |
| 133 | int tipc_port_peer_msg(struct tipc_port *p_ptr, struct tipc_msg *msg); | 121 | int tipc_port_peer_msg(struct tipc_port *p_ptr, struct tipc_msg *msg); |
| 134 | 122 | ||
| 135 | /* | ||
| 136 | * TIPC messaging routines | ||
| 137 | */ | ||
| 138 | |||
| 139 | int tipc_send(struct tipc_port *port, | ||
| 140 | struct iovec const *msg_sect, | ||
| 141 | unsigned int len); | ||
| 142 | |||
| 143 | int tipc_send2name(struct tipc_port *port, | ||
| 144 | struct tipc_name const *name, | ||
| 145 | u32 domain, | ||
| 146 | struct iovec const *msg_sect, | ||
| 147 | unsigned int len); | ||
| 148 | |||
| 149 | int tipc_send2port(struct tipc_port *port, | ||
| 150 | struct tipc_portid const *dest, | ||
| 151 | struct iovec const *msg_sect, | ||
| 152 | unsigned int len); | ||
| 153 | |||
| 154 | int tipc_port_mcast_xmit(struct tipc_port *port, | ||
| 155 | struct tipc_name_seq const *seq, | ||
| 156 | struct iovec const *msg, | ||
| 157 | unsigned int len); | ||
| 158 | |||
| 159 | int tipc_port_iovec_reject(struct tipc_port *p_ptr, | ||
| 160 | struct tipc_msg *hdr, | ||
| 161 | struct iovec const *msg_sect, | ||
| 162 | unsigned int len, | ||
| 163 | int err); | ||
| 164 | |||
| 165 | struct sk_buff *tipc_port_get_ports(void); | 123 | struct sk_buff *tipc_port_get_ports(void); |
| 166 | void tipc_port_proto_rcv(struct sk_buff *buf); | ||
| 167 | void tipc_port_mcast_rcv(struct sk_buff *buf, struct tipc_port_list *dp); | ||
| 168 | void tipc_port_reinit(void); | 124 | void tipc_port_reinit(void); |
| 169 | 125 | ||
| 170 | /** | 126 | /** |
| @@ -185,12 +141,6 @@ static inline void tipc_port_unlock(struct tipc_port *p_ptr) | |||
| 185 | spin_unlock_bh(p_ptr->lock); | 141 | spin_unlock_bh(p_ptr->lock); |
| 186 | } | 142 | } |
| 187 | 143 | ||
| 188 | static inline int tipc_port_congested(struct tipc_port *p_ptr) | ||
| 189 | { | ||
| 190 | return ((p_ptr->sent - p_ptr->acked) >= TIPC_FLOWCTRL_WIN); | ||
| 191 | } | ||
| 192 | |||
| 193 | |||
| 194 | static inline u32 tipc_port_peernode(struct tipc_port *p_ptr) | 144 | static inline u32 tipc_port_peernode(struct tipc_port *p_ptr) |
| 195 | { | 145 | { |
| 196 | return msg_destnode(&p_ptr->phdr); | 146 | return msg_destnode(&p_ptr->phdr); |
diff --git a/net/tipc/socket.c b/net/tipc/socket.c index ef0475568f9e..7d423ee10897 100644 --- a/net/tipc/socket.c +++ b/net/tipc/socket.c | |||
| @@ -36,20 +36,23 @@ | |||
| 36 | 36 | ||
| 37 | #include "core.h" | 37 | #include "core.h" |
| 38 | #include "port.h" | 38 | #include "port.h" |
| 39 | #include "name_table.h" | ||
| 39 | #include "node.h" | 40 | #include "node.h" |
| 40 | 41 | #include "link.h" | |
| 41 | #include <linux/export.h> | 42 | #include <linux/export.h> |
| 42 | 43 | ||
| 43 | #define SS_LISTENING -1 /* socket is listening */ | 44 | #define SS_LISTENING -1 /* socket is listening */ |
| 44 | #define SS_READY -2 /* socket is connectionless */ | 45 | #define SS_READY -2 /* socket is connectionless */ |
| 45 | 46 | ||
| 46 | #define CONN_TIMEOUT_DEFAULT 8000 /* default connect timeout = 8s */ | 47 | #define CONN_TIMEOUT_DEFAULT 8000 /* default connect timeout = 8s */ |
| 48 | #define TIPC_FWD_MSG 1 | ||
| 47 | 49 | ||
| 48 | static int tipc_backlog_rcv(struct sock *sk, struct sk_buff *skb); | 50 | static int tipc_backlog_rcv(struct sock *sk, struct sk_buff *skb); |
| 49 | static void tipc_data_ready(struct sock *sk); | 51 | static void tipc_data_ready(struct sock *sk); |
| 50 | static void tipc_write_space(struct sock *sk); | 52 | static void tipc_write_space(struct sock *sk); |
| 51 | static int tipc_release(struct socket *sock); | 53 | static int tipc_release(struct socket *sock); |
| 52 | static int tipc_accept(struct socket *sock, struct socket *new_sock, int flags); | 54 | static int tipc_accept(struct socket *sock, struct socket *new_sock, int flags); |
| 55 | static int tipc_wait_for_sndmsg(struct socket *sock, long *timeo_p); | ||
| 53 | 56 | ||
| 54 | static const struct proto_ops packet_ops; | 57 | static const struct proto_ops packet_ops; |
| 55 | static const struct proto_ops stream_ops; | 58 | static const struct proto_ops stream_ops; |
| @@ -123,9 +126,12 @@ static void advance_rx_queue(struct sock *sk) | |||
| 123 | static void reject_rx_queue(struct sock *sk) | 126 | static void reject_rx_queue(struct sock *sk) |
| 124 | { | 127 | { |
| 125 | struct sk_buff *buf; | 128 | struct sk_buff *buf; |
| 129 | u32 dnode; | ||
| 126 | 130 | ||
| 127 | while ((buf = __skb_dequeue(&sk->sk_receive_queue))) | 131 | while ((buf = __skb_dequeue(&sk->sk_receive_queue))) { |
| 128 | tipc_reject_msg(buf, TIPC_ERR_NO_PORT); | 132 | if (tipc_msg_reverse(buf, &dnode, TIPC_ERR_NO_PORT)) |
| 133 | tipc_link_xmit(buf, dnode, 0); | ||
| 134 | } | ||
| 129 | } | 135 | } |
| 130 | 136 | ||
| 131 | /** | 137 | /** |
| @@ -201,6 +207,7 @@ static int tipc_sk_create(struct net *net, struct socket *sock, | |||
| 201 | sk->sk_data_ready = tipc_data_ready; | 207 | sk->sk_data_ready = tipc_data_ready; |
| 202 | sk->sk_write_space = tipc_write_space; | 208 | sk->sk_write_space = tipc_write_space; |
| 203 | tsk->conn_timeout = CONN_TIMEOUT_DEFAULT; | 209 | tsk->conn_timeout = CONN_TIMEOUT_DEFAULT; |
| 210 | tsk->sent_unacked = 0; | ||
| 204 | atomic_set(&tsk->dupl_rcvcnt, 0); | 211 | atomic_set(&tsk->dupl_rcvcnt, 0); |
| 205 | tipc_port_unlock(port); | 212 | tipc_port_unlock(port); |
| 206 | 213 | ||
| @@ -303,6 +310,7 @@ static int tipc_release(struct socket *sock) | |||
| 303 | struct tipc_sock *tsk; | 310 | struct tipc_sock *tsk; |
| 304 | struct tipc_port *port; | 311 | struct tipc_port *port; |
| 305 | struct sk_buff *buf; | 312 | struct sk_buff *buf; |
| 313 | u32 dnode; | ||
| 306 | 314 | ||
| 307 | /* | 315 | /* |
| 308 | * Exit if socket isn't fully initialized (occurs when a failed accept() | 316 | * Exit if socket isn't fully initialized (occurs when a failed accept() |
| @@ -331,7 +339,8 @@ static int tipc_release(struct socket *sock) | |||
| 331 | sock->state = SS_DISCONNECTING; | 339 | sock->state = SS_DISCONNECTING; |
| 332 | tipc_port_disconnect(port->ref); | 340 | tipc_port_disconnect(port->ref); |
| 333 | } | 341 | } |
| 334 | tipc_reject_msg(buf, TIPC_ERR_NO_PORT); | 342 | if (tipc_msg_reverse(buf, &dnode, TIPC_ERR_NO_PORT)) |
| 343 | tipc_link_xmit(buf, dnode, 0); | ||
| 335 | } | 344 | } |
| 336 | } | 345 | } |
| 337 | 346 | ||
| @@ -504,12 +513,12 @@ static unsigned int tipc_poll(struct file *file, struct socket *sock, | |||
| 504 | 513 | ||
| 505 | switch ((int)sock->state) { | 514 | switch ((int)sock->state) { |
| 506 | case SS_UNCONNECTED: | 515 | case SS_UNCONNECTED: |
| 507 | if (!tsk->port.congested) | 516 | if (!tsk->link_cong) |
| 508 | mask |= POLLOUT; | 517 | mask |= POLLOUT; |
| 509 | break; | 518 | break; |
| 510 | case SS_READY: | 519 | case SS_READY: |
| 511 | case SS_CONNECTED: | 520 | case SS_CONNECTED: |
| 512 | if (!tsk->port.congested) | 521 | if (!tsk->link_cong && !tipc_sk_conn_cong(tsk)) |
| 513 | mask |= POLLOUT; | 522 | mask |= POLLOUT; |
| 514 | /* fall thru' */ | 523 | /* fall thru' */ |
| 515 | case SS_CONNECTING: | 524 | case SS_CONNECTING: |
| @@ -526,6 +535,136 @@ static unsigned int tipc_poll(struct file *file, struct socket *sock, | |||
| 526 | } | 535 | } |
| 527 | 536 | ||
| 528 | /** | 537 | /** |
| 538 | * tipc_sendmcast - send multicast message | ||
| 539 | * @sock: socket structure | ||
| 540 | * @seq: destination address | ||
| 541 | * @iov: message data to send | ||
| 542 | * @dsz: total length of message data | ||
| 543 | * @timeo: timeout to wait for wakeup | ||
| 544 | * | ||
| 545 | * Called from function tipc_sendmsg(), which has done all sanity checks | ||
| 546 | * Returns the number of bytes sent on success, or errno | ||
| 547 | */ | ||
| 548 | static int tipc_sendmcast(struct socket *sock, struct tipc_name_seq *seq, | ||
| 549 | struct iovec *iov, size_t dsz, long timeo) | ||
| 550 | { | ||
| 551 | struct sock *sk = sock->sk; | ||
| 552 | struct tipc_msg *mhdr = &tipc_sk(sk)->port.phdr; | ||
| 553 | struct sk_buff *buf; | ||
| 554 | uint mtu; | ||
| 555 | int rc; | ||
| 556 | |||
| 557 | msg_set_type(mhdr, TIPC_MCAST_MSG); | ||
| 558 | msg_set_lookup_scope(mhdr, TIPC_CLUSTER_SCOPE); | ||
| 559 | msg_set_destport(mhdr, 0); | ||
| 560 | msg_set_destnode(mhdr, 0); | ||
| 561 | msg_set_nametype(mhdr, seq->type); | ||
| 562 | msg_set_namelower(mhdr, seq->lower); | ||
| 563 | msg_set_nameupper(mhdr, seq->upper); | ||
| 564 | msg_set_hdr_sz(mhdr, MCAST_H_SIZE); | ||
| 565 | |||
| 566 | new_mtu: | ||
| 567 | mtu = tipc_bclink_get_mtu(); | ||
| 568 | rc = tipc_msg_build(mhdr, iov, 0, dsz, mtu, &buf); | ||
| 569 | if (unlikely(rc < 0)) | ||
| 570 | return rc; | ||
| 571 | |||
| 572 | do { | ||
| 573 | rc = tipc_bclink_xmit(buf); | ||
| 574 | if (likely(rc >= 0)) { | ||
| 575 | rc = dsz; | ||
| 576 | break; | ||
| 577 | } | ||
| 578 | if (rc == -EMSGSIZE) | ||
| 579 | goto new_mtu; | ||
| 580 | if (rc != -ELINKCONG) | ||
| 581 | break; | ||
| 582 | rc = tipc_wait_for_sndmsg(sock, &timeo); | ||
| 583 | if (rc) | ||
| 584 | kfree_skb_list(buf); | ||
| 585 | } while (!rc); | ||
| 586 | return rc; | ||
| 587 | } | ||
| 588 | |||
| 589 | /* tipc_sk_mcast_rcv - Deliver multicast message to all destination sockets | ||
| 590 | */ | ||
| 591 | void tipc_sk_mcast_rcv(struct sk_buff *buf) | ||
| 592 | { | ||
| 593 | struct tipc_msg *msg = buf_msg(buf); | ||
| 594 | struct tipc_port_list dports = {0, NULL, }; | ||
| 595 | struct tipc_port_list *item; | ||
| 596 | struct sk_buff *b; | ||
| 597 | uint i, last, dst = 0; | ||
| 598 | u32 scope = TIPC_CLUSTER_SCOPE; | ||
| 599 | |||
| 600 | if (in_own_node(msg_orignode(msg))) | ||
| 601 | scope = TIPC_NODE_SCOPE; | ||
| 602 | |||
| 603 | /* Create destination port list: */ | ||
| 604 | tipc_nametbl_mc_translate(msg_nametype(msg), | ||
| 605 | msg_namelower(msg), | ||
| 606 | msg_nameupper(msg), | ||
| 607 | scope, | ||
| 608 | &dports); | ||
| 609 | last = dports.count; | ||
| 610 | if (!last) { | ||
| 611 | kfree_skb(buf); | ||
| 612 | return; | ||
| 613 | } | ||
| 614 | |||
| 615 | for (item = &dports; item; item = item->next) { | ||
| 616 | for (i = 0; i < PLSIZE && ++dst <= last; i++) { | ||
| 617 | b = (dst != last) ? skb_clone(buf, GFP_ATOMIC) : buf; | ||
| 618 | if (!b) { | ||
| 619 | pr_warn("Failed do clone mcast rcv buffer\n"); | ||
| 620 | continue; | ||
| 621 | } | ||
| 622 | msg_set_destport(msg, item->ports[i]); | ||
| 623 | tipc_sk_rcv(b); | ||
| 624 | } | ||
| 625 | } | ||
| 626 | tipc_port_list_free(&dports); | ||
| 627 | } | ||
| 628 | |||
| 629 | /** | ||
| 630 | * tipc_sk_proto_rcv - receive a connection mng protocol message | ||
| 631 | * @tsk: receiving socket | ||
| 632 | * @dnode: node to send response message to, if any | ||
| 633 | * @buf: buffer containing protocol message | ||
| 634 | * Returns 0 (TIPC_OK) if message was consumed, 1 (TIPC_FWD_MSG) if | ||
| 635 | * (CONN_PROBE_REPLY) message should be forwarded. | ||
| 636 | */ | ||
| 637 | static int tipc_sk_proto_rcv(struct tipc_sock *tsk, u32 *dnode, | ||
| 638 | struct sk_buff *buf) | ||
| 639 | { | ||
| 640 | struct tipc_msg *msg = buf_msg(buf); | ||
| 641 | struct tipc_port *port = &tsk->port; | ||
| 642 | int conn_cong; | ||
| 643 | |||
| 644 | /* Ignore if connection cannot be validated: */ | ||
| 645 | if (!port->connected || !tipc_port_peer_msg(port, msg)) | ||
| 646 | goto exit; | ||
| 647 | |||
| 648 | port->probing_state = TIPC_CONN_OK; | ||
| 649 | |||
| 650 | if (msg_type(msg) == CONN_ACK) { | ||
| 651 | conn_cong = tipc_sk_conn_cong(tsk); | ||
| 652 | tsk->sent_unacked -= msg_msgcnt(msg); | ||
| 653 | if (conn_cong) | ||
| 654 | tipc_sock_wakeup(tsk); | ||
| 655 | } else if (msg_type(msg) == CONN_PROBE) { | ||
| 656 | if (!tipc_msg_reverse(buf, dnode, TIPC_OK)) | ||
| 657 | return TIPC_OK; | ||
| 658 | msg_set_type(msg, CONN_PROBE_REPLY); | ||
| 659 | return TIPC_FWD_MSG; | ||
| 660 | } | ||
| 661 | /* Do nothing if msg_type() == CONN_PROBE_REPLY */ | ||
| 662 | exit: | ||
| 663 | kfree_skb(buf); | ||
| 664 | return TIPC_OK; | ||
| 665 | } | ||
| 666 | |||
| 667 | /** | ||
| 529 | * dest_name_check - verify user is permitted to send to specified port name | 668 | * dest_name_check - verify user is permitted to send to specified port name |
| 530 | * @dest: destination address | 669 | * @dest: destination address |
| 531 | * @m: descriptor for message to be sent | 670 | * @m: descriptor for message to be sent |
| @@ -539,6 +678,8 @@ static int dest_name_check(struct sockaddr_tipc *dest, struct msghdr *m) | |||
| 539 | { | 678 | { |
| 540 | struct tipc_cfg_msg_hdr hdr; | 679 | struct tipc_cfg_msg_hdr hdr; |
| 541 | 680 | ||
| 681 | if (unlikely(dest->addrtype == TIPC_ADDR_ID)) | ||
| 682 | return 0; | ||
| 542 | if (likely(dest->addr.name.name.type >= TIPC_RESERVED_TYPES)) | 683 | if (likely(dest->addr.name.name.type >= TIPC_RESERVED_TYPES)) |
| 543 | return 0; | 684 | return 0; |
| 544 | if (likely(dest->addr.name.name.type == TIPC_TOP_SRV)) | 685 | if (likely(dest->addr.name.name.type == TIPC_TOP_SRV)) |
| @@ -575,19 +716,18 @@ static int tipc_wait_for_sndmsg(struct socket *sock, long *timeo_p) | |||
| 575 | return sock_intr_errno(*timeo_p); | 716 | return sock_intr_errno(*timeo_p); |
| 576 | 717 | ||
| 577 | prepare_to_wait(sk_sleep(sk), &wait, TASK_INTERRUPTIBLE); | 718 | prepare_to_wait(sk_sleep(sk), &wait, TASK_INTERRUPTIBLE); |
| 578 | done = sk_wait_event(sk, timeo_p, !tsk->port.congested); | 719 | done = sk_wait_event(sk, timeo_p, !tsk->link_cong); |
| 579 | finish_wait(sk_sleep(sk), &wait); | 720 | finish_wait(sk_sleep(sk), &wait); |
| 580 | } while (!done); | 721 | } while (!done); |
| 581 | return 0; | 722 | return 0; |
| 582 | } | 723 | } |
| 583 | 724 | ||
| 584 | |||
| 585 | /** | 725 | /** |
| 586 | * tipc_sendmsg - send message in connectionless manner | 726 | * tipc_sendmsg - send message in connectionless manner |
| 587 | * @iocb: if NULL, indicates that socket lock is already held | 727 | * @iocb: if NULL, indicates that socket lock is already held |
| 588 | * @sock: socket structure | 728 | * @sock: socket structure |
| 589 | * @m: message to send | 729 | * @m: message to send |
| 590 | * @total_len: length of message | 730 | * @dsz: amount of user data to be sent |
| 591 | * | 731 | * |
| 592 | * Message must have an destination specified explicitly. | 732 | * Message must have an destination specified explicitly. |
| 593 | * Used for SOCK_RDM and SOCK_DGRAM messages, | 733 | * Used for SOCK_RDM and SOCK_DGRAM messages, |
| @@ -597,100 +737,123 @@ static int tipc_wait_for_sndmsg(struct socket *sock, long *timeo_p) | |||
| 597 | * Returns the number of bytes sent on success, or errno otherwise | 737 | * Returns the number of bytes sent on success, or errno otherwise |
| 598 | */ | 738 | */ |
| 599 | static int tipc_sendmsg(struct kiocb *iocb, struct socket *sock, | 739 | static int tipc_sendmsg(struct kiocb *iocb, struct socket *sock, |
| 600 | struct msghdr *m, size_t total_len) | 740 | struct msghdr *m, size_t dsz) |
| 601 | { | 741 | { |
| 742 | DECLARE_SOCKADDR(struct sockaddr_tipc *, dest, m->msg_name); | ||
| 602 | struct sock *sk = sock->sk; | 743 | struct sock *sk = sock->sk; |
| 603 | struct tipc_sock *tsk = tipc_sk(sk); | 744 | struct tipc_sock *tsk = tipc_sk(sk); |
| 604 | struct tipc_port *port = &tsk->port; | 745 | struct tipc_port *port = &tsk->port; |
| 605 | DECLARE_SOCKADDR(struct sockaddr_tipc *, dest, m->msg_name); | 746 | struct tipc_msg *mhdr = &port->phdr; |
| 606 | int needs_conn; | 747 | struct iovec *iov = m->msg_iov; |
| 748 | u32 dnode, dport; | ||
| 749 | struct sk_buff *buf; | ||
| 750 | struct tipc_name_seq *seq = &dest->addr.nameseq; | ||
| 751 | u32 mtu; | ||
| 607 | long timeo; | 752 | long timeo; |
| 608 | int res = -EINVAL; | 753 | int rc = -EINVAL; |
| 609 | 754 | ||
| 610 | if (unlikely(!dest)) | 755 | if (unlikely(!dest)) |
| 611 | return -EDESTADDRREQ; | 756 | return -EDESTADDRREQ; |
| 757 | |||
| 612 | if (unlikely((m->msg_namelen < sizeof(*dest)) || | 758 | if (unlikely((m->msg_namelen < sizeof(*dest)) || |
| 613 | (dest->family != AF_TIPC))) | 759 | (dest->family != AF_TIPC))) |
| 614 | return -EINVAL; | 760 | return -EINVAL; |
| 615 | if (total_len > TIPC_MAX_USER_MSG_SIZE) | 761 | |
| 762 | if (dsz > TIPC_MAX_USER_MSG_SIZE) | ||
| 616 | return -EMSGSIZE; | 763 | return -EMSGSIZE; |
| 617 | 764 | ||
| 618 | if (iocb) | 765 | if (iocb) |
| 619 | lock_sock(sk); | 766 | lock_sock(sk); |
| 620 | 767 | ||
| 621 | needs_conn = (sock->state != SS_READY); | 768 | if (unlikely(sock->state != SS_READY)) { |
| 622 | if (unlikely(needs_conn)) { | ||
| 623 | if (sock->state == SS_LISTENING) { | 769 | if (sock->state == SS_LISTENING) { |
| 624 | res = -EPIPE; | 770 | rc = -EPIPE; |
| 625 | goto exit; | 771 | goto exit; |
| 626 | } | 772 | } |
| 627 | if (sock->state != SS_UNCONNECTED) { | 773 | if (sock->state != SS_UNCONNECTED) { |
| 628 | res = -EISCONN; | 774 | rc = -EISCONN; |
| 629 | goto exit; | 775 | goto exit; |
| 630 | } | 776 | } |
| 631 | if (tsk->port.published) { | 777 | if (tsk->port.published) { |
| 632 | res = -EOPNOTSUPP; | 778 | rc = -EOPNOTSUPP; |
| 633 | goto exit; | 779 | goto exit; |
| 634 | } | 780 | } |
| 635 | if (dest->addrtype == TIPC_ADDR_NAME) { | 781 | if (dest->addrtype == TIPC_ADDR_NAME) { |
| 636 | tsk->port.conn_type = dest->addr.name.name.type; | 782 | tsk->port.conn_type = dest->addr.name.name.type; |
| 637 | tsk->port.conn_instance = dest->addr.name.name.instance; | 783 | tsk->port.conn_instance = dest->addr.name.name.instance; |
| 638 | } | 784 | } |
| 639 | |||
| 640 | /* Abort any pending connection attempts (very unlikely) */ | ||
| 641 | reject_rx_queue(sk); | ||
| 642 | } | 785 | } |
| 786 | rc = dest_name_check(dest, m); | ||
| 787 | if (rc) | ||
| 788 | goto exit; | ||
| 643 | 789 | ||
| 644 | timeo = sock_sndtimeo(sk, m->msg_flags & MSG_DONTWAIT); | 790 | timeo = sock_sndtimeo(sk, m->msg_flags & MSG_DONTWAIT); |
| 645 | do { | 791 | |
| 646 | if (dest->addrtype == TIPC_ADDR_NAME) { | 792 | if (dest->addrtype == TIPC_ADDR_MCAST) { |
| 647 | res = dest_name_check(dest, m); | 793 | rc = tipc_sendmcast(sock, seq, iov, dsz, timeo); |
| 648 | if (res) | 794 | goto exit; |
| 649 | break; | 795 | } else if (dest->addrtype == TIPC_ADDR_NAME) { |
| 650 | res = tipc_send2name(port, | 796 | u32 type = dest->addr.name.name.type; |
| 651 | &dest->addr.name.name, | 797 | u32 inst = dest->addr.name.name.instance; |
| 652 | dest->addr.name.domain, | 798 | u32 domain = dest->addr.name.domain; |
| 653 | m->msg_iov, | 799 | |
| 654 | total_len); | 800 | dnode = domain; |
| 655 | } else if (dest->addrtype == TIPC_ADDR_ID) { | 801 | msg_set_type(mhdr, TIPC_NAMED_MSG); |
| 656 | res = tipc_send2port(port, | 802 | msg_set_hdr_sz(mhdr, NAMED_H_SIZE); |
| 657 | &dest->addr.id, | 803 | msg_set_nametype(mhdr, type); |
| 658 | m->msg_iov, | 804 | msg_set_nameinst(mhdr, inst); |
| 659 | total_len); | 805 | msg_set_lookup_scope(mhdr, tipc_addr_scope(domain)); |
| 660 | } else if (dest->addrtype == TIPC_ADDR_MCAST) { | 806 | dport = tipc_nametbl_translate(type, inst, &dnode); |
| 661 | if (needs_conn) { | 807 | msg_set_destnode(mhdr, dnode); |
| 662 | res = -EOPNOTSUPP; | 808 | msg_set_destport(mhdr, dport); |
| 663 | break; | 809 | if (unlikely(!dport && !dnode)) { |
| 664 | } | 810 | rc = -EHOSTUNREACH; |
| 665 | res = dest_name_check(dest, m); | 811 | goto exit; |
| 666 | if (res) | ||
| 667 | break; | ||
| 668 | res = tipc_port_mcast_xmit(port, | ||
| 669 | &dest->addr.nameseq, | ||
| 670 | m->msg_iov, | ||
| 671 | total_len); | ||
| 672 | } | 812 | } |
| 673 | if (likely(res != -ELINKCONG)) { | 813 | } else if (dest->addrtype == TIPC_ADDR_ID) { |
| 674 | if (needs_conn && (res >= 0)) | 814 | dnode = dest->addr.id.node; |
| 815 | msg_set_type(mhdr, TIPC_DIRECT_MSG); | ||
| 816 | msg_set_lookup_scope(mhdr, 0); | ||
| 817 | msg_set_destnode(mhdr, dnode); | ||
| 818 | msg_set_destport(mhdr, dest->addr.id.ref); | ||
| 819 | msg_set_hdr_sz(mhdr, BASIC_H_SIZE); | ||
| 820 | } | ||
| 821 | |||
| 822 | new_mtu: | ||
| 823 | mtu = tipc_node_get_mtu(dnode, tsk->port.ref); | ||
| 824 | rc = tipc_msg_build(mhdr, iov, 0, dsz, mtu, &buf); | ||
| 825 | if (rc < 0) | ||
| 826 | goto exit; | ||
| 827 | |||
| 828 | do { | ||
| 829 | rc = tipc_link_xmit(buf, dnode, tsk->port.ref); | ||
| 830 | if (likely(rc >= 0)) { | ||
| 831 | if (sock->state != SS_READY) | ||
| 675 | sock->state = SS_CONNECTING; | 832 | sock->state = SS_CONNECTING; |
| 833 | rc = dsz; | ||
| 676 | break; | 834 | break; |
| 677 | } | 835 | } |
| 678 | res = tipc_wait_for_sndmsg(sock, &timeo); | 836 | if (rc == -EMSGSIZE) |
| 679 | if (res) | 837 | goto new_mtu; |
| 838 | |||
| 839 | if (rc != -ELINKCONG) | ||
| 680 | break; | 840 | break; |
| 681 | } while (1); | ||
| 682 | 841 | ||
| 842 | rc = tipc_wait_for_sndmsg(sock, &timeo); | ||
| 843 | if (rc) | ||
| 844 | kfree_skb_list(buf); | ||
| 845 | } while (!rc); | ||
| 683 | exit: | 846 | exit: |
| 684 | if (iocb) | 847 | if (iocb) |
| 685 | release_sock(sk); | 848 | release_sock(sk); |
| 686 | return res; | 849 | |
| 850 | return rc; | ||
| 687 | } | 851 | } |
| 688 | 852 | ||
| 689 | static int tipc_wait_for_sndpkt(struct socket *sock, long *timeo_p) | 853 | static int tipc_wait_for_sndpkt(struct socket *sock, long *timeo_p) |
| 690 | { | 854 | { |
| 691 | struct sock *sk = sock->sk; | 855 | struct sock *sk = sock->sk; |
| 692 | struct tipc_sock *tsk = tipc_sk(sk); | 856 | struct tipc_sock *tsk = tipc_sk(sk); |
| 693 | struct tipc_port *port = &tsk->port; | ||
| 694 | DEFINE_WAIT(wait); | 857 | DEFINE_WAIT(wait); |
| 695 | int done; | 858 | int done; |
| 696 | 859 | ||
| @@ -709,37 +872,49 @@ static int tipc_wait_for_sndpkt(struct socket *sock, long *timeo_p) | |||
| 709 | 872 | ||
| 710 | prepare_to_wait(sk_sleep(sk), &wait, TASK_INTERRUPTIBLE); | 873 | prepare_to_wait(sk_sleep(sk), &wait, TASK_INTERRUPTIBLE); |
| 711 | done = sk_wait_event(sk, timeo_p, | 874 | done = sk_wait_event(sk, timeo_p, |
| 712 | (!port->congested || !port->connected)); | 875 | (!tsk->link_cong && |
| 876 | !tipc_sk_conn_cong(tsk)) || | ||
| 877 | !tsk->port.connected); | ||
| 713 | finish_wait(sk_sleep(sk), &wait); | 878 | finish_wait(sk_sleep(sk), &wait); |
| 714 | } while (!done); | 879 | } while (!done); |
| 715 | return 0; | 880 | return 0; |
| 716 | } | 881 | } |
| 717 | 882 | ||
| 718 | /** | 883 | /** |
| 719 | * tipc_send_packet - send a connection-oriented message | 884 | * tipc_send_stream - send stream-oriented data |
| 720 | * @iocb: if NULL, indicates that socket lock is already held | 885 | * @iocb: (unused) |
| 721 | * @sock: socket structure | 886 | * @sock: socket structure |
| 722 | * @m: message to send | 887 | * @m: data to send |
| 723 | * @total_len: length of message | 888 | * @dsz: total length of data to be transmitted |
| 724 | * | 889 | * |
| 725 | * Used for SOCK_SEQPACKET messages and SOCK_STREAM data. | 890 | * Used for SOCK_STREAM data. |
| 726 | * | 891 | * |
| 727 | * Returns the number of bytes sent on success, or errno otherwise | 892 | * Returns the number of bytes sent on success (or partial success), |
| 893 | * or errno if no data sent | ||
| 728 | */ | 894 | */ |
| 729 | static int tipc_send_packet(struct kiocb *iocb, struct socket *sock, | 895 | static int tipc_send_stream(struct kiocb *iocb, struct socket *sock, |
| 730 | struct msghdr *m, size_t total_len) | 896 | struct msghdr *m, size_t dsz) |
| 731 | { | 897 | { |
| 732 | struct sock *sk = sock->sk; | 898 | struct sock *sk = sock->sk; |
| 733 | struct tipc_sock *tsk = tipc_sk(sk); | 899 | struct tipc_sock *tsk = tipc_sk(sk); |
| 900 | struct tipc_port *port = &tsk->port; | ||
| 901 | struct tipc_msg *mhdr = &port->phdr; | ||
| 902 | struct sk_buff *buf; | ||
| 734 | DECLARE_SOCKADDR(struct sockaddr_tipc *, dest, m->msg_name); | 903 | DECLARE_SOCKADDR(struct sockaddr_tipc *, dest, m->msg_name); |
| 735 | int res = -EINVAL; | 904 | u32 ref = port->ref; |
| 905 | int rc = -EINVAL; | ||
| 736 | long timeo; | 906 | long timeo; |
| 907 | u32 dnode; | ||
| 908 | uint mtu, send, sent = 0; | ||
| 737 | 909 | ||
| 738 | /* Handle implied connection establishment */ | 910 | /* Handle implied connection establishment */ |
| 739 | if (unlikely(dest)) | 911 | if (unlikely(dest)) { |
| 740 | return tipc_sendmsg(iocb, sock, m, total_len); | 912 | rc = tipc_sendmsg(iocb, sock, m, dsz); |
| 741 | 913 | if (dsz && (dsz == rc)) | |
| 742 | if (total_len > TIPC_MAX_USER_MSG_SIZE) | 914 | tsk->sent_unacked = 1; |
| 915 | return rc; | ||
| 916 | } | ||
| 917 | if (dsz > (uint)INT_MAX) | ||
| 743 | return -EMSGSIZE; | 918 | return -EMSGSIZE; |
| 744 | 919 | ||
| 745 | if (iocb) | 920 | if (iocb) |
| @@ -747,123 +922,66 @@ static int tipc_send_packet(struct kiocb *iocb, struct socket *sock, | |||
| 747 | 922 | ||
| 748 | if (unlikely(sock->state != SS_CONNECTED)) { | 923 | if (unlikely(sock->state != SS_CONNECTED)) { |
| 749 | if (sock->state == SS_DISCONNECTING) | 924 | if (sock->state == SS_DISCONNECTING) |
| 750 | res = -EPIPE; | 925 | rc = -EPIPE; |
| 751 | else | 926 | else |
| 752 | res = -ENOTCONN; | 927 | rc = -ENOTCONN; |
| 753 | goto exit; | 928 | goto exit; |
| 754 | } | 929 | } |
| 755 | 930 | ||
| 756 | timeo = sock_sndtimeo(sk, m->msg_flags & MSG_DONTWAIT); | 931 | timeo = sock_sndtimeo(sk, m->msg_flags & MSG_DONTWAIT); |
| 932 | dnode = tipc_port_peernode(port); | ||
| 933 | |||
| 934 | next: | ||
| 935 | mtu = port->max_pkt; | ||
| 936 | send = min_t(uint, dsz - sent, TIPC_MAX_USER_MSG_SIZE); | ||
| 937 | rc = tipc_msg_build(mhdr, m->msg_iov, sent, send, mtu, &buf); | ||
| 938 | if (unlikely(rc < 0)) | ||
| 939 | goto exit; | ||
| 757 | do { | 940 | do { |
| 758 | res = tipc_send(&tsk->port, m->msg_iov, total_len); | 941 | if (likely(!tipc_sk_conn_cong(tsk))) { |
| 759 | if (likely(res != -ELINKCONG)) | 942 | rc = tipc_link_xmit(buf, dnode, ref); |
| 760 | break; | 943 | if (likely(!rc)) { |
| 761 | res = tipc_wait_for_sndpkt(sock, &timeo); | 944 | tsk->sent_unacked++; |
| 762 | if (res) | 945 | sent += send; |
| 763 | break; | 946 | if (sent == dsz) |
| 764 | } while (1); | 947 | break; |
| 948 | goto next; | ||
| 949 | } | ||
| 950 | if (rc == -EMSGSIZE) { | ||
| 951 | port->max_pkt = tipc_node_get_mtu(dnode, ref); | ||
| 952 | goto next; | ||
| 953 | } | ||
| 954 | if (rc != -ELINKCONG) | ||
| 955 | break; | ||
| 956 | } | ||
| 957 | rc = tipc_wait_for_sndpkt(sock, &timeo); | ||
| 958 | if (rc) | ||
| 959 | kfree_skb_list(buf); | ||
| 960 | } while (!rc); | ||
| 765 | exit: | 961 | exit: |
| 766 | if (iocb) | 962 | if (iocb) |
| 767 | release_sock(sk); | 963 | release_sock(sk); |
| 768 | return res; | 964 | return sent ? sent : rc; |
| 769 | } | 965 | } |
| 770 | 966 | ||
| 771 | /** | 967 | /** |
| 772 | * tipc_send_stream - send stream-oriented data | 968 | * tipc_send_packet - send a connection-oriented message |
| 773 | * @iocb: (unused) | 969 | * @iocb: if NULL, indicates that socket lock is already held |
| 774 | * @sock: socket structure | 970 | * @sock: socket structure |
| 775 | * @m: data to send | 971 | * @m: message to send |
| 776 | * @total_len: total length of data to be sent | 972 | * @dsz: length of data to be transmitted |
| 777 | * | 973 | * |
| 778 | * Used for SOCK_STREAM data. | 974 | * Used for SOCK_SEQPACKET messages. |
| 779 | * | 975 | * |
| 780 | * Returns the number of bytes sent on success (or partial success), | 976 | * Returns the number of bytes sent on success, or errno otherwise |
| 781 | * or errno if no data sent | ||
| 782 | */ | 977 | */ |
| 783 | static int tipc_send_stream(struct kiocb *iocb, struct socket *sock, | 978 | static int tipc_send_packet(struct kiocb *iocb, struct socket *sock, |
| 784 | struct msghdr *m, size_t total_len) | 979 | struct msghdr *m, size_t dsz) |
| 785 | { | 980 | { |
| 786 | struct sock *sk = sock->sk; | 981 | if (dsz > TIPC_MAX_USER_MSG_SIZE) |
| 787 | struct tipc_sock *tsk = tipc_sk(sk); | 982 | return -EMSGSIZE; |
| 788 | struct msghdr my_msg; | ||
| 789 | struct iovec my_iov; | ||
| 790 | struct iovec *curr_iov; | ||
| 791 | int curr_iovlen; | ||
| 792 | char __user *curr_start; | ||
| 793 | u32 hdr_size; | ||
| 794 | int curr_left; | ||
| 795 | int bytes_to_send; | ||
| 796 | int bytes_sent; | ||
| 797 | int res; | ||
| 798 | |||
| 799 | lock_sock(sk); | ||
| 800 | |||
| 801 | /* Handle special cases where there is no connection */ | ||
| 802 | if (unlikely(sock->state != SS_CONNECTED)) { | ||
| 803 | if (sock->state == SS_UNCONNECTED) | ||
| 804 | res = tipc_send_packet(NULL, sock, m, total_len); | ||
| 805 | else | ||
| 806 | res = sock->state == SS_DISCONNECTING ? -EPIPE : -ENOTCONN; | ||
| 807 | goto exit; | ||
| 808 | } | ||
| 809 | |||
| 810 | if (unlikely(m->msg_name)) { | ||
| 811 | res = -EISCONN; | ||
| 812 | goto exit; | ||
| 813 | } | ||
| 814 | |||
| 815 | if (total_len > (unsigned int)INT_MAX) { | ||
| 816 | res = -EMSGSIZE; | ||
| 817 | goto exit; | ||
| 818 | } | ||
| 819 | |||
| 820 | /* | ||
| 821 | * Send each iovec entry using one or more messages | ||
| 822 | * | ||
| 823 | * Note: This algorithm is good for the most likely case | ||
| 824 | * (i.e. one large iovec entry), but could be improved to pass sets | ||
| 825 | * of small iovec entries into send_packet(). | ||
| 826 | */ | ||
| 827 | curr_iov = m->msg_iov; | ||
| 828 | curr_iovlen = m->msg_iovlen; | ||
| 829 | my_msg.msg_iov = &my_iov; | ||
| 830 | my_msg.msg_iovlen = 1; | ||
| 831 | my_msg.msg_flags = m->msg_flags; | ||
| 832 | my_msg.msg_name = NULL; | ||
| 833 | bytes_sent = 0; | ||
| 834 | |||
| 835 | hdr_size = msg_hdr_sz(&tsk->port.phdr); | ||
| 836 | |||
| 837 | while (curr_iovlen--) { | ||
| 838 | curr_start = curr_iov->iov_base; | ||
| 839 | curr_left = curr_iov->iov_len; | ||
| 840 | |||
| 841 | while (curr_left) { | ||
| 842 | bytes_to_send = tsk->port.max_pkt - hdr_size; | ||
| 843 | if (bytes_to_send > TIPC_MAX_USER_MSG_SIZE) | ||
| 844 | bytes_to_send = TIPC_MAX_USER_MSG_SIZE; | ||
| 845 | if (curr_left < bytes_to_send) | ||
| 846 | bytes_to_send = curr_left; | ||
| 847 | my_iov.iov_base = curr_start; | ||
| 848 | my_iov.iov_len = bytes_to_send; | ||
| 849 | res = tipc_send_packet(NULL, sock, &my_msg, | ||
| 850 | bytes_to_send); | ||
| 851 | if (res < 0) { | ||
| 852 | if (bytes_sent) | ||
| 853 | res = bytes_sent; | ||
| 854 | goto exit; | ||
| 855 | } | ||
| 856 | curr_left -= bytes_to_send; | ||
| 857 | curr_start += bytes_to_send; | ||
| 858 | bytes_sent += bytes_to_send; | ||
| 859 | } | ||
| 860 | 983 | ||
| 861 | curr_iov++; | 984 | return tipc_send_stream(iocb, sock, m, dsz); |
| 862 | } | ||
| 863 | res = bytes_sent; | ||
| 864 | exit: | ||
| 865 | release_sock(sk); | ||
| 866 | return res; | ||
| 867 | } | 985 | } |
| 868 | 986 | ||
| 869 | /** | 987 | /** |
| @@ -1104,8 +1222,10 @@ restart: | |||
| 1104 | /* Consume received message (optional) */ | 1222 | /* Consume received message (optional) */ |
| 1105 | if (likely(!(flags & MSG_PEEK))) { | 1223 | if (likely(!(flags & MSG_PEEK))) { |
| 1106 | if ((sock->state != SS_READY) && | 1224 | if ((sock->state != SS_READY) && |
| 1107 | (++port->conn_unacked >= TIPC_CONNACK_INTV)) | 1225 | (++tsk->rcv_unacked >= TIPC_CONNACK_INTV)) { |
| 1108 | tipc_acknowledge(port->ref, port->conn_unacked); | 1226 | tipc_acknowledge(port->ref, tsk->rcv_unacked); |
| 1227 | tsk->rcv_unacked = 0; | ||
| 1228 | } | ||
| 1109 | advance_rx_queue(sk); | 1229 | advance_rx_queue(sk); |
| 1110 | } | 1230 | } |
| 1111 | exit: | 1231 | exit: |
| @@ -1213,8 +1333,10 @@ restart: | |||
| 1213 | 1333 | ||
| 1214 | /* Consume received message (optional) */ | 1334 | /* Consume received message (optional) */ |
| 1215 | if (likely(!(flags & MSG_PEEK))) { | 1335 | if (likely(!(flags & MSG_PEEK))) { |
| 1216 | if (unlikely(++port->conn_unacked >= TIPC_CONNACK_INTV)) | 1336 | if (unlikely(++tsk->rcv_unacked >= TIPC_CONNACK_INTV)) { |
| 1217 | tipc_acknowledge(port->ref, port->conn_unacked); | 1337 | tipc_acknowledge(port->ref, tsk->rcv_unacked); |
| 1338 | tsk->rcv_unacked = 0; | ||
| 1339 | } | ||
| 1218 | advance_rx_queue(sk); | 1340 | advance_rx_queue(sk); |
| 1219 | } | 1341 | } |
| 1220 | 1342 | ||
| @@ -1269,17 +1391,16 @@ static void tipc_data_ready(struct sock *sk) | |||
| 1269 | * @tsk: TIPC socket | 1391 | * @tsk: TIPC socket |
| 1270 | * @msg: message | 1392 | * @msg: message |
| 1271 | * | 1393 | * |
| 1272 | * Returns TIPC error status code and socket error status code | 1394 | * Returns 0 (TIPC_OK) if everyting ok, -TIPC_ERR_NO_PORT otherwise |
| 1273 | * once it encounters some errors | ||
| 1274 | */ | 1395 | */ |
| 1275 | static u32 filter_connect(struct tipc_sock *tsk, struct sk_buff **buf) | 1396 | static int filter_connect(struct tipc_sock *tsk, struct sk_buff **buf) |
| 1276 | { | 1397 | { |
| 1277 | struct sock *sk = &tsk->sk; | 1398 | struct sock *sk = &tsk->sk; |
| 1278 | struct tipc_port *port = &tsk->port; | 1399 | struct tipc_port *port = &tsk->port; |
| 1279 | struct socket *sock = sk->sk_socket; | 1400 | struct socket *sock = sk->sk_socket; |
| 1280 | struct tipc_msg *msg = buf_msg(*buf); | 1401 | struct tipc_msg *msg = buf_msg(*buf); |
| 1281 | 1402 | ||
| 1282 | u32 retval = TIPC_ERR_NO_PORT; | 1403 | int retval = -TIPC_ERR_NO_PORT; |
| 1283 | int res; | 1404 | int res; |
| 1284 | 1405 | ||
| 1285 | if (msg_mcast(msg)) | 1406 | if (msg_mcast(msg)) |
| @@ -1382,32 +1503,37 @@ static unsigned int rcvbuf_limit(struct sock *sk, struct sk_buff *buf) | |||
| 1382 | * | 1503 | * |
| 1383 | * Called with socket lock already taken; port lock may also be taken. | 1504 | * Called with socket lock already taken; port lock may also be taken. |
| 1384 | * | 1505 | * |
| 1385 | * Returns TIPC error status code (TIPC_OK if message is not to be rejected) | 1506 | * Returns 0 (TIPC_OK) if message was consumed, -TIPC error code if message |
| 1507 | * to be rejected, 1 (TIPC_FWD_MSG) if (CONN_MANAGER) message to be forwarded | ||
| 1386 | */ | 1508 | */ |
| 1387 | static u32 filter_rcv(struct sock *sk, struct sk_buff *buf) | 1509 | static int filter_rcv(struct sock *sk, struct sk_buff *buf) |
| 1388 | { | 1510 | { |
| 1389 | struct socket *sock = sk->sk_socket; | 1511 | struct socket *sock = sk->sk_socket; |
| 1390 | struct tipc_sock *tsk = tipc_sk(sk); | 1512 | struct tipc_sock *tsk = tipc_sk(sk); |
| 1391 | struct tipc_msg *msg = buf_msg(buf); | 1513 | struct tipc_msg *msg = buf_msg(buf); |
| 1392 | unsigned int limit = rcvbuf_limit(sk, buf); | 1514 | unsigned int limit = rcvbuf_limit(sk, buf); |
| 1393 | u32 res = TIPC_OK; | 1515 | u32 onode; |
| 1516 | int rc = TIPC_OK; | ||
| 1517 | |||
| 1518 | if (unlikely(msg_user(msg) == CONN_MANAGER)) | ||
| 1519 | return tipc_sk_proto_rcv(tsk, &onode, buf); | ||
| 1394 | 1520 | ||
| 1395 | /* Reject message if it is wrong sort of message for socket */ | 1521 | /* Reject message if it is wrong sort of message for socket */ |
| 1396 | if (msg_type(msg) > TIPC_DIRECT_MSG) | 1522 | if (msg_type(msg) > TIPC_DIRECT_MSG) |
| 1397 | return TIPC_ERR_NO_PORT; | 1523 | return -TIPC_ERR_NO_PORT; |
| 1398 | 1524 | ||
| 1399 | if (sock->state == SS_READY) { | 1525 | if (sock->state == SS_READY) { |
| 1400 | if (msg_connected(msg)) | 1526 | if (msg_connected(msg)) |
| 1401 | return TIPC_ERR_NO_PORT; | 1527 | return -TIPC_ERR_NO_PORT; |
| 1402 | } else { | 1528 | } else { |
| 1403 | res = filter_connect(tsk, &buf); | 1529 | rc = filter_connect(tsk, &buf); |
| 1404 | if (res != TIPC_OK || buf == NULL) | 1530 | if (rc != TIPC_OK || buf == NULL) |
| 1405 | return res; | 1531 | return rc; |
| 1406 | } | 1532 | } |
| 1407 | 1533 | ||
| 1408 | /* Reject message if there isn't room to queue it */ | 1534 | /* Reject message if there isn't room to queue it */ |
| 1409 | if (sk_rmem_alloc_get(sk) + buf->truesize >= limit) | 1535 | if (sk_rmem_alloc_get(sk) + buf->truesize >= limit) |
| 1410 | return TIPC_ERR_OVERLOAD; | 1536 | return -TIPC_ERR_OVERLOAD; |
| 1411 | 1537 | ||
| 1412 | /* Enqueue message */ | 1538 | /* Enqueue message */ |
| 1413 | TIPC_SKB_CB(buf)->handle = NULL; | 1539 | TIPC_SKB_CB(buf)->handle = NULL; |
| @@ -1429,16 +1555,23 @@ static u32 filter_rcv(struct sock *sk, struct sk_buff *buf) | |||
| 1429 | */ | 1555 | */ |
| 1430 | static int tipc_backlog_rcv(struct sock *sk, struct sk_buff *buf) | 1556 | static int tipc_backlog_rcv(struct sock *sk, struct sk_buff *buf) |
| 1431 | { | 1557 | { |
| 1432 | u32 res; | 1558 | int rc; |
| 1559 | u32 onode; | ||
| 1433 | struct tipc_sock *tsk = tipc_sk(sk); | 1560 | struct tipc_sock *tsk = tipc_sk(sk); |
| 1434 | uint truesize = buf->truesize; | 1561 | uint truesize = buf->truesize; |
| 1435 | 1562 | ||
| 1436 | res = filter_rcv(sk, buf); | 1563 | rc = filter_rcv(sk, buf); |
| 1437 | if (unlikely(res)) | ||
| 1438 | tipc_reject_msg(buf, res); | ||
| 1439 | 1564 | ||
| 1440 | if (atomic_read(&tsk->dupl_rcvcnt) < TIPC_CONN_OVERLOAD_LIMIT) | 1565 | if (likely(!rc)) { |
| 1441 | atomic_add(truesize, &tsk->dupl_rcvcnt); | 1566 | if (atomic_read(&tsk->dupl_rcvcnt) < TIPC_CONN_OVERLOAD_LIMIT) |
| 1567 | atomic_add(truesize, &tsk->dupl_rcvcnt); | ||
| 1568 | return 0; | ||
| 1569 | } | ||
| 1570 | |||
| 1571 | if ((rc < 0) && !tipc_msg_reverse(buf, &onode, -rc)) | ||
| 1572 | return 0; | ||
| 1573 | |||
| 1574 | tipc_link_xmit(buf, onode, 0); | ||
| 1442 | 1575 | ||
| 1443 | return 0; | 1576 | return 0; |
| 1444 | } | 1577 | } |
| @@ -1455,19 +1588,14 @@ int tipc_sk_rcv(struct sk_buff *buf) | |||
| 1455 | struct tipc_port *port; | 1588 | struct tipc_port *port; |
| 1456 | struct sock *sk; | 1589 | struct sock *sk; |
| 1457 | u32 dport = msg_destport(buf_msg(buf)); | 1590 | u32 dport = msg_destport(buf_msg(buf)); |
| 1458 | int err = TIPC_OK; | 1591 | int rc = TIPC_OK; |
| 1459 | uint limit; | 1592 | uint limit; |
| 1593 | u32 dnode; | ||
| 1460 | 1594 | ||
| 1461 | /* Forward unresolved named message */ | 1595 | /* Validate destination and message */ |
| 1462 | if (unlikely(!dport)) { | ||
| 1463 | tipc_net_route_msg(buf); | ||
| 1464 | return 0; | ||
| 1465 | } | ||
| 1466 | |||
| 1467 | /* Validate destination */ | ||
| 1468 | port = tipc_port_lock(dport); | 1596 | port = tipc_port_lock(dport); |
| 1469 | if (unlikely(!port)) { | 1597 | if (unlikely(!port)) { |
| 1470 | err = TIPC_ERR_NO_PORT; | 1598 | rc = tipc_msg_eval(buf, &dnode); |
| 1471 | goto exit; | 1599 | goto exit; |
| 1472 | } | 1600 | } |
| 1473 | 1601 | ||
| @@ -1478,23 +1606,25 @@ int tipc_sk_rcv(struct sk_buff *buf) | |||
| 1478 | bh_lock_sock(sk); | 1606 | bh_lock_sock(sk); |
| 1479 | 1607 | ||
| 1480 | if (!sock_owned_by_user(sk)) { | 1608 | if (!sock_owned_by_user(sk)) { |
| 1481 | err = filter_rcv(sk, buf); | 1609 | rc = filter_rcv(sk, buf); |
| 1482 | } else { | 1610 | } else { |
| 1483 | if (sk->sk_backlog.len == 0) | 1611 | if (sk->sk_backlog.len == 0) |
| 1484 | atomic_set(&tsk->dupl_rcvcnt, 0); | 1612 | atomic_set(&tsk->dupl_rcvcnt, 0); |
| 1485 | limit = rcvbuf_limit(sk, buf) + atomic_read(&tsk->dupl_rcvcnt); | 1613 | limit = rcvbuf_limit(sk, buf) + atomic_read(&tsk->dupl_rcvcnt); |
| 1486 | if (sk_add_backlog(sk, buf, limit)) | 1614 | if (sk_add_backlog(sk, buf, limit)) |
| 1487 | err = TIPC_ERR_OVERLOAD; | 1615 | rc = -TIPC_ERR_OVERLOAD; |
| 1488 | } | 1616 | } |
| 1489 | |||
| 1490 | bh_unlock_sock(sk); | 1617 | bh_unlock_sock(sk); |
| 1491 | tipc_port_unlock(port); | 1618 | tipc_port_unlock(port); |
| 1492 | 1619 | ||
| 1493 | if (likely(!err)) | 1620 | if (likely(!rc)) |
| 1494 | return 0; | 1621 | return 0; |
| 1495 | exit: | 1622 | exit: |
| 1496 | tipc_reject_msg(buf, err); | 1623 | if ((rc < 0) && !tipc_msg_reverse(buf, &dnode, -rc)) |
| 1497 | return -EHOSTUNREACH; | 1624 | return -EHOSTUNREACH; |
| 1625 | |||
| 1626 | tipc_link_xmit(buf, dnode, 0); | ||
| 1627 | return (rc < 0) ? -EHOSTUNREACH : 0; | ||
| 1498 | } | 1628 | } |
| 1499 | 1629 | ||
| 1500 | static int tipc_wait_for_connect(struct socket *sock, long *timeo_p) | 1630 | static int tipc_wait_for_connect(struct socket *sock, long *timeo_p) |
| @@ -1758,6 +1888,7 @@ static int tipc_shutdown(struct socket *sock, int how) | |||
| 1758 | struct tipc_sock *tsk = tipc_sk(sk); | 1888 | struct tipc_sock *tsk = tipc_sk(sk); |
| 1759 | struct tipc_port *port = &tsk->port; | 1889 | struct tipc_port *port = &tsk->port; |
| 1760 | struct sk_buff *buf; | 1890 | struct sk_buff *buf; |
| 1891 | u32 peer; | ||
| 1761 | int res; | 1892 | int res; |
| 1762 | 1893 | ||
| 1763 | if (how != SHUT_RDWR) | 1894 | if (how != SHUT_RDWR) |
| @@ -1778,7 +1909,8 @@ restart: | |||
| 1778 | goto restart; | 1909 | goto restart; |
| 1779 | } | 1910 | } |
| 1780 | tipc_port_disconnect(port->ref); | 1911 | tipc_port_disconnect(port->ref); |
| 1781 | tipc_reject_msg(buf, TIPC_CONN_SHUTDOWN); | 1912 | if (tipc_msg_reverse(buf, &peer, TIPC_CONN_SHUTDOWN)) |
| 1913 | tipc_link_xmit(buf, peer, 0); | ||
| 1782 | } else { | 1914 | } else { |
| 1783 | tipc_port_shutdown(port->ref); | 1915 | tipc_port_shutdown(port->ref); |
| 1784 | } | 1916 | } |
| @@ -1936,7 +2068,7 @@ static int tipc_getsockopt(struct socket *sock, int lvl, int opt, | |||
| 1936 | return put_user(sizeof(value), ol); | 2068 | return put_user(sizeof(value), ol); |
| 1937 | } | 2069 | } |
| 1938 | 2070 | ||
| 1939 | int tipc_ioctl(struct socket *sk, unsigned int cmd, unsigned long arg) | 2071 | static int tipc_ioctl(struct socket *sk, unsigned int cmd, unsigned long arg) |
| 1940 | { | 2072 | { |
| 1941 | struct tipc_sioc_ln_req lnr; | 2073 | struct tipc_sioc_ln_req lnr; |
| 1942 | void __user *argp = (void __user *)arg; | 2074 | void __user *argp = (void __user *)arg; |
| @@ -1952,7 +2084,6 @@ int tipc_ioctl(struct socket *sk, unsigned int cmd, unsigned long arg) | |||
| 1952 | return 0; | 2084 | return 0; |
| 1953 | } | 2085 | } |
| 1954 | return -EADDRNOTAVAIL; | 2086 | return -EADDRNOTAVAIL; |
| 1955 | break; | ||
| 1956 | default: | 2087 | default: |
| 1957 | return -ENOIOCTLCMD; | 2088 | return -ENOIOCTLCMD; |
| 1958 | } | 2089 | } |
diff --git a/net/tipc/socket.h b/net/tipc/socket.h index 3afcd2a70b31..43b75b3ceced 100644 --- a/net/tipc/socket.h +++ b/net/tipc/socket.h | |||
| @@ -38,6 +38,9 @@ | |||
| 38 | #include "port.h" | 38 | #include "port.h" |
| 39 | #include <net/sock.h> | 39 | #include <net/sock.h> |
| 40 | 40 | ||
| 41 | #define TIPC_CONN_OK 0 | ||
| 42 | #define TIPC_CONN_PROBING 1 | ||
| 43 | |||
| 41 | /** | 44 | /** |
| 42 | * struct tipc_sock - TIPC socket structure | 45 | * struct tipc_sock - TIPC socket structure |
| 43 | * @sk: socket - interacts with 'port' and with user via the socket API | 46 | * @sk: socket - interacts with 'port' and with user via the socket API |
| @@ -45,6 +48,9 @@ | |||
| 45 | * @peer_name: the peer of the connection, if any | 48 | * @peer_name: the peer of the connection, if any |
| 46 | * @conn_timeout: the time we can wait for an unresponded setup request | 49 | * @conn_timeout: the time we can wait for an unresponded setup request |
| 47 | * @dupl_rcvcnt: number of bytes counted twice, in both backlog and rcv queue | 50 | * @dupl_rcvcnt: number of bytes counted twice, in both backlog and rcv queue |
| 51 | * @link_cong: non-zero if owner must sleep because of link congestion | ||
| 52 | * @sent_unacked: # messages sent by socket, and not yet acked by peer | ||
| 53 | * @rcv_unacked: # messages read by user, but not yet acked back to peer | ||
| 48 | */ | 54 | */ |
| 49 | 55 | ||
| 50 | struct tipc_sock { | 56 | struct tipc_sock { |
| @@ -52,6 +58,9 @@ struct tipc_sock { | |||
| 52 | struct tipc_port port; | 58 | struct tipc_port port; |
| 53 | unsigned int conn_timeout; | 59 | unsigned int conn_timeout; |
| 54 | atomic_t dupl_rcvcnt; | 60 | atomic_t dupl_rcvcnt; |
| 61 | int link_cong; | ||
| 62 | uint sent_unacked; | ||
| 63 | uint rcv_unacked; | ||
| 55 | }; | 64 | }; |
| 56 | 65 | ||
| 57 | static inline struct tipc_sock *tipc_sk(const struct sock *sk) | 66 | static inline struct tipc_sock *tipc_sk(const struct sock *sk) |
| @@ -69,6 +78,13 @@ static inline void tipc_sock_wakeup(struct tipc_sock *tsk) | |||
| 69 | tsk->sk.sk_write_space(&tsk->sk); | 78 | tsk->sk.sk_write_space(&tsk->sk); |
| 70 | } | 79 | } |
| 71 | 80 | ||
| 81 | static inline int tipc_sk_conn_cong(struct tipc_sock *tsk) | ||
| 82 | { | ||
| 83 | return tsk->sent_unacked >= TIPC_FLOWCTRL_WIN; | ||
| 84 | } | ||
| 85 | |||
| 72 | int tipc_sk_rcv(struct sk_buff *buf); | 86 | int tipc_sk_rcv(struct sk_buff *buf); |
| 73 | 87 | ||
| 88 | void tipc_sk_mcast_rcv(struct sk_buff *buf); | ||
| 89 | |||
| 74 | #endif | 90 | #endif |
diff --git a/net/wireless/Kconfig b/net/wireless/Kconfig index 405f3c4cf70c..29c8675f9a11 100644 --- a/net/wireless/Kconfig +++ b/net/wireless/Kconfig | |||
| @@ -162,6 +162,12 @@ config CFG80211_INTERNAL_REGDB | |||
| 162 | and includes code to query that database. This is an alternative | 162 | and includes code to query that database. This is an alternative |
| 163 | to using CRDA for defining regulatory rules for the kernel. | 163 | to using CRDA for defining regulatory rules for the kernel. |
| 164 | 164 | ||
| 165 | Using this option requires some parsing of the db.txt at build time, | ||
| 166 | the parser will be upkept with the latest wireless-regdb updates but | ||
| 167 | older wireless-regdb formats will be ignored. The parser may later | ||
| 168 | be replaced to avoid issues with conflicts on versions of | ||
| 169 | wireless-regdb. | ||
| 170 | |||
| 165 | For details see: | 171 | For details see: |
| 166 | 172 | ||
| 167 | http://wireless.kernel.org/en/developers/Regulatory | 173 | http://wireless.kernel.org/en/developers/Regulatory |
diff --git a/net/wireless/core.c b/net/wireless/core.c index a1c40654dd9b..afee5e0455ea 100644 --- a/net/wireless/core.c +++ b/net/wireless/core.c | |||
| @@ -25,7 +25,6 @@ | |||
| 25 | #include "sysfs.h" | 25 | #include "sysfs.h" |
| 26 | #include "debugfs.h" | 26 | #include "debugfs.h" |
| 27 | #include "wext-compat.h" | 27 | #include "wext-compat.h" |
| 28 | #include "ethtool.h" | ||
| 29 | #include "rdev-ops.h" | 28 | #include "rdev-ops.h" |
| 30 | 29 | ||
| 31 | /* name for sysfs, %d is appended */ | 30 | /* name for sysfs, %d is appended */ |
| @@ -927,8 +926,6 @@ static int cfg80211_netdev_notifier_call(struct notifier_block *nb, | |||
| 927 | /* allow mac80211 to determine the timeout */ | 926 | /* allow mac80211 to determine the timeout */ |
| 928 | wdev->ps_timeout = -1; | 927 | wdev->ps_timeout = -1; |
| 929 | 928 | ||
| 930 | netdev_set_default_ethtool_ops(dev, &cfg80211_ethtool_ops); | ||
| 931 | |||
| 932 | if ((wdev->iftype == NL80211_IFTYPE_STATION || | 929 | if ((wdev->iftype == NL80211_IFTYPE_STATION || |
| 933 | wdev->iftype == NL80211_IFTYPE_P2P_CLIENT || | 930 | wdev->iftype == NL80211_IFTYPE_P2P_CLIENT || |
| 934 | wdev->iftype == NL80211_IFTYPE_ADHOC) && !wdev->use_4addr) | 931 | wdev->iftype == NL80211_IFTYPE_ADHOC) && !wdev->use_4addr) |
diff --git a/net/wireless/ethtool.c b/net/wireless/ethtool.c index d4860bfc020e..e9e91298c70d 100644 --- a/net/wireless/ethtool.c +++ b/net/wireless/ethtool.c | |||
| @@ -1,11 +1,9 @@ | |||
| 1 | #include <linux/utsname.h> | 1 | #include <linux/utsname.h> |
| 2 | #include <net/cfg80211.h> | 2 | #include <net/cfg80211.h> |
| 3 | #include "core.h" | 3 | #include "core.h" |
| 4 | #include "ethtool.h" | ||
| 5 | #include "rdev-ops.h" | 4 | #include "rdev-ops.h" |
| 6 | 5 | ||
| 7 | static void cfg80211_get_drvinfo(struct net_device *dev, | 6 | void cfg80211_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info) |
| 8 | struct ethtool_drvinfo *info) | ||
| 9 | { | 7 | { |
| 10 | struct wireless_dev *wdev = dev->ieee80211_ptr; | 8 | struct wireless_dev *wdev = dev->ieee80211_ptr; |
| 11 | 9 | ||
| @@ -23,84 +21,4 @@ static void cfg80211_get_drvinfo(struct net_device *dev, | |||
| 23 | strlcpy(info->bus_info, dev_name(wiphy_dev(wdev->wiphy)), | 21 | strlcpy(info->bus_info, dev_name(wiphy_dev(wdev->wiphy)), |
| 24 | sizeof(info->bus_info)); | 22 | sizeof(info->bus_info)); |
| 25 | } | 23 | } |
| 26 | 24 | EXPORT_SYMBOL(cfg80211_get_drvinfo); | |
| 27 | static int cfg80211_get_regs_len(struct net_device *dev) | ||
| 28 | { | ||
| 29 | /* For now, return 0... */ | ||
| 30 | return 0; | ||
| 31 | } | ||
| 32 | |||
| 33 | static void cfg80211_get_regs(struct net_device *dev, struct ethtool_regs *regs, | ||
| 34 | void *data) | ||
| 35 | { | ||
| 36 | struct wireless_dev *wdev = dev->ieee80211_ptr; | ||
| 37 | |||
| 38 | regs->version = wdev->wiphy->hw_version; | ||
| 39 | regs->len = 0; | ||
| 40 | } | ||
| 41 | |||
| 42 | static void cfg80211_get_ringparam(struct net_device *dev, | ||
| 43 | struct ethtool_ringparam *rp) | ||
| 44 | { | ||
| 45 | struct wireless_dev *wdev = dev->ieee80211_ptr; | ||
| 46 | struct cfg80211_registered_device *rdev = wiphy_to_rdev(wdev->wiphy); | ||
| 47 | |||
| 48 | memset(rp, 0, sizeof(*rp)); | ||
| 49 | |||
| 50 | if (rdev->ops->get_ringparam) | ||
| 51 | rdev_get_ringparam(rdev, &rp->tx_pending, &rp->tx_max_pending, | ||
| 52 | &rp->rx_pending, &rp->rx_max_pending); | ||
| 53 | } | ||
| 54 | |||
| 55 | static int cfg80211_set_ringparam(struct net_device *dev, | ||
| 56 | struct ethtool_ringparam *rp) | ||
| 57 | { | ||
| 58 | struct wireless_dev *wdev = dev->ieee80211_ptr; | ||
| 59 | struct cfg80211_registered_device *rdev = wiphy_to_rdev(wdev->wiphy); | ||
| 60 | |||
| 61 | if (rp->rx_mini_pending != 0 || rp->rx_jumbo_pending != 0) | ||
| 62 | return -EINVAL; | ||
| 63 | |||
| 64 | if (rdev->ops->set_ringparam) | ||
| 65 | return rdev_set_ringparam(rdev, rp->tx_pending, rp->rx_pending); | ||
| 66 | |||
| 67 | return -ENOTSUPP; | ||
| 68 | } | ||
| 69 | |||
| 70 | static int cfg80211_get_sset_count(struct net_device *dev, int sset) | ||
| 71 | { | ||
| 72 | struct wireless_dev *wdev = dev->ieee80211_ptr; | ||
| 73 | struct cfg80211_registered_device *rdev = wiphy_to_rdev(wdev->wiphy); | ||
| 74 | if (rdev->ops->get_et_sset_count) | ||
| 75 | return rdev_get_et_sset_count(rdev, dev, sset); | ||
| 76 | return -EOPNOTSUPP; | ||
| 77 | } | ||
| 78 | |||
| 79 | static void cfg80211_get_stats(struct net_device *dev, | ||
| 80 | struct ethtool_stats *stats, u64 *data) | ||
| 81 | { | ||
| 82 | struct wireless_dev *wdev = dev->ieee80211_ptr; | ||
| 83 | struct cfg80211_registered_device *rdev = wiphy_to_rdev(wdev->wiphy); | ||
| 84 | if (rdev->ops->get_et_stats) | ||
| 85 | rdev_get_et_stats(rdev, dev, stats, data); | ||
| 86 | } | ||
| 87 | |||
| 88 | static void cfg80211_get_strings(struct net_device *dev, u32 sset, u8 *data) | ||
| 89 | { | ||
| 90 | struct wireless_dev *wdev = dev->ieee80211_ptr; | ||
| 91 | struct cfg80211_registered_device *rdev = wiphy_to_rdev(wdev->wiphy); | ||
| 92 | if (rdev->ops->get_et_strings) | ||
| 93 | rdev_get_et_strings(rdev, dev, sset, data); | ||
| 94 | } | ||
| 95 | |||
| 96 | const struct ethtool_ops cfg80211_ethtool_ops = { | ||
| 97 | .get_drvinfo = cfg80211_get_drvinfo, | ||
| 98 | .get_regs_len = cfg80211_get_regs_len, | ||
| 99 | .get_regs = cfg80211_get_regs, | ||
| 100 | .get_link = ethtool_op_get_link, | ||
| 101 | .get_ringparam = cfg80211_get_ringparam, | ||
| 102 | .set_ringparam = cfg80211_set_ringparam, | ||
| 103 | .get_strings = cfg80211_get_strings, | ||
| 104 | .get_ethtool_stats = cfg80211_get_stats, | ||
| 105 | .get_sset_count = cfg80211_get_sset_count, | ||
| 106 | }; | ||
diff --git a/net/wireless/ethtool.h b/net/wireless/ethtool.h deleted file mode 100644 index 695ecad20bd6..000000000000 --- a/net/wireless/ethtool.h +++ /dev/null | |||
| @@ -1,6 +0,0 @@ | |||
| 1 | #ifndef __CFG80211_ETHTOOL__ | ||
| 2 | #define __CFG80211_ETHTOOL__ | ||
| 3 | |||
| 4 | extern const struct ethtool_ops cfg80211_ethtool_ops; | ||
| 5 | |||
| 6 | #endif /* __CFG80211_ETHTOOL__ */ | ||
diff --git a/net/wireless/genregdb.awk b/net/wireless/genregdb.awk index 40c37fc5b67c..baf2426b555a 100644 --- a/net/wireless/genregdb.awk +++ b/net/wireless/genregdb.awk | |||
| @@ -51,32 +51,41 @@ function parse_country_head() { | |||
| 51 | 51 | ||
| 52 | function parse_reg_rule() | 52 | function parse_reg_rule() |
| 53 | { | 53 | { |
| 54 | flag_starts_at = 7 | ||
| 55 | |||
| 54 | start = $1 | 56 | start = $1 |
| 55 | sub(/\(/, "", start) | 57 | sub(/\(/, "", start) |
| 56 | end = $3 | 58 | end = $3 |
| 57 | bw = $5 | 59 | bw = $5 |
| 58 | sub(/\),/, "", bw) | 60 | sub(/\),/, "", bw) |
| 59 | gain = $6 | 61 | gain = 0 |
| 60 | sub(/\(/, "", gain) | 62 | power = $6 |
| 61 | sub(/,/, "", gain) | ||
| 62 | power = $7 | ||
| 63 | sub(/\)/, "", power) | ||
| 64 | sub(/,/, "", power) | ||
| 65 | # power might be in mW... | 63 | # power might be in mW... |
| 66 | units = $8 | 64 | units = $7 |
| 65 | dfs_cac = 0 | ||
| 66 | |||
| 67 | sub(/\(/, "", power) | ||
| 68 | sub(/\),/, "", power) | ||
| 69 | sub(/\),/, "", units) | ||
| 67 | sub(/\)/, "", units) | 70 | sub(/\)/, "", units) |
| 68 | sub(/,/, "", units) | 71 | |
| 69 | dfs_cac = $9 | ||
| 70 | if (units == "mW") { | 72 | if (units == "mW") { |
| 73 | flag_starts_at = 8 | ||
| 71 | power = 10 * log(power)/log(10) | 74 | power = 10 * log(power)/log(10) |
| 75 | if ($8 ~ /[[:digit:]]/) { | ||
| 76 | flag_starts_at = 9 | ||
| 77 | dfs_cac = $8 | ||
| 78 | } | ||
| 72 | } else { | 79 | } else { |
| 73 | dfs_cac = $8 | 80 | if ($7 ~ /[[:digit:]]/) { |
| 81 | flag_starts_at = 8 | ||
| 82 | dfs_cac = $7 | ||
| 83 | } | ||
| 74 | } | 84 | } |
| 75 | sub(/,/, "", dfs_cac) | ||
| 76 | sub(/\(/, "", dfs_cac) | 85 | sub(/\(/, "", dfs_cac) |
| 77 | sub(/\)/, "", dfs_cac) | 86 | sub(/\),/, "", dfs_cac) |
| 78 | flagstr = "" | 87 | flagstr = "" |
| 79 | for (i=8; i<=NF; i++) | 88 | for (i=flag_starts_at; i<=NF; i++) |
| 80 | flagstr = flagstr $i | 89 | flagstr = flagstr $i |
| 81 | split(flagstr, flagarray, ",") | 90 | split(flagstr, flagarray, ",") |
| 82 | flags = "" | 91 | flags = "" |
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index 6668daf69326..df7b1332a1ec 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c | |||
| @@ -337,6 +337,7 @@ static const struct nla_policy nl80211_policy[NL80211_ATTR_MAX+1] = { | |||
| 337 | [NL80211_ATTR_TDLS_OPERATION] = { .type = NLA_U8 }, | 337 | [NL80211_ATTR_TDLS_OPERATION] = { .type = NLA_U8 }, |
| 338 | [NL80211_ATTR_TDLS_SUPPORT] = { .type = NLA_FLAG }, | 338 | [NL80211_ATTR_TDLS_SUPPORT] = { .type = NLA_FLAG }, |
| 339 | [NL80211_ATTR_TDLS_EXTERNAL_SETUP] = { .type = NLA_FLAG }, | 339 | [NL80211_ATTR_TDLS_EXTERNAL_SETUP] = { .type = NLA_FLAG }, |
| 340 | [NL80211_ATTR_TDLS_INITIATOR] = { .type = NLA_FLAG }, | ||
| 340 | [NL80211_ATTR_DONT_WAIT_FOR_ACK] = { .type = NLA_FLAG }, | 341 | [NL80211_ATTR_DONT_WAIT_FOR_ACK] = { .type = NLA_FLAG }, |
| 341 | [NL80211_ATTR_PROBE_RESP] = { .type = NLA_BINARY, | 342 | [NL80211_ATTR_PROBE_RESP] = { .type = NLA_BINARY, |
| 342 | .len = IEEE80211_MAX_DATA_LEN }, | 343 | .len = IEEE80211_MAX_DATA_LEN }, |
| @@ -3813,7 +3814,8 @@ int cfg80211_check_station_change(struct wiphy *wiphy, | |||
| 3813 | { | 3814 | { |
| 3814 | if (params->listen_interval != -1) | 3815 | if (params->listen_interval != -1) |
| 3815 | return -EINVAL; | 3816 | return -EINVAL; |
| 3816 | if (params->aid) | 3817 | if (params->aid && |
| 3818 | !(params->sta_flags_set & BIT(NL80211_STA_FLAG_TDLS_PEER))) | ||
| 3817 | return -EINVAL; | 3819 | return -EINVAL; |
| 3818 | 3820 | ||
| 3819 | /* When you run into this, adjust the code below for the new flag */ | 3821 | /* When you run into this, adjust the code below for the new flag */ |
| @@ -6011,17 +6013,6 @@ skip_beacons: | |||
| 6011 | params.radar_required = true; | 6013 | params.radar_required = true; |
| 6012 | } | 6014 | } |
| 6013 | 6015 | ||
| 6014 | /* TODO: I left this here for now. With channel switch, the | ||
| 6015 | * verification is a bit more complicated, because we only do | ||
| 6016 | * it later when the channel switch really happens. | ||
| 6017 | */ | ||
| 6018 | err = cfg80211_can_use_iftype_chan(rdev, wdev, wdev->iftype, | ||
| 6019 | params.chandef.chan, | ||
| 6020 | CHAN_MODE_SHARED, | ||
| 6021 | radar_detect_width); | ||
| 6022 | if (err) | ||
| 6023 | return err; | ||
| 6024 | |||
| 6025 | if (info->attrs[NL80211_ATTR_CH_SWITCH_BLOCK_TX]) | 6016 | if (info->attrs[NL80211_ATTR_CH_SWITCH_BLOCK_TX]) |
| 6026 | params.block_tx = true; | 6017 | params.block_tx = true; |
| 6027 | 6018 | ||
| @@ -7364,6 +7355,7 @@ static int nl80211_tdls_mgmt(struct sk_buff *skb, struct genl_info *info) | |||
| 7364 | u32 peer_capability = 0; | 7355 | u32 peer_capability = 0; |
| 7365 | u16 status_code; | 7356 | u16 status_code; |
| 7366 | u8 *peer; | 7357 | u8 *peer; |
| 7358 | bool initiator; | ||
| 7367 | 7359 | ||
| 7368 | if (!(rdev->wiphy.flags & WIPHY_FLAG_SUPPORTS_TDLS) || | 7360 | if (!(rdev->wiphy.flags & WIPHY_FLAG_SUPPORTS_TDLS) || |
| 7369 | !rdev->ops->tdls_mgmt) | 7361 | !rdev->ops->tdls_mgmt) |
| @@ -7380,12 +7372,14 @@ static int nl80211_tdls_mgmt(struct sk_buff *skb, struct genl_info *info) | |||
| 7380 | action_code = nla_get_u8(info->attrs[NL80211_ATTR_TDLS_ACTION]); | 7372 | action_code = nla_get_u8(info->attrs[NL80211_ATTR_TDLS_ACTION]); |
| 7381 | status_code = nla_get_u16(info->attrs[NL80211_ATTR_STATUS_CODE]); | 7373 | status_code = nla_get_u16(info->attrs[NL80211_ATTR_STATUS_CODE]); |
| 7382 | dialog_token = nla_get_u8(info->attrs[NL80211_ATTR_TDLS_DIALOG_TOKEN]); | 7374 | dialog_token = nla_get_u8(info->attrs[NL80211_ATTR_TDLS_DIALOG_TOKEN]); |
| 7375 | initiator = nla_get_flag(info->attrs[NL80211_ATTR_TDLS_INITIATOR]); | ||
| 7383 | if (info->attrs[NL80211_ATTR_TDLS_PEER_CAPABILITY]) | 7376 | if (info->attrs[NL80211_ATTR_TDLS_PEER_CAPABILITY]) |
| 7384 | peer_capability = | 7377 | peer_capability = |
| 7385 | nla_get_u32(info->attrs[NL80211_ATTR_TDLS_PEER_CAPABILITY]); | 7378 | nla_get_u32(info->attrs[NL80211_ATTR_TDLS_PEER_CAPABILITY]); |
| 7386 | 7379 | ||
| 7387 | return rdev_tdls_mgmt(rdev, dev, peer, action_code, | 7380 | return rdev_tdls_mgmt(rdev, dev, peer, action_code, |
| 7388 | dialog_token, status_code, peer_capability, | 7381 | dialog_token, status_code, peer_capability, |
| 7382 | initiator, | ||
| 7389 | nla_data(info->attrs[NL80211_ATTR_IE]), | 7383 | nla_data(info->attrs[NL80211_ATTR_IE]), |
| 7390 | nla_len(info->attrs[NL80211_ATTR_IE])); | 7384 | nla_len(info->attrs[NL80211_ATTR_IE])); |
| 7391 | } | 7385 | } |
diff --git a/net/wireless/rdev-ops.h b/net/wireless/rdev-ops.h index d95bbe348138..56c2240c30ce 100644 --- a/net/wireless/rdev-ops.h +++ b/net/wireless/rdev-ops.h | |||
| @@ -714,25 +714,6 @@ static inline int rdev_get_antenna(struct cfg80211_registered_device *rdev, | |||
| 714 | return ret; | 714 | return ret; |
| 715 | } | 715 | } |
| 716 | 716 | ||
| 717 | static inline int rdev_set_ringparam(struct cfg80211_registered_device *rdev, | ||
| 718 | u32 tx, u32 rx) | ||
| 719 | { | ||
| 720 | int ret; | ||
| 721 | trace_rdev_set_ringparam(&rdev->wiphy, tx, rx); | ||
| 722 | ret = rdev->ops->set_ringparam(&rdev->wiphy, tx, rx); | ||
| 723 | trace_rdev_return_int(&rdev->wiphy, ret); | ||
| 724 | return ret; | ||
| 725 | } | ||
| 726 | |||
| 727 | static inline void rdev_get_ringparam(struct cfg80211_registered_device *rdev, | ||
| 728 | u32 *tx, u32 *tx_max, u32 *rx, | ||
| 729 | u32 *rx_max) | ||
| 730 | { | ||
| 731 | trace_rdev_get_ringparam(&rdev->wiphy); | ||
| 732 | rdev->ops->get_ringparam(&rdev->wiphy, tx, tx_max, rx, rx_max); | ||
| 733 | trace_rdev_return_void_tx_rx(&rdev->wiphy, *tx, *tx_max, *rx, *rx_max); | ||
| 734 | } | ||
| 735 | |||
| 736 | static inline int | 717 | static inline int |
| 737 | rdev_sched_scan_start(struct cfg80211_registered_device *rdev, | 718 | rdev_sched_scan_start(struct cfg80211_registered_device *rdev, |
| 738 | struct net_device *dev, | 719 | struct net_device *dev, |
| @@ -770,15 +751,15 @@ static inline int rdev_tdls_mgmt(struct cfg80211_registered_device *rdev, | |||
| 770 | struct net_device *dev, u8 *peer, | 751 | struct net_device *dev, u8 *peer, |
| 771 | u8 action_code, u8 dialog_token, | 752 | u8 action_code, u8 dialog_token, |
| 772 | u16 status_code, u32 peer_capability, | 753 | u16 status_code, u32 peer_capability, |
| 773 | const u8 *buf, size_t len) | 754 | bool initiator, const u8 *buf, size_t len) |
| 774 | { | 755 | { |
| 775 | int ret; | 756 | int ret; |
| 776 | trace_rdev_tdls_mgmt(&rdev->wiphy, dev, peer, action_code, | 757 | trace_rdev_tdls_mgmt(&rdev->wiphy, dev, peer, action_code, |
| 777 | dialog_token, status_code, peer_capability, | 758 | dialog_token, status_code, peer_capability, |
| 778 | buf, len); | 759 | initiator, buf, len); |
| 779 | ret = rdev->ops->tdls_mgmt(&rdev->wiphy, dev, peer, action_code, | 760 | ret = rdev->ops->tdls_mgmt(&rdev->wiphy, dev, peer, action_code, |
| 780 | dialog_token, status_code, peer_capability, | 761 | dialog_token, status_code, peer_capability, |
| 781 | buf, len); | 762 | initiator, buf, len); |
| 782 | trace_rdev_return_int(&rdev->wiphy, ret); | 763 | trace_rdev_return_int(&rdev->wiphy, ret); |
| 783 | return ret; | 764 | return ret; |
| 784 | } | 765 | } |
| @@ -816,35 +797,6 @@ static inline int rdev_set_noack_map(struct cfg80211_registered_device *rdev, | |||
| 816 | } | 797 | } |
| 817 | 798 | ||
| 818 | static inline int | 799 | static inline int |
| 819 | rdev_get_et_sset_count(struct cfg80211_registered_device *rdev, | ||
| 820 | struct net_device *dev, int sset) | ||
| 821 | { | ||
| 822 | int ret; | ||
| 823 | trace_rdev_get_et_sset_count(&rdev->wiphy, dev, sset); | ||
| 824 | ret = rdev->ops->get_et_sset_count(&rdev->wiphy, dev, sset); | ||
| 825 | trace_rdev_return_int(&rdev->wiphy, ret); | ||
| 826 | return ret; | ||
| 827 | } | ||
| 828 | |||
| 829 | static inline void rdev_get_et_stats(struct cfg80211_registered_device *rdev, | ||
| 830 | struct net_device *dev, | ||
| 831 | struct ethtool_stats *stats, u64 *data) | ||
| 832 | { | ||
| 833 | trace_rdev_get_et_stats(&rdev->wiphy, dev); | ||
| 834 | rdev->ops->get_et_stats(&rdev->wiphy, dev, stats, data); | ||
| 835 | trace_rdev_return_void(&rdev->wiphy); | ||
| 836 | } | ||
| 837 | |||
| 838 | static inline void rdev_get_et_strings(struct cfg80211_registered_device *rdev, | ||
| 839 | struct net_device *dev, u32 sset, | ||
| 840 | u8 *data) | ||
| 841 | { | ||
| 842 | trace_rdev_get_et_strings(&rdev->wiphy, dev, sset); | ||
| 843 | rdev->ops->get_et_strings(&rdev->wiphy, dev, sset, data); | ||
| 844 | trace_rdev_return_void(&rdev->wiphy); | ||
| 845 | } | ||
| 846 | |||
| 847 | static inline int | ||
| 848 | rdev_get_channel(struct cfg80211_registered_device *rdev, | 800 | rdev_get_channel(struct cfg80211_registered_device *rdev, |
| 849 | struct wireless_dev *wdev, | 801 | struct wireless_dev *wdev, |
| 850 | struct cfg80211_chan_def *chandef) | 802 | struct cfg80211_chan_def *chandef) |
diff --git a/net/wireless/trace.h b/net/wireless/trace.h index 7cc887f9da11..0c524cd76c83 100644 --- a/net/wireless/trace.h +++ b/net/wireless/trace.h | |||
| @@ -298,11 +298,6 @@ DEFINE_EVENT(wiphy_only_evt, rdev_return_void, | |||
| 298 | TP_ARGS(wiphy) | 298 | TP_ARGS(wiphy) |
| 299 | ); | 299 | ); |
| 300 | 300 | ||
| 301 | DEFINE_EVENT(wiphy_only_evt, rdev_get_ringparam, | ||
| 302 | TP_PROTO(struct wiphy *wiphy), | ||
| 303 | TP_ARGS(wiphy) | ||
| 304 | ); | ||
| 305 | |||
| 306 | DEFINE_EVENT(wiphy_only_evt, rdev_get_antenna, | 301 | DEFINE_EVENT(wiphy_only_evt, rdev_get_antenna, |
| 307 | TP_PROTO(struct wiphy *wiphy), | 302 | TP_PROTO(struct wiphy *wiphy), |
| 308 | TP_ARGS(wiphy) | 303 | TP_ARGS(wiphy) |
| @@ -580,11 +575,6 @@ DEFINE_EVENT(wiphy_netdev_evt, rdev_stop_ap, | |||
| 580 | TP_ARGS(wiphy, netdev) | 575 | TP_ARGS(wiphy, netdev) |
| 581 | ); | 576 | ); |
| 582 | 577 | ||
| 583 | DEFINE_EVENT(wiphy_netdev_evt, rdev_get_et_stats, | ||
| 584 | TP_PROTO(struct wiphy *wiphy, struct net_device *netdev), | ||
| 585 | TP_ARGS(wiphy, netdev) | ||
| 586 | ); | ||
| 587 | |||
| 588 | DEFINE_EVENT(wiphy_netdev_evt, rdev_sched_scan_stop, | 578 | DEFINE_EVENT(wiphy_netdev_evt, rdev_sched_scan_stop, |
| 589 | TP_PROTO(struct wiphy *wiphy, struct net_device *netdev), | 579 | TP_PROTO(struct wiphy *wiphy, struct net_device *netdev), |
| 590 | TP_ARGS(wiphy, netdev) | 580 | TP_ARGS(wiphy, netdev) |
| @@ -1439,11 +1429,6 @@ DECLARE_EVENT_CLASS(tx_rx_evt, | |||
| 1439 | WIPHY_PR_ARG, __entry->tx, __entry->rx) | 1429 | WIPHY_PR_ARG, __entry->tx, __entry->rx) |
| 1440 | ); | 1430 | ); |
| 1441 | 1431 | ||
| 1442 | DEFINE_EVENT(tx_rx_evt, rdev_set_ringparam, | ||
| 1443 | TP_PROTO(struct wiphy *wiphy, u32 tx, u32 rx), | ||
| 1444 | TP_ARGS(wiphy, rx, tx) | ||
| 1445 | ); | ||
| 1446 | |||
| 1447 | DEFINE_EVENT(tx_rx_evt, rdev_set_antenna, | 1432 | DEFINE_EVENT(tx_rx_evt, rdev_set_antenna, |
| 1448 | TP_PROTO(struct wiphy *wiphy, u32 tx, u32 rx), | 1433 | TP_PROTO(struct wiphy *wiphy, u32 tx, u32 rx), |
| 1449 | TP_ARGS(wiphy, rx, tx) | 1434 | TP_ARGS(wiphy, rx, tx) |
| @@ -1469,9 +1454,9 @@ TRACE_EVENT(rdev_tdls_mgmt, | |||
| 1469 | TP_PROTO(struct wiphy *wiphy, struct net_device *netdev, | 1454 | TP_PROTO(struct wiphy *wiphy, struct net_device *netdev, |
| 1470 | u8 *peer, u8 action_code, u8 dialog_token, | 1455 | u8 *peer, u8 action_code, u8 dialog_token, |
| 1471 | u16 status_code, u32 peer_capability, | 1456 | u16 status_code, u32 peer_capability, |
| 1472 | const u8 *buf, size_t len), | 1457 | bool initiator, const u8 *buf, size_t len), |
| 1473 | TP_ARGS(wiphy, netdev, peer, action_code, dialog_token, status_code, | 1458 | TP_ARGS(wiphy, netdev, peer, action_code, dialog_token, status_code, |
| 1474 | peer_capability, buf, len), | 1459 | peer_capability, initiator, buf, len), |
| 1475 | TP_STRUCT__entry( | 1460 | TP_STRUCT__entry( |
| 1476 | WIPHY_ENTRY | 1461 | WIPHY_ENTRY |
| 1477 | NETDEV_ENTRY | 1462 | NETDEV_ENTRY |
| @@ -1480,6 +1465,7 @@ TRACE_EVENT(rdev_tdls_mgmt, | |||
| 1480 | __field(u8, dialog_token) | 1465 | __field(u8, dialog_token) |
| 1481 | __field(u16, status_code) | 1466 | __field(u16, status_code) |
| 1482 | __field(u32, peer_capability) | 1467 | __field(u32, peer_capability) |
| 1468 | __field(bool, initiator) | ||
| 1483 | __dynamic_array(u8, buf, len) | 1469 | __dynamic_array(u8, buf, len) |
| 1484 | ), | 1470 | ), |
| 1485 | TP_fast_assign( | 1471 | TP_fast_assign( |
| @@ -1490,13 +1476,16 @@ TRACE_EVENT(rdev_tdls_mgmt, | |||
| 1490 | __entry->dialog_token = dialog_token; | 1476 | __entry->dialog_token = dialog_token; |
| 1491 | __entry->status_code = status_code; | 1477 | __entry->status_code = status_code; |
| 1492 | __entry->peer_capability = peer_capability; | 1478 | __entry->peer_capability = peer_capability; |
| 1479 | __entry->initiator = initiator; | ||
| 1493 | memcpy(__get_dynamic_array(buf), buf, len); | 1480 | memcpy(__get_dynamic_array(buf), buf, len); |
| 1494 | ), | 1481 | ), |
| 1495 | TP_printk(WIPHY_PR_FMT ", " NETDEV_PR_FMT ", " MAC_PR_FMT ", action_code: %u, " | 1482 | TP_printk(WIPHY_PR_FMT ", " NETDEV_PR_FMT ", " MAC_PR_FMT ", action_code: %u, " |
| 1496 | "dialog_token: %u, status_code: %u, peer_capability: %u buf: %#.2x ", | 1483 | "dialog_token: %u, status_code: %u, peer_capability: %u " |
| 1484 | "initiator: %s buf: %#.2x ", | ||
| 1497 | WIPHY_PR_ARG, NETDEV_PR_ARG, MAC_PR_ARG(peer), | 1485 | WIPHY_PR_ARG, NETDEV_PR_ARG, MAC_PR_ARG(peer), |
| 1498 | __entry->action_code, __entry->dialog_token, | 1486 | __entry->action_code, __entry->dialog_token, |
| 1499 | __entry->status_code, __entry->peer_capability, | 1487 | __entry->status_code, __entry->peer_capability, |
| 1488 | BOOL_TO_STR(__entry->initiator), | ||
| 1500 | ((u8 *)__get_dynamic_array(buf))[0]) | 1489 | ((u8 *)__get_dynamic_array(buf))[0]) |
| 1501 | ); | 1490 | ); |
| 1502 | 1491 | ||
| @@ -1725,40 +1714,6 @@ TRACE_EVENT(rdev_set_noack_map, | |||
| 1725 | WIPHY_PR_ARG, NETDEV_PR_ARG, __entry->noack_map) | 1714 | WIPHY_PR_ARG, NETDEV_PR_ARG, __entry->noack_map) |
| 1726 | ); | 1715 | ); |
| 1727 | 1716 | ||
| 1728 | TRACE_EVENT(rdev_get_et_sset_count, | ||
| 1729 | TP_PROTO(struct wiphy *wiphy, struct net_device *netdev, int sset), | ||
| 1730 | TP_ARGS(wiphy, netdev, sset), | ||
| 1731 | TP_STRUCT__entry( | ||
| 1732 | WIPHY_ENTRY | ||
| 1733 | NETDEV_ENTRY | ||
| 1734 | __field(int, sset) | ||
| 1735 | ), | ||
| 1736 | TP_fast_assign( | ||
| 1737 | WIPHY_ASSIGN; | ||
| 1738 | NETDEV_ASSIGN; | ||
| 1739 | __entry->sset = sset; | ||
| 1740 | ), | ||
| 1741 | TP_printk(WIPHY_PR_FMT ", " NETDEV_PR_FMT ", sset: %d", | ||
| 1742 | WIPHY_PR_ARG, NETDEV_PR_ARG, __entry->sset) | ||
| 1743 | ); | ||
| 1744 | |||
| 1745 | TRACE_EVENT(rdev_get_et_strings, | ||
| 1746 | TP_PROTO(struct wiphy *wiphy, struct net_device *netdev, u32 sset), | ||
| 1747 | TP_ARGS(wiphy, netdev, sset), | ||
| 1748 | TP_STRUCT__entry( | ||
| 1749 | WIPHY_ENTRY | ||
| 1750 | NETDEV_ENTRY | ||
| 1751 | __field(u32, sset) | ||
| 1752 | ), | ||
| 1753 | TP_fast_assign( | ||
| 1754 | WIPHY_ASSIGN; | ||
| 1755 | NETDEV_ASSIGN; | ||
| 1756 | __entry->sset = sset; | ||
| 1757 | ), | ||
| 1758 | TP_printk(WIPHY_PR_FMT ", " NETDEV_PR_FMT ", sset: %u", | ||
| 1759 | WIPHY_PR_ARG, NETDEV_PR_ARG, __entry->sset) | ||
| 1760 | ); | ||
| 1761 | |||
| 1762 | DEFINE_EVENT(wiphy_wdev_evt, rdev_get_channel, | 1717 | DEFINE_EVENT(wiphy_wdev_evt, rdev_get_channel, |
| 1763 | TP_PROTO(struct wiphy *wiphy, struct wireless_dev *wdev), | 1718 | TP_PROTO(struct wiphy *wiphy, struct wireless_dev *wdev), |
| 1764 | TP_ARGS(wiphy, wdev) | 1719 | TP_ARGS(wiphy, wdev) |
diff --git a/net/xfrm/xfrm_policy.c b/net/xfrm/xfrm_policy.c index 0525d78ba328..beeed602aeb3 100644 --- a/net/xfrm/xfrm_policy.c +++ b/net/xfrm/xfrm_policy.c | |||
| @@ -389,7 +389,7 @@ redo: | |||
| 389 | if (h != h0) | 389 | if (h != h0) |
| 390 | continue; | 390 | continue; |
| 391 | hlist_del(&pol->bydst); | 391 | hlist_del(&pol->bydst); |
| 392 | hlist_add_after(entry0, &pol->bydst); | 392 | hlist_add_behind(&pol->bydst, entry0); |
| 393 | } | 393 | } |
| 394 | entry0 = &pol->bydst; | 394 | entry0 = &pol->bydst; |
| 395 | } | 395 | } |
| @@ -654,7 +654,7 @@ int xfrm_policy_insert(int dir, struct xfrm_policy *policy, int excl) | |||
| 654 | break; | 654 | break; |
| 655 | } | 655 | } |
| 656 | if (newpos) | 656 | if (newpos) |
| 657 | hlist_add_after(newpos, &policy->bydst); | 657 | hlist_add_behind(&policy->bydst, newpos); |
| 658 | else | 658 | else |
| 659 | hlist_add_head(&policy->bydst, chain); | 659 | hlist_add_head(&policy->bydst, chain); |
| 660 | xfrm_pol_hold(policy); | 660 | xfrm_pol_hold(policy); |
