// File: /workspace/github_c_makefile_star2_O2/open-mesh-mirror[P]batmand/schedule.c
// Function: schedule_forward_packet
void schedule_forward_packet(struct orig_node *orig_node, struct bat_packet *in, uint32_t neigh, uint8_t directlink, int16_t hna_buff_len, struct batman_if *if_incoming, uint32_t curr_time)
{
	struct forw_node *forw_node_new = NULL, *forw_node_aggregate = NULL, *forw_node_pos = NULL;
	struct list_head *list_pos = forw_list.next, *prev_list_head = (struct list_head *)&forw_list;
	struct bat_packet *bat_packet;
	uint8_t tq_avg = 0;
	uint32_t send_time;
	prof_start(PROF_schedule_forward_packet);

	debug_output(4, "schedule_forward_packet():  \n");

	if (in->ttl <= 1) {
		debug_output(4, "ttl exceeded \n");
		prof_stop(PROF_schedule_forward_packet);
		return;
	}

	if (aggregation_enabled)
		send_time = curr_time + MAX_AGGREGATION_MS - (JITTER/2) + rand_num(JITTER);
	else
		send_time = curr_time + rand_num(JITTER/2);


	/* find position for the packet in the forward queue */
	list_for_each(list_pos, &forw_list) {

		forw_node_pos = list_entry(list_pos, struct forw_node, list);

		if (aggregation_enabled) {

			/* don't save aggregation position if aggregation is disabled */
			forw_node_aggregate = forw_node_pos;

			/**
			 * we can aggregate the current packet to this packet if:
			 * - the send time is within our MAX_AGGREGATION_MS time
			 * - the resulting packet wont be bigger than MAX_AGGREGATION_BYTES
			 */
			if (((int)(forw_node_pos->send_time - send_time) < 0) &&
				(forw_node_pos->pack_buff_len + sizeof(struct bat_packet) + hna_buff_len <= MAX_AGGREGATION_BYTES)) {

				bat_packet = (struct bat_packet *)forw_node_pos->pack_buff;

				/**
				 * check aggregation compatibility
				 * -> direct link packets are broadcasted on their interface only
				 * -> aggregate packet if the current packet is a "global" packet
				 *    as well as the base packet
				 */

				/* packets without direct link flag and high TTL are flooded through the net  */
				if ((!directlink) && (!(bat_packet->flags & DIRECTLINK)) && (bat_packet->ttl != 1) &&

				/* own packets originating non-primary interfaces leave only that interface */
						((!forw_node_pos->own) || (forw_node_pos->if_incoming->if_num == 0)))
					break;

				/* if the incoming packet is sent via this one interface only - we still can aggregate */
				if ((directlink) && (in->ttl == 2) && (forw_node_pos->if_incoming == if_incoming))
					break;

			}

			/* could not find packet to aggregate with */
			forw_node_aggregate = NULL;

		}

		if ((int)(forw_node_pos->send_time - send_time) > 0)
			break;

		prev_list_head = &forw_node_pos->list;
		forw_node_pos = NULL;

	}

	/* nothing to aggregate with - either aggregation disabled or no suitable aggregation packet found */
	if (forw_node_aggregate == NULL) {

		forw_node_new = debugMalloc(sizeof(struct forw_node), 504);
		forw_node_new->pack_buff = debugMalloc(MAX_AGGREGATION_BYTES, 505);

		INIT_LIST_HEAD(&forw_node_new->list);

		forw_node_new->pack_buff_len = sizeof(struct bat_packet) + hna_buff_len;
		memcpy(forw_node_new->pack_buff, in, forw_node_new->pack_buff_len);

		bat_packet = (struct bat_packet *)forw_node_new->pack_buff;

		forw_node_new->own = 0;
		forw_node_new->if_incoming = if_incoming;
		forw_node_new->num_packets = 0;
		forw_node_new->direct_link_flags = 0;

		forw_node_new->send_time = send_time;

	} else {

		memcpy(forw_node_aggregate->pack_buff + forw_node_aggregate->pack_buff_len, in, sizeof(struct bat_packet) + hna_buff_len);
		bat_packet = (struct bat_packet *)(forw_node_aggregate->pack_buff + forw_node_aggregate->pack_buff_len);
		forw_node_aggregate->pack_buff_len += sizeof(struct bat_packet) + hna_buff_len;

		forw_node_aggregate->num_packets++;

		forw_node_new = forw_node_aggregate;

	}

	/* save packet direct link flag status */
	if (directlink)
		forw_node_new->direct_link_flags = forw_node_new->direct_link_flags | (1 << forw_node_new->num_packets);

	bat_packet->ttl--;
	bat_packet->prev_sender = neigh;

	/* rebroadcast tq of our best ranking neighbor to ensure the rebroadcast of our best tq value */
	if ((orig_node->router != NULL) && (orig_node->router->tq_avg != 0)) {

		/* rebroadcast ogm of best ranking neighbor as is */
		if (orig_node->router->addr != neigh) {
			bat_packet->tq = orig_node->router->tq_avg;

			if (orig_node->router->last_ttl)
				bat_packet->ttl = orig_node->router->last_ttl - 1;
		}

		tq_avg = orig_node->router->tq_avg;

	}

	/* apply hop penalty */
	bat_packet->tq = (bat_packet->tq * (TQ_MAX_VALUE - hop_penalty)) / (TQ_MAX_VALUE);

	debug_output(4, "forwarding: tq_orig: %i, tq_avg: %i, tq_forw: %i, ttl_orig: %i, ttl_forw: %i \n", in->tq, tq_avg, bat_packet->tq, in->ttl - 1, bat_packet->ttl);

	/* change sequence number to network order */
	bat_packet->seqno = htons(bat_packet->seqno);

	if (directlink)
		bat_packet->flags |= DIRECTLINK;
	else
		bat_packet->flags &= ~DIRECTLINK;


	/* if the packet was not aggregated */
	if (forw_node_aggregate == NULL) {

		/* if the packet should go somewhere in the queue */
		if (forw_node_pos != NULL)
			list_add_before(prev_list_head, list_pos, &forw_node_new->list);
		/* if the packet is the last packet in the queue */
		else
			list_add_tail(&forw_node_new->list, &forw_list);

	}

	prof_stop(PROF_schedule_forward_packet);
}

