帮我用代码写出FreeBSD分片重组算法
时间: 2024-03-03 08:49:44 浏览: 239
FreeBSD中的分片重组算法是通过IP层进行实现的。具体的代码实现如下:
首先,定义一个名为`ip_input()`的函数,该函数用于接收并处理IP分片。在该函数中,通过读取IP首部的标识符、偏移量和总长度等信息来判断该分片是否为分段数据的第一个分片,如果是,则需要创建一个新的缓存区用于存储该数据包的所有分片;如果不是,则需要将该分片添加到之前创建的缓存区中。
```
void ip_input(struct mbuf *m)
{
struct ip *ip = mtod(m, struct ip *);
int hlen = ip->ip_hl << 2;
int len = ntohs(ip->ip_len);
int off = ntohs(ip->ip_off);
if (off & IP_MF || off & IP_OFFMASK) {
// This is a fragment
// Find the original packet
struct ipq *fp = ip_findf(ip);
if (fp == NULL) {
// First fragment
fp = ip_insertq(ip);
if (fp == NULL) {
// Cache is full
ipstat.ips_fragments++;
m_freem(m);
return;
}
m_copydata(m, 0, hlen, (caddr_t)&fp->ipq_ip);
fp->ipq_hlen = hlen;
fp->ipq_flags = 0;
fp->ipq_ttl = ip->ip_ttl;
fp->ipq_p = ip->ip_p;
fp->ipq_id = ip->ip_id;
fp->ipq_nfrags = 0;
fp->ipq_next = NULL;
fp->ipq_prev = NULL;
fp->ipq_frag[0] = m;
fp->ipq_nfrags++;
if (off & IP_OFFMASK)
fp->ipq_flags |= IP_LF;
else
fp->ipq_flags |= IP_FF;
m_freem(m);
return;
} else {
// Subsequent fragment
if (ip->ip_id != fp->ipq_id ||
ip->ip_src.s_addr != fp->ipq_src.s_addr ||
ip->ip_dst.s_addr != fp->ipq_dst.s_addr ||
ip->ip_p != fp->ipq_p) {
// Bad packet
ipstat.ips_fragdropped++;
m_freem(m);
return;
}
int i = (off & IP_OFFMASK) >> 3;
if (i >= IP_MAXFRAGS) {
// Too many fragments
ipstat.ips_fragdropped++;
m_freem(m);
return;
}
if (fp->ipq_frag[i] != NULL) {
// Duplicate fragment
ipstat.ips_fragdropped++;
m_freem(m);
return;
}
fp->ipq_frag[i] = m;
fp->ipq_nfrags++;
if (off & IP_OFFMASK)
fp->ipq_flags |= IP_LF;
if (fp->ipq_nfrags == (off >> 3) + 1)
fp->ipq_flags |= IP_FF;
if (fp->ipq_flags & IP_FF) {
// All fragments received
m = fp->ipq_frag[0];
int tlen = fp->ipq_hlen + len;
for (i = 1; i < FP_MAXFRAGS; i++)
if (fp->ipq_frag[i] != NULL)
tlen += ntohs(fp->ipq_frag[i]->m_len) - sizeof(struct ip);
if (m->m_len < tlen) {
if (m->m_flags & M_EXT) {
m->m_data -= fp->ipq_hlen;
m->m_len += fp->ipq_hlen;
m->m_ext.ext_size -= fp->ipq_hlen;
} else {
m = m_pullup(m, fp->ipq_hlen);
if (m == NULL) {
ipstat.ips_fragdropped++;
ip_freef(fp);
return;
}
}
}
ipstat.ips_reassembled++;
m->m_pkthdr.len = tlen;
m->m_pkthdr.rcvif = NULL;
m->m_data += fp->ipq_hlen;
m->m_len -= fp->ipq_hlen;
ip_forward(m, 1);
ip_freef(fp);
} else {
m_freem(m);
}
}
} else {
// This is not a fragment
...
}
}
```
在上述代码中,`ip_findf()`函数用于查找之前存储的缓存区;`ip_insertq()`函数用于创建一个新的缓存区。在缓存区中,`ipq_ip`保存了该数据包的IP首部,`ipq_frag`数组保存了该数据包的所有分片。`IP_FF`和`IP_LF`分别表示该数据包的第一个分片和最后一个分片。当收到所有分片后,将会调用`ip_forward()`函数将该数据包转发至目的地。
阅读全文