NS2:802.11代码整个流程—packet传输的流程

来源:互联网 发布:echarts java 类库 编辑:程序博客网 时间:2024/05/22 15:32
如何传送一个封包(How to transmit a packet?)
首 先,我们要看的第一个function是在mac-802_11.cc内的recv( ),程式会先判断目前呼叫recv( )这个packet的传输方向,若是DOWN,则表示此packet是要送出去的,因此就会再呼叫send(p, h).所以接着,我们跳到send( ),此send( )首先会去检查energy model,若是目前这个node是在睡眠状态(sleep mode),则把此packet给丢弃.然后会把handler h设定给callback_.下一步,就是去呼叫sendDATA(p)和sendRTS(ETHER_ADDR(dh->dh_ra)).
底下是sendDATA的程式码. (部份英文说明和程式码,会因为长度的关系而拿掉,所以读者最好还是拿原本的程式码做对照)
void Mac802_11::sendDATA(Packet *p){
hdr_cmn* ch = HDR_CMN(p);
struct hdr_mac802_11* dh = HDR_MAC802_11(p);
ch->size() += phymib_.getHdrLen11();
dh->dh_fc.fc_protocol_version = MAC_ProtocolVersion;
dh->dh_fc.fc_type = MAC_Type_Data;
dh->dh_fc.fc_subtype = MAC_Subtype_Data;
//printf(".....p = %x, mac-subtype-%d\n",p,dh->dh_fc.fc_subtype);
dh->dh_fc.fc_to_ds = 0;
dh->dh_fc.fc_from_ds = 0;
dh->dh_fc.fc_more_frag = 0;
dh->dh_fc.fc_retry = 0;
dh->dh_fc.fc_pwr_mgt = 0;
dh->dh_fc.fc_more_data = 0;
dh->dh_fc.fc_wep = 0;
dh->dh_fc.fc_order = 0;
ch->txtime() = txtime(ch->size(), dataRate_);
if((u_int32_t)ETHER_ADDR(dh->dh_ra) != MAC_BROADCAST) {
ch->txtime() = txtime(ch->size(), dataRate_);
dh->dh_duration = usec(txtime(phymib_.getACKlen(), basicRate_)+ phymib_.getSIFS());
} else {
ch->txtime() = txtime(ch->size(), basicRate_);
dh->dh_duration = 0;
}
pktTx_ = p;
}
底下是sendRTS的程式码. (部份英文说明和程式码,会因为长度的关系而拿掉,所以读者最好还是拿原本的程式码做对照)


void Mac802_11::sendRTS(int dst){

Packet *p = Packet::alloc();
hdr_cmn* ch = HDR_CMN(p);
struct rts_frame *rf = (struct rts_frame*)p->access(hdr_mac::offset_);
if( (u_int32_t) HDR_CMN(pktTx_)->size() < macmib_.getRTSThreshold() || (u_int32_t) dst == MAC_BROADCAST) {
Packet::free(p);
return;
}
ch->uid() = 0;
ch->ptype() = PT_MAC;
ch->size() = phymib_.getRTSlen();
ch->iface() = -2;
ch->error() = 0;
bzero(rf, MAC_HDR_LEN);

rf->rf_fc.fc_protocol_version = MAC_ProtocolVersion;
rf->rf_fc.fc_type = MAC_Type_Control;
rf->rf_fc.fc_subtype = MAC_Subtype_RTS;
rf->rf_fc.fc_to_ds = 0;
rf->rf_fc.fc_from_ds = 0;
rf->rf_fc.fc_more_frag = 0;
rf->rf_fc.fc_retry = 0;
rf->rf_fc.fc_pwr_mgt = 0;
rf->rf_fc.fc_more_data = 0;
rf->rf_fc.fc_wep = 0;
rf->rf_fc.fc_order = 0;

STORE4BYTE(&dst, (rf->rf_ra));
ch->txtime() = txtime(ch->size(), basicRate_);
STORE4BYTE(&index_, (rf->rf_ta));
rf->rf_duration = usec(phymib_.getSIFS()
+ txtime(phymib_.getCTSlen(), basicRate_)
+ phymib_.getSIFS()
+ txtime(pktTx_)
+ phymib_.getSIFS()
+ txtime(phymib_.getACKlen(), basicRate_))
;
pktRTS_ = p;
}
看完sendDATA( )和sendRTS( )之后,我们再回到send( ).接着,就指定一个unique sequence number给这个data packet.为了更清处的说明,底下把剩余的程式码贴在底下.
/ * 这是在send( )内的程式码 */
if(mhBackoff_.busy() == 0) {
if(is_idle()) {
if (mhDefer_.busy() == 0) {
rTime = (Random::random() % cw_)*(phymib_.getSlotTime());
mhDefer_.start(phymib_.getDIFS() + rTime);
}
else {
mhBackoff_.start(cw_, is_idle());
}}
做完以上的事情后, send()已经完成了.
然 后,当Defer timer expires的时候,程式就会去呼叫deferHandler(),在deferHandler()中会先去呼叫check_pktCTRL(),但因 为目前pktCTRL没有资料(回传-1),所以会继续去执行check_pktRTS().若是目前channel是idle的状 态,check_pktRTS()内的程
式码就会去设定传输状态为MAC_RTC,并且计算送出RTS timeout的时间,算法为:
timeout = txtime(phymib_.getRTSlen(), basicRate_)
+ DSSS_MaxPropagationDelay // 设定为2 us,可以参考mac-802_11.h
+ phymib_.getSIFS()
+ txtime(phymib_.getCTSlen(), basicRate_)
+ DSSS_MaxPropagationDelay; // 设定为2 us,可以参考mac-802_11.h
设定完后,就会去执行transmit(pktRTS_, timeout),把RTS的packet送出去.
送 完RTS后,我们必需等待CTS,所以我们再回到recv()中的mhRecv_.start(txtime(p)),这个程式码主要是等待整个 packet完全接收后就会去呼叫recvHandler(),而recvHandler()就会再去呼叫recv_timer(),若是判断所收到的 packet是CTS,则再呼叫recvCTS(pktRx_).在recvCTS()中,因为已收到CTS,则代表RTS已传送成功,因此把 pktRTS_ = 0和ssrc_=0,然后再呼叫tx_resume().
在tx_resume()中,由于已成功的做完RTS/CTS,现在要准备送出data.这部份的程式如下所示
/ * 若是pktTx_有资料要传送 */
else if(pktTx_) {
if (mhBackoff_.busy() == 0) {
hdr_cmn *ch = HDR_CMN(pktTx_);
struct hdr_mac802_11 *mh = HDR_MAC802_11(pktTx_);

if ((u_int32_t) ch->size() < macmib_.getRTSThreshold() || (u_int32_t) ETHER_ADDR(mh->dh_ra) == MAC_BROADCAST) {
rTime = (Random::random() % cw_) * phymib_.getSlotTime();
mhDefer_.start(phymib_.getDIFS() + rTime);
} else {
mhDefer_.start(phymib_.getSIFS());
}}}
等到defer timer expires后,又会呼叫deferHandler(),而在deferHandler()又会再去呼叫check_pktTx(). check_pktTx()的程式码如下:
int Mac802_11::check_pktTx(){
struct hdr_mac802_11 *mh;
double timeout;
assert(mhBackoff_.busy() == 0);
if(pktTx_ == 0)
return -1;
mh = HDR_MAC802_11(pktTx_);
switch(mh->dh_fc.fc_subtype) {
case MAC_Subtype_Data:
if(! is_idle()) {
sendRTS(ETHER_ADDR(mh->dh_ra));
inc_cw();
mhBackoff_.start(cw_, is_idle());
return 0;
}
setTxState(MAC_SEND);
if((u_int32_t)ETHER_ADDR(mh->dh_ra) != MAC_BROADCAST)
timeout = txtime(pktTx_)
+ DSSS_MaxPropagationDelay
// 设定为2 us,可以参考mac-802_11.h
+ phymib_.getSIFS()
+ txtime(phymib_.getACKlen(), basicRate_)
+ DSSS_MaxPropagationDelay; // 设定为2 us,可以参考mac-802_11.h
else
timeout = txtime(pktTx_);
break;
default:
fprintf(stderr, "check_pktTx:Invalid MAC Control subtype\n");
exit(1);
}
transmit(pktTx_, timeout);
return 0;
}
资料送出去后,若是unicast的data packet就需要等待ACK,所以我们再回到recv()中的mhRecv_.start(txtime(p)),这个程式码主要是等待整个 packet完全接收后就会去呼叫recvHandler(),而recvHandler()就会再去呼叫recv_timer(),若是判断所收到的 packet是ACK,则会呼叫recvACK(pktRx_). 由于已成功收到ACK,则表示DATA packet已成功的送出,所以就把mhSend_.stop(),判断packet size是否有大于RTSThreshold,若是有大于的话,就把slrc_ = 0,没有的话,就把ssrc_=0.并且把pktTx_=0. 最后在结束之前,再呼叫tx_resume().而tx_resume()会呼叫callback_....然后整个DATA packet传送过程就结束了.
原创粉丝点击