// Assembly:
pushq %rbp
pushq %r15
pushq %r14
pushq %r13
pushq %r12
pushq %rbx
subq $0x28, %rsp
movq %r9, 0x10(%rsp)
movl %r8d, %r13d
movl %ecx, 0xc(%rsp)
movl %edx, %ebp
movq %rsi, %rbx
movq %rdi, %r12
movl 0x60(%rsp), %r14d
pushq $0x7
popq %rdi
callq 0x63a8
leaq 0xa343(%rip), %rsi      # 0xf4f8
pushq $0x4
popq %rdi
xorl %eax, %eax
callq 0xcb1c
cmpb $0x1, 0x2(%rbx)
ja 0x51db
leaq 0xa34a(%rip), %rsi      # 0xf516
pushq $0x4
popq %rdi
xorl %eax, %eax
callq 0xcb1c
jmp 0x5408
movl %ebp, 0x1c(%rsp)
leaq 0x120b3(%rip), %r15     # 0x17299
cmpb $0x0, (%r15)
movq %r12, 0x20(%rsp)
je 0x5202
pushq $0x64
popq %rdi
callq 0xb066
leal (%r14,%rax), %ebp
addl $0x32, %ebp
jmp 0x520f
pushq $0x32
popq %rdi
callq 0xb066
movl %eax, %ebp
addl %r14d, %ebp
movb (%r15), %cl
movswq %r13w, %r12
addq $0x12, %r12
leaq 0x12117(%rip), %rdx     # 0x17338
xorl %eax, %eax
movq %rdx, %r14
movl 0xc(%rsp), %r10d
movq %r14, %r15
movq (%r14), %r14
cmpq %rdx, %r14
je 0x52a2
movl 0x8(%r14), %esi
subl %ebp, %esi
testb %cl, %cl
je 0x529b
testl %esi, %esi
jns 0x529b
movzwl 0x18(%r14), %r8d
leaq (%r12,%r8), %rdi
cmpq $0x200, %rdi            # imm = 0x200
ja 0x529b
movq 0x10(%r14), %rdi
testb %r10b, %r10b
je 0x5275
cmpb $0x2, 0x2(%rbx)
jne 0x529b
movq 0x10(%rsp), %r9
cmpq %r9, 0x28(%r14)
jne 0x529b
jmp 0x541e
testb $0x40, 0x1(%rdi)
jne 0x529b
cmpb $0x1, 0x2(%rdi)
je 0x529b
cmpb $0x0, 0xc(%r14)
je 0x541e
movq 0x28(%r14), %r9
cmpb $0x0, 0x1c(%r9)
je 0x541e
testl %esi, %esi
jle 0x522b
movq %r14, %rax
testq %rax, %rax
sete %al
movl %eax, 0x8(%rsp)
pushq $0x30
popq %rdi
movl $0x1f8, %esi            # imm = 0x1F8
callq 0x58c9
movq %rax, %r12
movl $0x200, %edi            # imm = 0x200
movl $0x1f9, %esi            # imm = 0x1F9
callq 0x58c9
movq %rax, 0x10(%r12)
movq %r12, (%r12)
addl $0x12, %r13d
movw %r13w, 0x18(%r12)
movzwl %r13w, %edx
movq %rax, %rdi
movq %rbx, %rsi
callq 0x2290
movq 0x10(%r12), %r13
xorl %ecx, %ecx
movb %cl, 0xc(%r12)
movq 0x10(%rsp), %rax
movq %rax, 0x28(%r12)
movb %cl, 0x20(%r12)
andl $0x0, 0x1c(%r12)
movl %ebp, 0x8(%r12)
movb $0x1, %r8b
movl 0xc(%rsp), %edx
testb %dl, %dl
movl 0x1c(%rsp), %edi
je 0x532c
pushq $0x1
popq %rax
shll %cl, %eax
orl %eax, 0x1c(%r12)
movb 0x2(%r13), %sil
decb %sil
movb %sil, 0x2(%r13)
movl %edi, 0xc(%r13)
movq 0x20(%rsp), %rax
movq 0x8(%rax), %rax
testq %rax, %rax
movl %r8d, 0x10(%rsp)
je 0x5370
movzbl 0x19(%rax), %ecx
testl %ecx, %ecx
je 0x5370
cmpl %edi, 0x8(%rax)
je 0x5372
movb %cl, 0x10(%r13)
movb 0x1a(%rax), %al
testb %al, %al
je 0x5372
decb %al
movb %al, 0x2(%r13)
movl %eax, %esi
jmp 0x5372
xorl %ecx, %ecx
testb %dl, %dl
setne %bpl
movzbl 0x10(%r13), %edx
leaq 0x11f08(%rip), %rax     # 0x1728c
movzbl (%rax), %eax
xorl $0xff, %eax
imull %edx, %eax
movw $0xff, %di
xorl %edx, %edx
divw %di
movb %al, 0x10(%r13)
movzbl 0x10(%rbx), %edx
movzwl %ax, %r8d
movzbl 0x2(%rbx), %r9d
decl %r9d
movzbl %sil, %eax
movl %eax, (%rsp)
leaq 0xa16b(%rip), %rsi      # 0xf525
pushq $0x4
popq %rdi
xorl %eax, %eax
callq 0xcb1c
rolw $0x8, 0x4(%r13)
movb 0x1(%r13), %al
andb $-0x41, %al
shlb $0x6, %bpl
orb %al, %bpl
movb %bpl, 0x1(%r13)
cmpb $0x0, 0x10(%rsp)
je 0x5408
cmpb $0x0, 0x8(%rsp)
je 0x53fa
leaq 0x11f48(%rip), %rsi     # 0x17338
movq %r12, %rdi
callq 0x574d
jmp 0x5408
movq %r15, %rdi
movq %r14, %rsi
movq %r12, %rdx
callq 0x575c
pushq $0x7
popq %rdi
addq $0x28, %rsp
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
jmp 0x63c4
testq %r14, %r14
je 0x5462
addq %r8, %rdi
movq %rbx, %rsi
movq %r12, %rdx
callq 0x2290
movzwl 0x18(%r14), %r13d
addl %r13d, %r12d
addq 0x10(%r14), %r13
movw %r12w, 0x18(%r14)
movb 0x20(%r14), %al
incb %al
movb %al, 0x20(%r14)
movzbl %al, %ecx
xorl %r8d, %r8d
movl $0x0, 0x8(%rsp)
movq %r14, %r12
jmp 0x5316
movb $0x1, %al
jmp 0x52a8