📄 snoop.c
字号:
spin_lock_irqsave(&retransmit_packet->lock, retransmit_packet->irqflags); if (retransmit_packet->num_rxmit < SNOOP_MAX_RXMIT && retransmit_packet->skb != 0){ snoop_forward (retransmit_packet->skb, retransmit_packet); if (SNOOP_DEBUG) printk("..adding timer.."); retransmit_packet->num_rxmit++; retransmit_packet->departure = jiffies; init_timer(&retransmit_packet->rexmit); retransmit_packet->rexmit.expires = jiffies + 2 * cs->rto; retransmit_packet->rexmit.function = &snoop_packet_retransmit; retransmit_packet->rexmit.data = (unsigned long) retransmit_packet; add_timer(&retransmit_packet->rexmit); } spin_unlock_irqrestore(&retransmit_packet->lock, retransmit_packet->irqflags); if (SNOOP_DEBUG) printk("..DONE.\n\n");}//============ SNOOP FORWARD - forward packet given packet pointer =========/* * This function uses the kernel symbol snoop_ip_forward_finish() to push * the buffered sk_buff into the IP stacks, so that it can be forwarded by * the kernel. Before forwarding, the buffer must be unlinked from the * sk_buff linked list maintained by the kernel. Since the buffer is * freed, after a packet is sent out on the medium, not unlinking it from * the kernel might cause the kernel to go into panic. */int snoop_forward (struct sk_buff * skb, snoop_packet_t * forward_packet){ struct sk_buff * forward; if (skb != 0){ if(snoop_ip_forward_finish && (forward = snoop_skb_clone(skb))){ skb_unlink(forward); (* snoop_ip_forward_finish) (forward); } if (SNOOP_DEBUG) printk ("done forwarding.\n"); } return SNOOPE_SUCCESS;}//============ SNOOP SAVE PACEKT - fills in the packet structure ===========/* * The snoop_save_packet(.) function receives the pointer to the packet * container (snoop_packet), the id of the connection, under which to add * the packet, and the snoop buffer, which contains the buffer and the * other information required to make the snoop buffer. If the packet is * a duplicate packet which already resides in the buffer, then the size of * the payload ofthe new packet is checked against the one in the buffer. * If the new packet contains more data than the previous, the older one is * replaced by the newer one. * * The spinlock is set down before the operation on the snoop_packet * begins. The buffer is copied using snoop_skb_copy, and the variables * int the snoop packet are set using the values in the snoop buffer. * * The timer is set using the RTO value from the connection state struct. * The spinlock is unlocked, and the function returns. */int snoop_save_packet (snoop_packet_t * save_packet, struct snoop_buffer * snb, unsigned int conn_id){ snoop_cs_t *cs = snoop_control.cstate[conn_id]; if (SNOOP_DEBUG) printk("buffering pack with seq # %u ...", snb->seq); if (save_packet->seq == snb->seq){ if (SNOOP_DEBUG) printk ("duplicate BUFF[%u][%u] PKT[%u][%u]...REPLACING", snb->seq, snb->size, save_packet->seq, save_packet->size); snoop_free_packet (save_packet); } spin_lock_irqsave(&save_packet->lock, save_packet->irqflags); save_packet->skb = snoop_skb_clone(snb->skb); save_packet->conn_id = conn_id; save_packet->seq = snb->seq; save_packet->size = snb->size; save_packet->departure = jiffies; save_packet->num_rxmit = 0;// save_packet->sock = snb->sock; init_timer(&save_packet->rexmit); save_packet->rexmit.expires = jiffies + 2 * cs->rto; save_packet->rexmit.data = (unsigned long)save_packet; save_packet->rexmit.function = &snoop_packet_retransmit; add_timer(&save_packet->rexmit); spin_unlock_irqrestore(&save_packet->lock, save_packet->irqflags); if (SNOOP_DEBUG) printk("done"); return SNOOPE_SUCCESS;}//============ SNOOP RTO CALC - estimates the rto over one hop =============/* * The fucntion is passed the pointer to the connection, the RTO of which * nees to be updated, and the time of departure of the last packet which * has just been acknowledged. * * The function calculates the RTT, and using hte formula below, it * computes the RTO, and updates the value in the connection state. */void snoop_rto_calc (snoop_cs_t * cs, unsigned long last){ if (cs->state & SNOOP_NOACK){ cs->rto = jiffies - last; cs->state &= ~SNOOP_NOACK; if (SNOOP_DEBUG) printk("- FIRST-: [%lu] ",cs->rto); } else cs->rto = (0.75*cs->rto) + (0.25 * (jiffies - last)); if (SNOOP_DEBUG) printk("-Jiff:[%lu] | last:[%lu] | RTO:[%lu]- ", jiffies, last, cs->rto); return;}//============ SNOOP ACK - handles ack packets from MH =====================/* * To determine what action to take with the newly received packet form * the Mobile Host, a series of checks are performed. If the packet does * not have the acknowledgement bit set, the function returns, and no * operation is performed on using the packet. * * If the acknowledgement sequence number is equal to the last received * acknowledgement, then local recovery is performed for the requested * packet. The packet which is being demanded by the mobile host will * be transmitted using the snoop_forward(.) function, only if the * maximum number of retransmissions has not been exceeded. The dupack * is dropped, so that it does not traverse to the Fixed host. In case * the maximum number of retransmissions has been reached, no action is * taken and the duplicate ack is propagated to the fixed host. * * If the acknowledgement sequence number is greater than the last received * acknowledgement, the acknowledgement is new, and it is used to empty the * packet buffer for that connection. snoop_clean_buff(.) is invoked to * clean the buffer using the acknowledgement sequence number. */int snoop_ack(struct snoop_buffer *snb, unsigned int conn_id){ snoop_cs_t *cs = snoop_control.cstate[conn_id]; snoop_packet_t * head_packet; int toReturn = SNOOPE_SUCCESS; if (SNOOP_DEBUG) printk("SNOOP: ==Mobile Host== ["); if (!snb->flags->ack || snb->ack_seq < cs->last_ack) { // if ack bit is not even set if (SNOOP_DEBUG) printk(" Old Acknowledgement - allow it to pass through ]\n"); toReturn = SNOOPE_SUCCESS; goto final; } if (snb->ack_seq == cs->last_ack){ // Duplicate Ack if (SNOOP_DEBUG) printk("last_ack[%u] this ack[%u]", cs->last_ack, snb->ack_seq); head_packet = cs->pkts[NEXT(cs->head)]; if (SNOOP_DEBUG) printk("-duplicate ack-"); if (cs->state & SNOOP_DUPACK){ cs->state &= ~SNOOP_DUPACK; if (head_packet->num_rxmit <= SNOOP_MAX_RXMIT){ if (SNOOP_DEBUG) printk("RETRANSMITTING."); toReturn = SNOOPE_DROP; snoop_forward (head_packet->skb, head_packet); ++head_packet->num_rxmit; } else { if (SNOOP_DEBUG) printk("FORWARDING."); } goto final; }else{ cs->state |= SNOOP_DUPACK; toReturn = SNOOPE_SUCCESS; } } if (snb->ack_seq > cs->last_ack){ // if it is a pure ack if (SNOOP_DEBUG) printk("-pure ack-"); cs->last_ack = snb->ack_seq; snoop_clean_buff(conn_id, snb->ack_seq); }final: kfree(snb->sock); kfree(snb->flags); kfree(snb); if (SNOOP_DEBUG) printk(" ]\n\n"); return toReturn;}//============ SNOOP CLEANBUF - remove acked packets =======================/* * This function clears all the packets from the buffer with the sequence * numbers less than the acknowledgement sequence number. If the buffer * is empty, the function simply returns without performing any action. * * The packets are cleared using the snoop_clean_packet() function. * If there are packets to clean, then the packet to which the * acknowledgement belongs is isolated. The departure is temporarily * stored so that when all the packets that could be cleared are free, * the snoop_rto_calc function is called to update the RTO for the * connection. * * If buffer is cleared, the snoop buffer full status us unset, so * that packts could be cached again from then on. */void snoop_clean_buff (unsigned int conn_id, unsigned int ack_seq){ snoop_cs_t *cs = snoop_control.cstate[conn_id]; int i; char flag = 0; snoop_packet_t *clean_packet; unsigned long last = 1; if (SNOOP_DEBUG) printk(" cleaning packetets acked by ack_seq %u... (", ack_seq); // If packet buffer is empty, then just return. if (NEXT(cs->head) == cs->tail && !(cs->state & SNOOP_FULL)){ if (SNOOP_DEBUG) printk(" no packets to clean ) ...done."); return; } // Empty all packets that have been acked i = cs->head; flag = 0; for (i = NEXT(cs->head); NEXT(i) != cs->head || !flag; i = NEXT(i)){ clean_packet = cs->pkts[i]; if (ack_seq < clean_packet->seq || clean_packet->seq == 0) {break;break;} last = clean_packet->departure; if (SNOOP_DEBUG) printk("- Dep: [%lu] ",last); snoop_free_packet(clean_packet); flag = 1; } // Set head to the oldest packet not acked if (flag) { snoop_rto_calc(cs, last); cs->state &= ~SNOOP_FULL; cs->head = PREV(i); if (cs->state & SNOOP_FULL) printk("**** FULL ***"); if (SNOOP_DEBUG) printk(" -head [%2d] tail [%2d]- ", cs->head, cs->tail); } if (SNOOP_DEBUG) printk(") done"); return;}//============ SNOOP FREE PACKET - empties the contents of a packet=========/* * Before the packet is operated on, the spinlock for the packet is set * down to avoid race conditions. The snoop_free_packet(.) function calls * the snoop_free_skb(.) to free the memory for the cloned sk_buff that it * had stored within it. The timers are cleared, and the variables are * initialized to zero. */void snoop_free_packet (snoop_packet_t *free_packet){ if (SNOOP_DEBUG) printk(" freeing pkt with seq: %u...", free_packet->seq); spin_lock_irqsave(&free_packet->lock, free_packet->irqflags); if (SNOOP_DEBUG) printk("=lock="); if (SNOOP_DEBUG) printk("=deltiemr="); if (free_packet->skb){ snoop_free_skb(free_packet->skb); // Clear skb if it exists free_packet->skb = 0; del_timer(&free_packet->rexmit); } // if (free_packet->sock)kfree (free_packet->sock); free_packet->conn_id = 0; free_packet->seq = 0; free_packet->size = 0; free_packet->num_rxmit = 0; free_packet->skb = 0; free_packet->sock = 0; spin_unlock_irqrestore(&free_packet->lock, free_packet->irqflags); if (SNOOP_DEBUG) printk("...done."); return;}//============ SNOOP FREE SKB - empties the skb from packet ================/* * The snoop_free_skb(.) function takes in a pointer to the sk_buff. If * the sk_buff exists, its occupied memory is freed. If the pointer is * null, the function simply returns. */void snoop_free_skb (struct sk_buff * free_skb){ if (free_skb){ kfree_skb(free_skb); // Clear skb if it exists return; } return;}//============ SNOOP CLEAN CONN - cleans connection state===================/* * The clean_conn function clears the snoop connection state once a * connction which was being handled by the snoop module terminates. This * can happen either when the connection times out, or a fin flag is read * from the packets belonging to this connection. * * All the packets belonging to that conection are cleaned, and the timer * is unset. The connection structure variables are all initialized to * zero, and the number of free connections is incremented. */void snoop_clean_conn(unsigned int conn_id){ snoop_cs_t *cs = snoop_control.cstate[conn_id]; int i; if (SNOOP_DEBUG) printk("SNOOP: Cleaning up connection [%3d]... ", conn_id); down (&cs->mutex); del_timer(&cs->timeout); cs->state = SNOOP_CLOSED; snoop_control.num_connections--; cs->last_seq = cs->last_ack = 0; cs->rto = SNOOP_RTO; // Free all packets. for (i = 0; i < SNOOP_MAXWINDOW; i++){ if (SNOOP_DEBUG) printk("\nSNOOP: packet [%3d] =", i); snoop_free_packet(cs->pkts[i]); } cs->head = 0;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -