// File: /workspace/github_c_makefile_star2_O1/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 $0x38, %rsp
movq %r9, %r12
movl %r8d, %r13d
movl %ecx, 0x18(%rsp)
movl %edx, %ebp
movq %rsi, %r14
movq %rdi, %r15
movl 0x70(%rsp), %ebx
movl $0x7, %edi
callq 0x6880
leaq 0xaf5e(%rip), %rsi      # 0x104f8
movl $0x4, %edi
xorl %eax, %eax
callq 0xd5b0
movq %r14, 0x28(%rsp)
cmpb $0x1, 0x2(%r14)
ja 0x55ca
leaq 0xaf5d(%rip), %rsi      # 0x10516
movl $0x4, %edi
xorl %eax, %eax
callq 0xd5b0
jmp 0x583b
movl %ebp, 0x14(%rsp)
leaq 0x11cc4(%rip), %r14     # 0x17299
cmpb $0x0, (%r14)
movq %r15, 0x30(%rsp)
movq %r12, 0x20(%rsp)
je 0x55f7
movl $0x64, %edi
callq 0xb8d1
leal (%rbx,%rax), %ebp
addl $0x32, %ebp
jmp 0x5605
movl $0x32, %edi
callq 0xb8d1
movl %eax, %ebp
addl %ebx, %ebp
movb (%r14), %al
movl %r13d, 0x1c(%rsp)
movswq %r13w, %r13
addq $0x12, %r13
leaq 0x11d1c(%rip), %rcx     # 0x17338
xorl %r12d, %r12d
movq %rcx, %r14
movq 0x28(%rsp), %rbx
movl 0x18(%rsp), %esi
movq %r14, %r15
movq (%r14), %r14
cmpq %rcx, %r14
je 0x56a6
testb %al, %al
je 0x5695
cmpl %ebp, 0x8(%r14)
jns 0x5695
movzwl 0x18(%r14), %edx
addq %r13, %rdx
cmpq $0x200, %rdx            # imm = 0x200
ja 0x5695
testb %sil, %sil
je 0x566c
cmpb $0x2, 0x2(%rbx)
jne 0x5695
movq 0x20(%rsp), %rdx
cmpq %rdx, 0x28(%r14)
jne 0x5695
jmp 0x5853
movq 0x10(%r14), %rdx
testb $0x40, 0x1(%rdx)
jne 0x5695
cmpb $0x1, 0x2(%rdx)
je 0x5695
cmpb $0x0, 0xc(%r14)
je 0x5853
movq 0x28(%r14), %rdx
cmpb $0x0, 0x1c(%rdx)
je 0x5853
movl 0x8(%r14), %edx
subl %ebp, %edx
testl %edx, %edx
jle 0x562b
movq %r14, 0x8(%rsp)
jmp 0x56af
movq $0x0, 0x8(%rsp)
testq %r12, %r12
je 0x56e8
movzwl 0x18(%r12), %edi
addq 0x10(%r12), %rdi
movq %rbx, %rsi
movq %r13, %rdx
callq 0x2290
movzwl 0x18(%r12), %ebx
addl %ebx, %r13d
addq 0x10(%r12), %rbx
movw %r13w, 0x18(%r12)
incb 0x20(%r12)
movq %r12, %r13
jmp 0x574e
movl $0x30, %edi
movl $0x1f8, %esi            # imm = 0x1F8
callq 0x5d3e
movq %rax, %r13
movl $0x200, %edi            # imm = 0x200
movl $0x1f9, %esi            # imm = 0x1F9
callq 0x5d3e
movq %rax, 0x10(%r13)
movq %r13, (%r13)
movl 0x1c(%rsp), %ecx
addl $0x12, %ecx
movw %cx, 0x18(%r13)
movzwl %cx, %edx
movq %rax, %rdi
movq %rbx, %rsi
callq 0x2290
movq 0x10(%r13), %rbx
xorl %eax, %eax
movb %al, 0xc(%r13)
movq 0x20(%rsp), %rcx
movq %rcx, 0x28(%r13)
movb %al, 0x20(%r13)
movl $0x0, 0x1c(%r13)
movl %ebp, 0x8(%r13)
movl 0x14(%rsp), %edi
movl 0x18(%rsp), %esi
testb %sil, %sil
je 0x576a
movb 0x20(%r13), %cl
movl $0x1, %eax
shll %cl, %eax
orl %eax, 0x1c(%r13)
decb 0x2(%rbx)
movl %edi, 0xc(%rbx)
movq 0x30(%rsp), %rax
movq 0x8(%rax), %rdx
xorl %ecx, %ecx
testq %rdx, %rdx
je 0x579e
movzbl 0x19(%rdx), %eax
testl %eax, %eax
je 0x579e
cmpl %edi, 0x8(%rdx)
je 0x579c
movb %al, 0x10(%rbx)
movb 0x1a(%rdx), %cl
testb %cl, %cl
je 0x579c
decb %cl
movb %cl, 0x2(%rbx)
movl %eax, %ecx
testb %sil, %sil
setne %bpl
movzbl 0x10(%rbx), %eax
leaq 0x11adc(%rip), %rdx     # 0x1728c
movzbl (%rdx), %edx
movl $0xff, %esi
xorl %esi, %edx
imull %eax, %edx
imull $0x8081, %edx, %r8d     # imm = 0x8081
shrl $0x17, %r8d
movb %r8b, 0x10(%rbx)
movq 0x28(%rsp), %rax
movzbl 0x10(%rax), %edx
andl %esi, %r8d
movzbl 0x2(%rax), %r9d
decl %r9d
movzbl 0x2(%rbx), %eax
movl %eax, (%rsp)
leaq 0xad37(%rip), %rsi      # 0x10525
movl $0x4, %edi
xorl %eax, %eax
callq 0xd5b0
rolw $0x8, 0x4(%rbx)
movb 0x1(%rbx), %al
andb $-0x41, %al
shlb $0x6, %bpl
orb %al, %bpl
movb %bpl, 0x1(%rbx)
testq %r12, %r12
jne 0x583b
cmpq $0x0, 0x8(%rsp)
je 0x582c
movq %r15, %rdi
movq %r14, %rsi
movq %r13, %rdx
callq 0x5bc8
jmp 0x583b
leaq 0x11b05(%rip), %rsi     # 0x17338
movq %r13, %rdi
callq 0x5bb9
movl $0x7, %edi
addq $0x38, %rsp
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
jmp 0x689c
movq %r14, %r12
jmp 0x569f