| .. | .. | 
|---|
| 46 | 46 | #define BCLINK_WIN_MIN      32	/* bcast minimum link window size */ | 
|---|
| 47 | 47 |  | 
|---|
| 48 | 48 | const char tipc_bclink_name[] = "broadcast-link"; | 
|---|
|  | 49 | +unsigned long sysctl_tipc_bc_retruni __read_mostly; | 
|---|
| 49 | 50 |  | 
|---|
| 50 | 51 | /** | 
|---|
| 51 | 52 | * struct tipc_bc_base - base structure for keeping broadcast send state | 
|---|
| .. | .. | 
|---|
| 54 | 55 | * @dests: array keeping number of reachable destinations per bearer | 
|---|
| 55 | 56 | * @primary_bearer: a bearer having links to all broadcast destinations, if any | 
|---|
| 56 | 57 | * @bcast_support: indicates if primary bearer, if any, supports broadcast | 
|---|
|  | 58 | + * @force_bcast: forces broadcast for multicast traffic | 
|---|
| 57 | 59 | * @rcast_support: indicates if all peer nodes support replicast | 
|---|
|  | 60 | + * @force_rcast: forces replicast for multicast traffic | 
|---|
| 58 | 61 | * @rc_ratio: dest count as percentage of cluster size where send method changes | 
|---|
| 59 | 62 | * @bc_threshold: calculated from rc_ratio; if dests > threshold use broadcast | 
|---|
| 60 | 63 | */ | 
|---|
| .. | .. | 
|---|
| 64 | 67 | int dests[MAX_BEARERS]; | 
|---|
| 65 | 68 | int primary_bearer; | 
|---|
| 66 | 69 | bool bcast_support; | 
|---|
|  | 70 | +	bool force_bcast; | 
|---|
| 67 | 71 | bool rcast_support; | 
|---|
|  | 72 | +	bool force_rcast; | 
|---|
| 68 | 73 | int rc_ratio; | 
|---|
| 69 | 74 | int bc_threshold; | 
|---|
| 70 | 75 | }; | 
|---|
| .. | .. | 
|---|
| 80 | 85 | */ | 
|---|
| 81 | 86 | int tipc_bcast_get_mtu(struct net *net) | 
|---|
| 82 | 87 | { | 
|---|
| 83 |  | -	return tipc_link_mtu(tipc_bc_sndlink(net)) - INT_H_SIZE; | 
|---|
|  | 88 | +	return tipc_link_mss(tipc_bc_sndlink(net)); | 
|---|
| 84 | 89 | } | 
|---|
| 85 | 90 |  | 
|---|
| 86 |  | -void tipc_bcast_disable_rcast(struct net *net) | 
|---|
|  | 91 | +void tipc_bcast_toggle_rcast(struct net *net, bool supp) | 
|---|
| 87 | 92 | { | 
|---|
| 88 |  | -	tipc_bc_base(net)->rcast_support = false; | 
|---|
|  | 93 | +	tipc_bc_base(net)->rcast_support = supp; | 
|---|
| 89 | 94 | } | 
|---|
| 90 | 95 |  | 
|---|
| 91 | 96 | static void tipc_bcbase_calc_bc_threshold(struct net *net) | 
|---|
| .. | .. | 
|---|
| 103 | 108 | { | 
|---|
| 104 | 109 | struct tipc_bc_base *bb = tipc_bc_base(net); | 
|---|
| 105 | 110 | int all_dests =  tipc_link_bc_peers(bb->link); | 
|---|
|  | 111 | +	int max_win = tipc_link_max_win(bb->link); | 
|---|
|  | 112 | +	int min_win = tipc_link_min_win(bb->link); | 
|---|
| 106 | 113 | int i, mtu, prim; | 
|---|
| 107 | 114 |  | 
|---|
| 108 | 115 | bb->primary_bearer = INVALID_BEARER_ID; | 
|---|
| .. | .. | 
|---|
| 116 | 123 | continue; | 
|---|
| 117 | 124 |  | 
|---|
| 118 | 125 | mtu = tipc_bearer_mtu(net, i); | 
|---|
| 119 |  | -		if (mtu < tipc_link_mtu(bb->link)) | 
|---|
|  | 126 | +		if (mtu < tipc_link_mtu(bb->link)) { | 
|---|
| 120 | 127 | tipc_link_set_mtu(bb->link, mtu); | 
|---|
|  | 128 | +			tipc_link_set_queue_limits(bb->link, | 
|---|
|  | 129 | +						   min_win, | 
|---|
|  | 130 | +						   max_win); | 
|---|
|  | 131 | +		} | 
|---|
| 121 | 132 | bb->bcast_support &= tipc_bearer_bcast_support(net, i); | 
|---|
| 122 | 133 | if (bb->dests[i] < all_dests) | 
|---|
| 123 | 134 | continue; | 
|---|
| .. | .. | 
|---|
| 216 | 227 | } | 
|---|
| 217 | 228 | /* Can current method be changed ? */ | 
|---|
| 218 | 229 | method->expires = jiffies + TIPC_METHOD_EXPIRE; | 
|---|
| 219 |  | -	if (method->mandatory || time_before(jiffies, exp)) | 
|---|
|  | 230 | +	if (method->mandatory) | 
|---|
| 220 | 231 | return; | 
|---|
| 221 | 232 |  | 
|---|
|  | 233 | +	if (!(tipc_net(net)->capabilities & TIPC_MCAST_RBCTL) && | 
|---|
|  | 234 | +	    time_before(jiffies, exp)) | 
|---|
|  | 235 | +		return; | 
|---|
|  | 236 | + | 
|---|
|  | 237 | +	/* Configuration as force 'broadcast' method */ | 
|---|
|  | 238 | +	if (bb->force_bcast) { | 
|---|
|  | 239 | +		method->rcast = false; | 
|---|
|  | 240 | +		return; | 
|---|
|  | 241 | +	} | 
|---|
|  | 242 | +	/* Configuration as force 'replicast' method */ | 
|---|
|  | 243 | +	if (bb->force_rcast) { | 
|---|
|  | 244 | +		method->rcast = true; | 
|---|
|  | 245 | +		return; | 
|---|
|  | 246 | +	} | 
|---|
|  | 247 | +	/* Configuration as 'autoselect' or default method */ | 
|---|
| 222 | 248 | /* Determine method to use now */ | 
|---|
| 223 | 249 | method->rcast = dests <= bb->bc_threshold; | 
|---|
| 224 | 250 | } | 
|---|
| .. | .. | 
|---|
| 230 | 256 | * Consumes the buffer chain. | 
|---|
| 231 | 257 | * Returns 0 if success, otherwise errno: -EHOSTUNREACH,-EMSGSIZE | 
|---|
| 232 | 258 | */ | 
|---|
| 233 |  | -static int tipc_bcast_xmit(struct net *net, struct sk_buff_head *pkts, | 
|---|
| 234 |  | -			   u16 *cong_link_cnt) | 
|---|
|  | 259 | +int tipc_bcast_xmit(struct net *net, struct sk_buff_head *pkts, | 
|---|
|  | 260 | +		    u16 *cong_link_cnt) | 
|---|
| 235 | 261 | { | 
|---|
| 236 | 262 | struct tipc_link *l = tipc_bc_sndlink(net); | 
|---|
| 237 | 263 | struct sk_buff_head xmitq; | 
|---|
| .. | .. | 
|---|
| 281 | 307 | return 0; | 
|---|
| 282 | 308 | } | 
|---|
| 283 | 309 |  | 
|---|
|  | 310 | +/* tipc_mcast_send_sync - deliver a dummy message with SYN bit | 
|---|
|  | 311 | + * @net: the applicable net namespace | 
|---|
|  | 312 | + * @skb: socket buffer to copy | 
|---|
|  | 313 | + * @method: send method to be used | 
|---|
|  | 314 | + * @dests: destination nodes for message. | 
|---|
|  | 315 | + * Returns 0 if success, otherwise errno | 
|---|
|  | 316 | + */ | 
|---|
|  | 317 | +static int tipc_mcast_send_sync(struct net *net, struct sk_buff *skb, | 
|---|
|  | 318 | +				struct tipc_mc_method *method, | 
|---|
|  | 319 | +				struct tipc_nlist *dests) | 
|---|
|  | 320 | +{ | 
|---|
|  | 321 | +	struct tipc_msg *hdr, *_hdr; | 
|---|
|  | 322 | +	struct sk_buff_head tmpq; | 
|---|
|  | 323 | +	struct sk_buff *_skb; | 
|---|
|  | 324 | +	u16 cong_link_cnt; | 
|---|
|  | 325 | +	int rc = 0; | 
|---|
|  | 326 | + | 
|---|
|  | 327 | +	/* Is a cluster supporting with new capabilities ? */ | 
|---|
|  | 328 | +	if (!(tipc_net(net)->capabilities & TIPC_MCAST_RBCTL)) | 
|---|
|  | 329 | +		return 0; | 
|---|
|  | 330 | + | 
|---|
|  | 331 | +	hdr = buf_msg(skb); | 
|---|
|  | 332 | +	if (msg_user(hdr) == MSG_FRAGMENTER) | 
|---|
|  | 333 | +		hdr = msg_inner_hdr(hdr); | 
|---|
|  | 334 | +	if (msg_type(hdr) != TIPC_MCAST_MSG) | 
|---|
|  | 335 | +		return 0; | 
|---|
|  | 336 | + | 
|---|
|  | 337 | +	/* Allocate dummy message */ | 
|---|
|  | 338 | +	_skb = tipc_buf_acquire(MCAST_H_SIZE, GFP_KERNEL); | 
|---|
|  | 339 | +	if (!_skb) | 
|---|
|  | 340 | +		return -ENOMEM; | 
|---|
|  | 341 | + | 
|---|
|  | 342 | +	/* Preparing for 'synching' header */ | 
|---|
|  | 343 | +	msg_set_syn(hdr, 1); | 
|---|
|  | 344 | + | 
|---|
|  | 345 | +	/* Copy skb's header into a dummy header */ | 
|---|
|  | 346 | +	skb_copy_to_linear_data(_skb, hdr, MCAST_H_SIZE); | 
|---|
|  | 347 | +	skb_orphan(_skb); | 
|---|
|  | 348 | + | 
|---|
|  | 349 | +	/* Reverse method for dummy message */ | 
|---|
|  | 350 | +	_hdr = buf_msg(_skb); | 
|---|
|  | 351 | +	msg_set_size(_hdr, MCAST_H_SIZE); | 
|---|
|  | 352 | +	msg_set_is_rcast(_hdr, !msg_is_rcast(hdr)); | 
|---|
|  | 353 | +	msg_set_errcode(_hdr, TIPC_ERR_NO_PORT); | 
|---|
|  | 354 | + | 
|---|
|  | 355 | +	__skb_queue_head_init(&tmpq); | 
|---|
|  | 356 | +	__skb_queue_tail(&tmpq, _skb); | 
|---|
|  | 357 | +	if (method->rcast) | 
|---|
|  | 358 | +		rc = tipc_bcast_xmit(net, &tmpq, &cong_link_cnt); | 
|---|
|  | 359 | +	else | 
|---|
|  | 360 | +		rc = tipc_rcast_xmit(net, &tmpq, dests, &cong_link_cnt); | 
|---|
|  | 361 | + | 
|---|
|  | 362 | +	/* This queue should normally be empty by now */ | 
|---|
|  | 363 | +	__skb_queue_purge(&tmpq); | 
|---|
|  | 364 | + | 
|---|
|  | 365 | +	return rc; | 
|---|
|  | 366 | +} | 
|---|
|  | 367 | + | 
|---|
| 284 | 368 | /* tipc_mcast_xmit - deliver message to indicated destination nodes | 
|---|
| 285 | 369 | *                   and to identified node local sockets | 
|---|
| 286 | 370 | * @net: the applicable net namespace | 
|---|
| .. | .. | 
|---|
| 296 | 380 | u16 *cong_link_cnt) | 
|---|
| 297 | 381 | { | 
|---|
| 298 | 382 | struct sk_buff_head inputq, localq; | 
|---|
|  | 383 | +	bool rcast = method->rcast; | 
|---|
|  | 384 | +	struct tipc_msg *hdr; | 
|---|
|  | 385 | +	struct sk_buff *skb; | 
|---|
| 299 | 386 | int rc = 0; | 
|---|
| 300 | 387 |  | 
|---|
| 301 | 388 | skb_queue_head_init(&inputq); | 
|---|
| .. | .. | 
|---|
| 309 | 396 | /* Send according to determined transmit method */ | 
|---|
| 310 | 397 | if (dests->remote) { | 
|---|
| 311 | 398 | tipc_bcast_select_xmit_method(net, dests->remote, method); | 
|---|
|  | 399 | + | 
|---|
|  | 400 | +		skb = skb_peek(pkts); | 
|---|
|  | 401 | +		hdr = buf_msg(skb); | 
|---|
|  | 402 | +		if (msg_user(hdr) == MSG_FRAGMENTER) | 
|---|
|  | 403 | +			hdr = msg_inner_hdr(hdr); | 
|---|
|  | 404 | +		msg_set_is_rcast(hdr, method->rcast); | 
|---|
|  | 405 | + | 
|---|
|  | 406 | +		/* Switch method ? */ | 
|---|
|  | 407 | +		if (rcast != method->rcast) { | 
|---|
|  | 408 | +			rc = tipc_mcast_send_sync(net, skb, method, dests); | 
|---|
|  | 409 | +			if (unlikely(rc)) { | 
|---|
|  | 410 | +				pr_err("Unable to send SYN: method %d, rc %d\n", | 
|---|
|  | 411 | +				       rcast, rc); | 
|---|
|  | 412 | +				goto exit; | 
|---|
|  | 413 | +			} | 
|---|
|  | 414 | +		} | 
|---|
|  | 415 | + | 
|---|
| 312 | 416 | if (method->rcast) | 
|---|
| 313 | 417 | rc = tipc_rcast_xmit(net, pkts, dests, cong_link_cnt); | 
|---|
| 314 | 418 | else | 
|---|
| 315 | 419 | rc = tipc_bcast_xmit(net, pkts, cong_link_cnt); | 
|---|
| 316 | 420 | } | 
|---|
| 317 | 421 |  | 
|---|
| 318 |  | -	if (dests->local) | 
|---|
|  | 422 | +	if (dests->local) { | 
|---|
|  | 423 | +		tipc_loopback_trace(net, &localq); | 
|---|
| 319 | 424 | tipc_sk_mcast_rcv(net, &localq, &inputq); | 
|---|
|  | 425 | +	} | 
|---|
| 320 | 426 | exit: | 
|---|
| 321 | 427 | /* This queue should normally be empty by now */ | 
|---|
| 322 | 428 | __skb_queue_purge(pkts); | 
|---|
| .. | .. | 
|---|
| 375 | 481 | __skb_queue_head_init(&xmitq); | 
|---|
| 376 | 482 |  | 
|---|
| 377 | 483 | tipc_bcast_lock(net); | 
|---|
| 378 |  | -	tipc_link_bc_ack_rcv(l, acked, &xmitq); | 
|---|
|  | 484 | +	tipc_link_bc_ack_rcv(l, acked, 0, NULL, &xmitq, NULL); | 
|---|
| 379 | 485 | tipc_bcast_unlock(net); | 
|---|
| 380 | 486 |  | 
|---|
| 381 | 487 | tipc_bcbase_xmit(net, &xmitq); | 
|---|
| .. | .. | 
|---|
| 390 | 496 | * RCU is locked, no other locks set | 
|---|
| 391 | 497 | */ | 
|---|
| 392 | 498 | int tipc_bcast_sync_rcv(struct net *net, struct tipc_link *l, | 
|---|
| 393 |  | -			struct tipc_msg *hdr) | 
|---|
|  | 499 | +			struct tipc_msg *hdr, | 
|---|
|  | 500 | +			struct sk_buff_head *retrq) | 
|---|
| 394 | 501 | { | 
|---|
| 395 | 502 | struct sk_buff_head *inputq = &tipc_bc_base(net)->inputq; | 
|---|
|  | 503 | +	struct tipc_gap_ack_blks *ga; | 
|---|
| 396 | 504 | struct sk_buff_head xmitq; | 
|---|
| 397 | 505 | int rc = 0; | 
|---|
| 398 | 506 |  | 
|---|
| .. | .. | 
|---|
| 402 | 510 | if (msg_type(hdr) != STATE_MSG) { | 
|---|
| 403 | 511 | tipc_link_bc_init_rcv(l, hdr); | 
|---|
| 404 | 512 | } else if (!msg_bc_ack_invalid(hdr)) { | 
|---|
| 405 |  | -		tipc_link_bc_ack_rcv(l, msg_bcast_ack(hdr), &xmitq); | 
|---|
| 406 |  | -		rc = tipc_link_bc_sync_rcv(l, hdr, &xmitq); | 
|---|
|  | 513 | +		tipc_get_gap_ack_blks(&ga, l, hdr, false); | 
|---|
|  | 514 | +		if (!sysctl_tipc_bc_retruni) | 
|---|
|  | 515 | +			retrq = &xmitq; | 
|---|
|  | 516 | +		rc = tipc_link_bc_ack_rcv(l, msg_bcast_ack(hdr), | 
|---|
|  | 517 | +					  msg_bc_gap(hdr), ga, &xmitq, | 
|---|
|  | 518 | +					  retrq); | 
|---|
|  | 519 | +		rc |= tipc_link_bc_sync_rcv(l, hdr, &xmitq); | 
|---|
| 407 | 520 | } | 
|---|
| 408 | 521 | tipc_bcast_unlock(net); | 
|---|
| 409 | 522 |  | 
|---|
| .. | .. | 
|---|
| 456 | 569 | tipc_sk_rcv(net, inputq); | 
|---|
| 457 | 570 | } | 
|---|
| 458 | 571 |  | 
|---|
| 459 |  | -int tipc_bclink_reset_stats(struct net *net) | 
|---|
|  | 572 | +int tipc_bclink_reset_stats(struct net *net, struct tipc_link *l) | 
|---|
| 460 | 573 | { | 
|---|
| 461 |  | -	struct tipc_link *l = tipc_bc_sndlink(net); | 
|---|
| 462 |  | - | 
|---|
| 463 | 574 | if (!l) | 
|---|
| 464 | 575 | return -ENOPROTOOPT; | 
|---|
| 465 | 576 |  | 
|---|
| .. | .. | 
|---|
| 469 | 580 | return 0; | 
|---|
| 470 | 581 | } | 
|---|
| 471 | 582 |  | 
|---|
| 472 |  | -static int tipc_bc_link_set_queue_limits(struct net *net, u32 limit) | 
|---|
|  | 583 | +static int tipc_bc_link_set_queue_limits(struct net *net, u32 max_win) | 
|---|
| 473 | 584 | { | 
|---|
| 474 | 585 | struct tipc_link *l = tipc_bc_sndlink(net); | 
|---|
| 475 | 586 |  | 
|---|
| 476 | 587 | if (!l) | 
|---|
| 477 | 588 | return -ENOPROTOOPT; | 
|---|
| 478 |  | -	if (limit < BCLINK_WIN_MIN) | 
|---|
| 479 |  | -		limit = BCLINK_WIN_MIN; | 
|---|
| 480 |  | -	if (limit > TIPC_MAX_LINK_WIN) | 
|---|
|  | 589 | +	if (max_win < BCLINK_WIN_MIN) | 
|---|
|  | 590 | +		max_win = BCLINK_WIN_MIN; | 
|---|
|  | 591 | +	if (max_win > TIPC_MAX_LINK_WIN) | 
|---|
| 481 | 592 | return -EINVAL; | 
|---|
| 482 | 593 | tipc_bcast_lock(net); | 
|---|
| 483 |  | -	tipc_link_set_queue_limits(l, limit); | 
|---|
|  | 594 | +	tipc_link_set_queue_limits(l, tipc_link_min_win(l), max_win); | 
|---|
| 484 | 595 | tipc_bcast_unlock(net); | 
|---|
|  | 596 | +	return 0; | 
|---|
|  | 597 | +} | 
|---|
|  | 598 | + | 
|---|
|  | 599 | +static int tipc_bc_link_set_broadcast_mode(struct net *net, u32 bc_mode) | 
|---|
|  | 600 | +{ | 
|---|
|  | 601 | +	struct tipc_bc_base *bb = tipc_bc_base(net); | 
|---|
|  | 602 | + | 
|---|
|  | 603 | +	switch (bc_mode) { | 
|---|
|  | 604 | +	case BCLINK_MODE_BCAST: | 
|---|
|  | 605 | +		if (!bb->bcast_support) | 
|---|
|  | 606 | +			return -ENOPROTOOPT; | 
|---|
|  | 607 | + | 
|---|
|  | 608 | +		bb->force_bcast = true; | 
|---|
|  | 609 | +		bb->force_rcast = false; | 
|---|
|  | 610 | +		break; | 
|---|
|  | 611 | +	case BCLINK_MODE_RCAST: | 
|---|
|  | 612 | +		if (!bb->rcast_support) | 
|---|
|  | 613 | +			return -ENOPROTOOPT; | 
|---|
|  | 614 | + | 
|---|
|  | 615 | +		bb->force_bcast = false; | 
|---|
|  | 616 | +		bb->force_rcast = true; | 
|---|
|  | 617 | +		break; | 
|---|
|  | 618 | +	case BCLINK_MODE_SEL: | 
|---|
|  | 619 | +		if (!bb->bcast_support || !bb->rcast_support) | 
|---|
|  | 620 | +			return -ENOPROTOOPT; | 
|---|
|  | 621 | + | 
|---|
|  | 622 | +		bb->force_bcast = false; | 
|---|
|  | 623 | +		bb->force_rcast = false; | 
|---|
|  | 624 | +		break; | 
|---|
|  | 625 | +	default: | 
|---|
|  | 626 | +		return -EINVAL; | 
|---|
|  | 627 | +	} | 
|---|
|  | 628 | + | 
|---|
|  | 629 | +	return 0; | 
|---|
|  | 630 | +} | 
|---|
|  | 631 | + | 
|---|
|  | 632 | +static int tipc_bc_link_set_broadcast_ratio(struct net *net, u32 bc_ratio) | 
|---|
|  | 633 | +{ | 
|---|
|  | 634 | +	struct tipc_bc_base *bb = tipc_bc_base(net); | 
|---|
|  | 635 | + | 
|---|
|  | 636 | +	if (!bb->bcast_support || !bb->rcast_support) | 
|---|
|  | 637 | +		return -ENOPROTOOPT; | 
|---|
|  | 638 | + | 
|---|
|  | 639 | +	if (bc_ratio > 100 || bc_ratio <= 0) | 
|---|
|  | 640 | +		return -EINVAL; | 
|---|
|  | 641 | + | 
|---|
|  | 642 | +	bb->rc_ratio = bc_ratio; | 
|---|
|  | 643 | +	tipc_bcast_lock(net); | 
|---|
|  | 644 | +	tipc_bcbase_calc_bc_threshold(net); | 
|---|
|  | 645 | +	tipc_bcast_unlock(net); | 
|---|
|  | 646 | + | 
|---|
| 485 | 647 | return 0; | 
|---|
| 486 | 648 | } | 
|---|
| 487 | 649 |  | 
|---|
| .. | .. | 
|---|
| 489 | 651 | { | 
|---|
| 490 | 652 | int err; | 
|---|
| 491 | 653 | u32 win; | 
|---|
|  | 654 | +	u32 bc_mode; | 
|---|
|  | 655 | +	u32 bc_ratio; | 
|---|
| 492 | 656 | struct nlattr *props[TIPC_NLA_PROP_MAX + 1]; | 
|---|
| 493 | 657 |  | 
|---|
| 494 | 658 | if (!attrs[TIPC_NLA_LINK_PROP]) | 
|---|
| .. | .. | 
|---|
| 498 | 662 | if (err) | 
|---|
| 499 | 663 | return err; | 
|---|
| 500 | 664 |  | 
|---|
| 501 |  | -	if (!props[TIPC_NLA_PROP_WIN]) | 
|---|
|  | 665 | +	if (!props[TIPC_NLA_PROP_WIN] && | 
|---|
|  | 666 | +	    !props[TIPC_NLA_PROP_BROADCAST] && | 
|---|
|  | 667 | +	    !props[TIPC_NLA_PROP_BROADCAST_RATIO]) { | 
|---|
| 502 | 668 | return -EOPNOTSUPP; | 
|---|
|  | 669 | +	} | 
|---|
| 503 | 670 |  | 
|---|
| 504 |  | -	win = nla_get_u32(props[TIPC_NLA_PROP_WIN]); | 
|---|
|  | 671 | +	if (props[TIPC_NLA_PROP_BROADCAST]) { | 
|---|
|  | 672 | +		bc_mode = nla_get_u32(props[TIPC_NLA_PROP_BROADCAST]); | 
|---|
|  | 673 | +		err = tipc_bc_link_set_broadcast_mode(net, bc_mode); | 
|---|
|  | 674 | +	} | 
|---|
| 505 | 675 |  | 
|---|
| 506 |  | -	return tipc_bc_link_set_queue_limits(net, win); | 
|---|
|  | 676 | +	if (!err && props[TIPC_NLA_PROP_BROADCAST_RATIO]) { | 
|---|
|  | 677 | +		bc_ratio = nla_get_u32(props[TIPC_NLA_PROP_BROADCAST_RATIO]); | 
|---|
|  | 678 | +		err = tipc_bc_link_set_broadcast_ratio(net, bc_ratio); | 
|---|
|  | 679 | +	} | 
|---|
|  | 680 | + | 
|---|
|  | 681 | +	if (!err && props[TIPC_NLA_PROP_WIN]) { | 
|---|
|  | 682 | +		win = nla_get_u32(props[TIPC_NLA_PROP_WIN]); | 
|---|
|  | 683 | +		err = tipc_bc_link_set_queue_limits(net, win); | 
|---|
|  | 684 | +	} | 
|---|
|  | 685 | + | 
|---|
|  | 686 | +	return err; | 
|---|
| 507 | 687 | } | 
|---|
| 508 | 688 |  | 
|---|
| 509 | 689 | int tipc_bcast_init(struct net *net) | 
|---|
| .. | .. | 
|---|
| 518 | 698 | tn->bcbase = bb; | 
|---|
| 519 | 699 | spin_lock_init(&tipc_net(net)->bclock); | 
|---|
| 520 | 700 |  | 
|---|
| 521 |  | -	if (!tipc_link_bc_create(net, 0, 0, | 
|---|
| 522 |  | -				 FB_MTU, | 
|---|
|  | 701 | +	if (!tipc_link_bc_create(net, 0, 0, NULL, | 
|---|
|  | 702 | +				 one_page_mtu, | 
|---|
|  | 703 | +				 BCLINK_WIN_DEFAULT, | 
|---|
| 523 | 704 | BCLINK_WIN_DEFAULT, | 
|---|
| 524 | 705 | 0, | 
|---|
| 525 | 706 | &bb->inputq, | 
|---|
| .. | .. | 
|---|
| 529 | 710 | goto enomem; | 
|---|
| 530 | 711 | bb->link = l; | 
|---|
| 531 | 712 | tn->bcl = l; | 
|---|
| 532 |  | -	bb->rc_ratio = 25; | 
|---|
|  | 713 | +	bb->rc_ratio = 10; | 
|---|
| 533 | 714 | bb->rcast_support = true; | 
|---|
| 534 | 715 | return 0; | 
|---|
| 535 | 716 | enomem: | 
|---|
| .. | .. | 
|---|
| 576 | 757 | nl->remote = 0; | 
|---|
| 577 | 758 | nl->local = false; | 
|---|
| 578 | 759 | } | 
|---|
|  | 760 | + | 
|---|
|  | 761 | +u32 tipc_bcast_get_mode(struct net *net) | 
|---|
|  | 762 | +{ | 
|---|
|  | 763 | +	struct tipc_bc_base *bb = tipc_bc_base(net); | 
|---|
|  | 764 | + | 
|---|
|  | 765 | +	if (bb->force_bcast) | 
|---|
|  | 766 | +		return BCLINK_MODE_BCAST; | 
|---|
|  | 767 | + | 
|---|
|  | 768 | +	if (bb->force_rcast) | 
|---|
|  | 769 | +		return BCLINK_MODE_RCAST; | 
|---|
|  | 770 | + | 
|---|
|  | 771 | +	if (bb->bcast_support && bb->rcast_support) | 
|---|
|  | 772 | +		return BCLINK_MODE_SEL; | 
|---|
|  | 773 | + | 
|---|
|  | 774 | +	return 0; | 
|---|
|  | 775 | +} | 
|---|
|  | 776 | + | 
|---|
|  | 777 | +u32 tipc_bcast_get_broadcast_ratio(struct net *net) | 
|---|
|  | 778 | +{ | 
|---|
|  | 779 | +	struct tipc_bc_base *bb = tipc_bc_base(net); | 
|---|
|  | 780 | + | 
|---|
|  | 781 | +	return bb->rc_ratio; | 
|---|
|  | 782 | +} | 
|---|
|  | 783 | + | 
|---|
|  | 784 | +void tipc_mcast_filter_msg(struct net *net, struct sk_buff_head *defq, | 
|---|
|  | 785 | +			   struct sk_buff_head *inputq) | 
|---|
|  | 786 | +{ | 
|---|
|  | 787 | +	struct sk_buff *skb, *_skb, *tmp; | 
|---|
|  | 788 | +	struct tipc_msg *hdr, *_hdr; | 
|---|
|  | 789 | +	bool match = false; | 
|---|
|  | 790 | +	u32 node, port; | 
|---|
|  | 791 | + | 
|---|
|  | 792 | +	skb = skb_peek(inputq); | 
|---|
|  | 793 | +	if (!skb) | 
|---|
|  | 794 | +		return; | 
|---|
|  | 795 | + | 
|---|
|  | 796 | +	hdr = buf_msg(skb); | 
|---|
|  | 797 | + | 
|---|
|  | 798 | +	if (likely(!msg_is_syn(hdr) && skb_queue_empty(defq))) | 
|---|
|  | 799 | +		return; | 
|---|
|  | 800 | + | 
|---|
|  | 801 | +	node = msg_orignode(hdr); | 
|---|
|  | 802 | +	if (node == tipc_own_addr(net)) | 
|---|
|  | 803 | +		return; | 
|---|
|  | 804 | + | 
|---|
|  | 805 | +	port = msg_origport(hdr); | 
|---|
|  | 806 | + | 
|---|
|  | 807 | +	/* Has the twin SYN message already arrived ? */ | 
|---|
|  | 808 | +	skb_queue_walk(defq, _skb) { | 
|---|
|  | 809 | +		_hdr = buf_msg(_skb); | 
|---|
|  | 810 | +		if (msg_orignode(_hdr) != node) | 
|---|
|  | 811 | +			continue; | 
|---|
|  | 812 | +		if (msg_origport(_hdr) != port) | 
|---|
|  | 813 | +			continue; | 
|---|
|  | 814 | +		match = true; | 
|---|
|  | 815 | +		break; | 
|---|
|  | 816 | +	} | 
|---|
|  | 817 | + | 
|---|
|  | 818 | +	if (!match) { | 
|---|
|  | 819 | +		if (!msg_is_syn(hdr)) | 
|---|
|  | 820 | +			return; | 
|---|
|  | 821 | +		__skb_dequeue(inputq); | 
|---|
|  | 822 | +		__skb_queue_tail(defq, skb); | 
|---|
|  | 823 | +		return; | 
|---|
|  | 824 | +	} | 
|---|
|  | 825 | + | 
|---|
|  | 826 | +	/* Deliver non-SYN message from other link, otherwise queue it */ | 
|---|
|  | 827 | +	if (!msg_is_syn(hdr)) { | 
|---|
|  | 828 | +		if (msg_is_rcast(hdr) != msg_is_rcast(_hdr)) | 
|---|
|  | 829 | +			return; | 
|---|
|  | 830 | +		__skb_dequeue(inputq); | 
|---|
|  | 831 | +		__skb_queue_tail(defq, skb); | 
|---|
|  | 832 | +		return; | 
|---|
|  | 833 | +	} | 
|---|
|  | 834 | + | 
|---|
|  | 835 | +	/* Queue non-SYN/SYN message from same link */ | 
|---|
|  | 836 | +	if (msg_is_rcast(hdr) == msg_is_rcast(_hdr)) { | 
|---|
|  | 837 | +		__skb_dequeue(inputq); | 
|---|
|  | 838 | +		__skb_queue_tail(defq, skb); | 
|---|
|  | 839 | +		return; | 
|---|
|  | 840 | +	} | 
|---|
|  | 841 | + | 
|---|
|  | 842 | +	/* Matching SYN messages => return the one with data, if any */ | 
|---|
|  | 843 | +	__skb_unlink(_skb, defq); | 
|---|
|  | 844 | +	if (msg_data_sz(hdr)) { | 
|---|
|  | 845 | +		kfree_skb(_skb); | 
|---|
|  | 846 | +	} else { | 
|---|
|  | 847 | +		__skb_dequeue(inputq); | 
|---|
|  | 848 | +		kfree_skb(skb); | 
|---|
|  | 849 | +		__skb_queue_tail(inputq, _skb); | 
|---|
|  | 850 | +	} | 
|---|
|  | 851 | + | 
|---|
|  | 852 | +	/* Deliver subsequent non-SYN messages from same peer */ | 
|---|
|  | 853 | +	skb_queue_walk_safe(defq, _skb, tmp) { | 
|---|
|  | 854 | +		_hdr = buf_msg(_skb); | 
|---|
|  | 855 | +		if (msg_orignode(_hdr) != node) | 
|---|
|  | 856 | +			continue; | 
|---|
|  | 857 | +		if (msg_origport(_hdr) != port) | 
|---|
|  | 858 | +			continue; | 
|---|
|  | 859 | +		if (msg_is_syn(_hdr)) | 
|---|
|  | 860 | +			break; | 
|---|
|  | 861 | +		__skb_unlink(_skb, defq); | 
|---|
|  | 862 | +		__skb_queue_tail(inputq, _skb); | 
|---|
|  | 863 | +	} | 
|---|
|  | 864 | +} | 
|---|