📄 serial_tun.c
字号:
len -= sizeof(*dispatch);
/* Hops Left */
if ((*dispatch & 0x0F) == 0) {
goto discard_packet;
}
/* Final Destination Address */
if (*dispatch & DISPATCH_MESH_F_FLAG) {
hw_dst_addr.type = HW_ADDR_LONG;
memcpy(&hw_dst_addr.addr_long, buf,
sizeof(hw_dst_addr.addr_long));
buf += sizeof(hw_dst_addr.addr_long);
len -= sizeof(hw_dst_addr.addr_long);
} else {
hw_dst_addr.type = HW_ADDR_SHORT;
memcpy(&hw_dst_addr.addr_short, buf,
sizeof(hw_dst_addr.addr_short));
buf += sizeof(hw_dst_addr.addr_short);
len -= sizeof(hw_dst_addr.addr_short);
}
/* check if we're the recipient */
if (cmp_hw_addr(&hw_dst_addr, &hw_addr) != 0
&& !hw_addr_is_broadcat(&hw_dst_addr)) {
// TODO: if mesh forwarding enabled, then forward
goto discard_packet;
}
/* Originator Address */
if (*dispatch & DISPATCH_MESH_O_FLAG) {
hw_src_addr.type = HW_ADDR_LONG;
memcpy(&hw_src_addr.addr_long, buf,
sizeof(hw_src_addr.addr_long));
buf += sizeof(hw_src_addr.addr_long);
len -= sizeof(hw_src_addr.addr_long);
} else {
hw_src_addr.type = HW_ADDR_SHORT;
memcpy(&hw_src_addr.addr_short, buf,
sizeof(hw_src_addr.addr_short));
buf += sizeof(hw_src_addr.addr_short);
len -= sizeof(hw_src_addr.addr_short);
}
dispatch = buf;
}
/* Broadcast header */
if (*dispatch == DISPATCH_BC0) {
bc_hdr = (struct lowpan_broadcast_hdr *) buf;
// do something usefull with bc_hdr->seq_no...
buf += (sizeof(struct lowpan_broadcast_hdr));
len -= (sizeof(struct lowpan_broadcast_hdr));
dispatch = buf;
}
/* fragment header */
if ((*dispatch & DISPATCH_FRAG_MASK)
== DISPATCH_FIRST_FRAG
|| (*dispatch & DISPATCH_FRAG_MASK)
== DISPATCH_SUBSEQ_FRAG
) {
frag_hdr = (struct lowpan_frag_hdr *) buf;
buf += sizeof(struct lowpan_frag_hdr);
len -= sizeof(struct lowpan_frag_hdr);
/* collect information about the fragment */
dgram_tag = frag_hdr->dgram_tag;
dgram_size = frag_hdr->dgram_size & htons(0x07FF);
//dgram_size = frag_hdr->dgram_size8[1];
//dgram_size += ((uint16_t) (frag_hdr->dgram_size8[0] & 0x07)) << 8;
if ((*dispatch & DISPATCH_FRAG_MASK) == DISPATCH_SUBSEQ_FRAG) {
dgram_offset = *buf;
buf += 1;
len -= 1;
} else {
dgram_offset = 0;
}
debug("fragment reassembly: tag: 0x%04X, size: %d, offset: %d"\
"(*8=%d)\n",
ntohs(dgram_tag), ntohs(dgram_size),
dgram_offset, dgram_offset*8);
pkt = find_fragment(&hw_src_addr, &hw_dst_addr,
dgram_size, dgram_tag);
if (pkt) {
debug("found an existing reassembly buffer\n");
/* fragment reassembly buffer found */
/* check for overlap */
for (p = pkt->frag_list; p; p=p->next) {
if (dgram_offset == p->offset && len == p->len) {
/* duplicate - discard it */
result = 0;
goto discard_packet;
} else if ((dgram_offset == p->offset && len < p->len) ||
(dgram_offset > p->offset
&& dgram_offset < p->offset + p->len/8)
) {
goto frag_overlap;
}
}
/* no overlap found */
goto frag_reassemble;
} else {
debug("starting a new reassembly buffer\n");
/* fragment reassembly buffer not found - set up a new one */
pkt = malloc(sizeof(lowpan_pkt_t));
if (!pkt) {
// no free slot for reassembling fragments
fprintf(stderr, "out of memory - dropping a fragment\n");
result = -1;
goto discard_packet;
}
pkt->next = fragments;
fragments = pkt;
clear_pkt(pkt);
memcpy(&pkt->hw_src_addr, &hw_src_addr, sizeof(hw_src_addr));
memcpy(&pkt->hw_dst_addr, &hw_dst_addr, sizeof(hw_dst_addr));
pkt->dgram_tag = dgram_tag;
pkt->dgram_size = dgram_size;
gettimeofday(&tv, NULL);
pkt->frag_timeout = tv.tv_sec + FRAG_TIMEOUT;
goto frag_reassemble;
}
frag_overlap:
/* overlap - discard previous frags
* and restart freagment reassembly
*/
free_frag_list(pkt->frag_list);
pkt->frag_list = NULL;
/* not sure if we want to clear the whole buf */
//memset(&pkt->buf, 0, sizeof(pkt->buf));
gettimeofday(&tv, NULL);
pkt->frag_timeout = tv.tv_sec + FRAG_TIMEOUT;
goto frag_reassemble;
frag_reassemble:
/* copy buf data */
debug("dgram_offset: %d\n", dgram_offset);
memcpy(pkt->buf_begin + dgram_offset*8, buf, len);
//TODO: make sure a large len does not cause a buffer overflow
/* update frag_info */
p = malloc(sizeof(frag_info_t));
if (!p) {
fprintf(stderr, "out of memory - fragment "\
"reassembly failing\n");
} else {
p->offset = dgram_offset;
p->len = len;
/* insert frag_info into the orderer list */
if (pkt->frag_list) {
for(q = &(pkt->frag_list); (*q)->next; q=&((*q)->next)) {
if (p->offset > (*q)->offset) {
break;
}
}
if ((*q)) {
debug("inserting frag_info before offset %d\n",
(*q)->offset);
} else {
debug("inserting frag_info at the beginning/end\n");
}
p->next = *q;
*q = p;
} else {
debug("inserting frag_info to the beginning "
"of the list\n");
p->next = pkt->frag_list;
pkt->frag_list = p;
}
}
/* check if this is not the last fragment */
if (!dgram_offset) {
/* the first fragment cannot be the last one */
last_frag = 0;
} else {
debug("checking last_frag...\n");
last_frag=1;
dgram_offset = ntohs(dgram_size)/8;
for(p=pkt->frag_list; p && dgram_offset; p=p->next) {
debug("dgram_offset: %d, p->offset: %d, p->len: %d\n",
dgram_offset, p->offset, p->len);
if (p->offset + p->len/8 != dgram_offset) {
debug("offset mismatch - not the last fragment\n");
last_frag = 0;
break;
}
dgram_offset = p->offset;
}
}
if (last_frag) {
debug("last fragment, reassembly done\n");
pkt->len = ntohs(dgram_size);
debug("dumping reassembled datagram...\n");
dump_serial_packet(pkt->buf_begin, pkt->len);
/* pass up the complete packet */
result = serial_input_layer3(pkt->buf_begin, pkt->len,
&hw_src_addr, &hw_dst_addr);
/* deallocate pkt and all fragment info */
free_lowpan_pkt(pkt);
} else {
result = 0;
}
} else { /* no fragment header present */
result = serial_input_layer3(buf, len,
&hw_src_addr, &hw_dst_addr);
}
} else {
//printf("no data on serial port, but FD trigerred select\n");
}
discard_packet:
if (ser_data) {
free(ser_data);
}
if (ser_data && ser_len > 0) {
return 1;
} else {
return 0;
}
//return result;
}
int serial_input_layer3(uint8_t *buf, int len,
const hw_addr_t *hw_src_addr,
const hw_addr_t *hw_dst_addr)
{
uint8_t *dispatch = buf;
//debug("%s()\n", __func__);
//dump_serial_packet(buf, len);
if (len <= 0) return 1;
/* uncompressed IPv6 */
if (*dispatch == 0x41) {
return serial_input_ipv6_uncompressed(buf+1, len-1,
hw_src_addr, hw_dst_addr);
}
/* LOWPAN_HC1 compressed IPv6 */
else if (*dispatch == 0x42) {
return serial_input_ipv6_compressed(buf+1, len-1,
hw_src_addr, hw_dst_addr);
}
/* unknown dispatch value if we got here */
else {
debug("unknown dispatch value: %X\n", *dispatch);
return tun_write(tun_fd, (char*) buf+1, len-1);
}
}
int serial_input_ipv6_uncompressed(uint8_t *buf, int len,
const hw_addr_t *hw_src_addr,
const hw_addr_t *hw_dst_addr)
{
debug("%s()\n", __func__);
//dump_serial_packet(buf, len);
// TODO: update neighbor table
return tun_write(tun_fd, (char*) buf, len);
}
int serial_input_ipv6_compressed(uint8_t *buf, int len,
const hw_addr_t *hw_src_addr,
const hw_addr_t *hw_dst_addr)
{
int ret=0;
int new_len;
uint8_t *new_buf;
debug("%s()\n", __func__);
if (0 == lowpan_decompress(buf, len,
hw_src_addr, hw_dst_addr,
&new_buf, &new_len)
) {
// TODO: update neighbor table
buf = new_buf;
len = new_len;
ret = tun_write(tun_fd, (char*) buf, len);
if (new_buf && new_len) {
free(new_buf);
}
}
return ret;
}
/* ------------------------------------------------------------------------- */
void timer_fired()
{
struct timeval tv;
lowpan_pkt_t *p;
lowpan_pkt_t **q;
/* time out old fragments */
(void) gettimeofday(&tv, NULL);
for(q = &fragments; *q; ) {
if ((*q)->frag_timeout > tv.tv_sec) {
p = (*q)->next;
free(*q);
*q = p;
} else {
q = &((*q)->next);
}
}
// TODO: ND retransmission
// TODO: neighbor table timeouts
}
/* shifts data between the serial port and the tun interface */
int serial_tunnel(serial_source ser_src, int tun_fd) {
//int result;
fd_set fs;
while (1) {
FD_ZERO (&fs);
FD_SET (tun_fd, &fs);
FD_SET (serial_source_fd(ser_src), &fs);
select (tun_fd>serial_source_fd(ser_src)?
tun_fd+1 : serial_source_fd(ser_src)+1,
&fs, NULL, NULL, NULL);
debug("--- select() fired ---\n");
/* data available on tunnel device */
if (FD_ISSET (tun_fd, &fs)) {
//result = tun_input();
while( tun_input() );
}
/* data available on serial port */
if (FD_ISSET (serial_source_fd(ser_src), &fs)) {
/* more packets may be queued so process them all */
while (serial_input());
/* using serial_source_empty() seems to make select()
* fire way too often, so the above solution is better */
//while(! serial_source_empty(ser_src)) {
//result = serial_input();
//}
}
/* end of data available */
}
/* end of while(1) */
return 0;
}
int main(int argc, char **argv) {
char dev[16];
if (argc != 3)
{
fprintf(stderr, "Usage: %s <device> <rate>\n", argv[0]);
exit(2);
}
hw_addr.type = HW_ADDR_SHORT;
hw_addr.addr_short[0] = 0x00; // network byte order
hw_addr.addr_short[1] = 0x12;
/* create the tunnel device */
dev[0] = 0;
tun_fd = tun_open(dev);
if (tun_fd < 1) {
printf("Could not create tunnel device. Fatal.\n");
return 1;
}
else {
printf("Created tunnel device: %s\n", dev);
}
/* open the serial port */
ser_src = open_serial_source(argv[1], platform_baud_rate(argv[2]),
1, stderr_msg);
/* 0 - blocking reads
* 1 - non-blocking reads
*/
if (!ser_src) {
debug("Couldn't open serial port at %s:%s\n",
argv[1], argv[2]);
exit(1);
}
/* set up the tun interface */
printf("\n");
ssystem("ifconfig tun0 up");
ssystem("ifconfig tun0 mtu 1280");
ssystem("ifconfig tun0 inet6 add 2001:0638:0709:1234::fffe:12/64");
ssystem("ifconfig tun0 inet6 add fe80::fffe:12/64");
printf("\n");
printf("try:\n\tsudo ping6 -s 0 2001:0638:0709:1234::fffe:14\n"
"\tnc6 -u 2001:0638:0709:1234::fffe:14 1234\n\n");
/* start tunneling */
serial_tunnel(ser_src, tun_fd);
/* clean up */
close_serial_source(ser_src);
//close(ser_fd);
tun_close(tun_fd, dev);
return 0;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -