u16 tipc_get_gap_ack_blks(struct tipc_gap_ack_blks **ga, struct tipc_link *l,
			  struct tipc_msg *hdr, bool uc)
{
	struct tipc_gap_ack_blks *p;
	u16 sz = 0;

	/* Does peer support the Gap ACK blocks feature? */
	if (l->peer_caps & TIPC_GAP_ACK_BLOCK) {
		p = (struct tipc_gap_ack_blks *)msg_data(hdr);
		sz = ntohs(p->len);
		/* Sanity check */
		if (sz == struct_size(p, gacks, p->ugack_cnt + p->bgack_cnt)) {
			/* Good, check if the desired type exists */
			if ((uc && p->ugack_cnt) || (!uc && p->bgack_cnt))
				goto ok;
		/* Backward compatible: peer might not support bc, but uc? */
		} else if (uc && sz == struct_size(p, gacks, p->ugack_cnt)) {
			if (p->ugack_cnt) {
				p->bgack_cnt = 0;
				goto ok;
			}
		}
	}
	/* Other cases: ignore! */
	p = NULL;

ok:
	*ga = p;
	return sz;
}
u16 tipc_get_gap_ack_blks(struct tipc_gap_ack_blks **ga, struct tipc_link *l,
			  struct tipc_msg *hdr, bool uc)
{
	struct tipc_gap_ack_blks *p;
	u16 sz = 0;

	 
	if (l->peer_caps & TIPC_GAP_ACK_BLOCK) {
		p = (struct tipc_gap_ack_blks *)msg_data(hdr);
		sz = ntohs(p->len);
		 
		if (sz == struct_size(p, gacks, p->ugack_cnt + p->bgack_cnt)) {
			 
			if ((uc && p->ugack_cnt) || (!uc && p->bgack_cnt))
				goto ok;
		 
		} else if (uc && sz == struct_size(p, gacks, p->ugack_cnt)) {
			if (p->ugack_cnt) {
				p->bgack_cnt = 0;
				goto ok;
			}
		}
	}
	 
	p = NULL;

ok:
	*ga = p;
	return sz;
}