现在的位置: 首页 > 综合 > 正文

ns2mac层理解

2013年07月17日 ⁄ 综合 ⁄ 共 7094字 ⁄ 字号 评论关闭

http://www.joshuarobinson.net/docs/802_11.html  这个是原稿。

 

http://hi.baidu.com/ynp130y/blog/item/b205811411db3415962b4316.html

 

下面是经过别人解读的:

mac-802_11.h:
// frame control field:
struct frame_control {
u_char        fc_subtype        : 4;
u_char        fc_type            : 2;   //frame type : RTS, CTS, ACK, data
u_char        fc_protocol_version    : 2;

u_char        fc_order        : 1;
u_char        fc_wep            : 1;
u_char        fc_more_data        : 1;
u_char        fc_pwr_mgt        : 1;
u_char        fc_retry        : 1;
u_char        fc_more_frag        : 1;
u_char        fc_from_ds        : 1;
u_char        fc_to_ds        : 1;
};

// frame field:
struct hdr_mac802_11 {
struct frame_control    dh_fc;
//duration of reserved transmission time (RTS/CTS)
u_int16_t        dh_duration;
//address 1: MAC address of wireless host or AP to receive this frame
u_char            dh_ra[ETHER_ADDR_LEN];
//MAC address of wireless host or AP transmitting this frame
u_char            dh_ta[ETHER_ADDR_LEN];
//MAC address of router interface to which AP is attached
u_char            dh_3a[ETHER_ADDR_LEN];
//used only in ad hoc mode
u_char            dh_4a[ETHER_ADDR_LEN];
u_int16_t        dh_scontrol;
u_char            dh_body[1]; // size of 1 for ANSI compatibility
};

发送包:
recv()-->send()-->sendDATA() and sendRTS()-->start defer timer-->deferHandler()-->check_pktRTS()-->transmit()-->recv()-->recieve timer started-->recv_timer()-->recvCTS()-->tx_resume()-->start defer timer-->rx_resume()-->deferHandler()-->check_pktTx()-->transmit()-->recv()-->recieve timer started-->recv_timer()-->recvACK()-->tx_resume()-->callback_-->rx_resume()

  • recv()(down)--要发送的数据包先被recv()处理,recv()先检查包头方向字段,如果是down,意味着包来自上层,数据包将转由send()处理。不管接收包来自上层或下层,recv()总被调用。
  • send()-- 首先检查能量模式,如果在睡眠模式则丢弃包,并随包设callback_ 给handler(?),这是包传送完毕后会调用handler的原因。

    • 下一步,send()调用sendDATA()and sendRTS建立数据包包头,RTS包存储在pktTx_ and pktRTS_并随数据包发送。数据包的MAC头赋唯一序列值。
    • MAC用 is_idle()检查backoff timer,如果backoff timer不减少,则检查信道(medium)是否空闲,如果空闲则启动defer.
      • DIFS+a randomly chosen amount of time in the interval [0,cw_), cw_当前竞争窗口。
      • 如果节点正在等待其defer time,则继续等待。
      • 如果介质忙,节点启动其backoff timer.
    • 此时,send()结束,控制将在timer expired 后调用deferHandler() 或backoffHandler().

//部分send()代码:
// 若是目前backoff timer并没有在 count down
if(mhBackoff_.busy() == 0) {
// 此时channel又是idle
if(is_idle()) {
// 若是节点已经再等待defer timer,则让defer timer继续,因此不做任何的设定.但是若没有defer timer,就要根据802.11的规定,需要再等待一个DIFS和一个random time才能做资料的传送,而这个random time是由[0, cw_]所决定的
if (mhDefer_.busy() == 0) {
rTime = (Random::random() % cw_)*(phymib_.getSlotTime());
mhDefer_.start(phymib_.getDIFS() + rTime);
}
/* 此时channel若是busy */
else {
mhBackoff_.start(cw_, is_idle());
}
}
}

  • sendDATA()--为数据包建立MAC头.存储由txtime()算出的包的txtime(size_of_packet * rate),duration等等。MAC包头建立后数据包存储在缓存里准备传送。此时代码回到send().

//sendDATA():
void Mac802_11::sendDATA(Packet *p)
{
hdr_cmn* ch = HDR_CMN(p);
struct hdr_mac802_11* dh = HDR_MAC802_11(p);

// 更新packet的长度,把packet的长度加上PreambleLength (内定值为144 bits), PLCPHeaderLength(内定值为48bits), Mac Header Length和ETHER_FCS_LEN
ch->size() += phymib_.getHdrLen11();
// 填入Mac Header中frame control内的子栏位值
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;
// 记录传送所需要花的时间,计算的方式(PreambleLength +PLCPHeaderLength) * 8 / PLCPDataRate + 剩于的封包长度(单位为bytes) * 8 / dataRate_
//算了两次,第一次没有必要。因为如果数据包恰巧是广播包,会对data rate使用不同的值。
ch->txtime() = txtime(ch->size(), dataRate_);
// 若是这是一个unicast的封包
if  ((u_int32_t)ETHER_ADDR(dh->dh_ra) != MAC_BROADCAST) {
//如果不是广播包,再次计算传送所需要花的时间txtime
ch->txtime() = txtime(ch->size(), dataRate_);
//duration的意思是送出去此data packet之后,此次的通讯还需要占用channel所需要的时间,这个时间的长度为传送一个ACK和一个SIF的时间。
dh->dh_duration = usec(txtime(phymib_.getACKlen(), basicRate_)+ phymib_.getSIFS());
} else {
// 若这是一个multicast的封包
ch->txtime() = txtime(ch->size(), basicRate_);
// 若是multicast packet,送出去此data packet之后,就算传送完成,不需要再等待ACK,因此duration为0
dh->dh_duration = 0;
}
//当Mac Header中的资讯都填完后,最终赋值给中间变量pktTx_以指向所建的包。把要传送的包存储在Mac Layer中的local buffer,等待适当的时机再传送出去。
pktTx_ = p;
}

  • sendRTS()--生成一个特定目的地的RTS包.

//sendRTS:
void Mac802_11::sendRTS(int dst)
{//首先生成一个新RTS包
Packet *p = Packet::alloc();
hdr_cmn* ch = HDR_CMN(p);
struct rts_frame *rf = (struct rts_frame*)p->access(hdr_mac:offset_);
// 检查要传送的封包大小是否是小于RTSThreshold或是不是一个broadcast的封包,若是,则不需要传送RTS.返回send(). 如果在使用者所写的 tcl中没有指定RTSThreshold,则ns2会去读取ns-default.tcl的值,内定为0,因此若是使用unicast,则一定会送出去 RTS。
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);
//设定RTS packet中Mac Header的字段
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;
// 把目的位址存放到RA(由函数的参数得到)
STORE4BYTE(&dst, (rf->rf_ra));
// 存放传送RTS所需要花的时间, RTS Frame是用basicRate_传送
ch->txtime() = txtime(ch->size(), basicRate_);
// 把传送端的位址放到TA
STORE4BYTE(&index_, (rf->rf_ta));
// 计算duration,计算的公式为: SIF + T(CTS) + SIF + T(Pkt) + SIF + T(ACK)
rf->rf_duration = usec(phymib_.getSIFS()
+ txtime(phymib_.getCTSlen(), basicRate_)
+ phymib_.getSIFS()
+ txtime(pktTx_)
+ phymib_.getSIFS()
+ txtime(phymib_.getACKlen(), basicRate_));
//把建立好的RTS packet先暂时存放到pktRTS_
pktRTS_ = p;
}

  • deferHandler()-- 当defer time到期时此函数被调用。此时节点为避免冲突已经等待足够的时间并准备传送。首先确认是否有a control,RTS或数据包等待传送。然后调用check_pktCTL()??以确认backoff timer不正在运行。随后调用check_pktRTS()和check_pktTx().如果那些函数的返回值为0,既发送成功,则程序终止。因此, 实际包的发送由那些check_function处理.在这一点,包的传送开始于某种类型的包,而控制在接口计数器到期时返回 (tx_Handler(),清零?标志 tx_active_以显示phy空闲)。如果以下另一个包由recv()接收,控制会返回:

    •  

      • a CTS且RTS刚被发送
      • a data packet且CTS刚被发送
      • an ACK且data packet刚被发送
      • 或send timer,sendHandler()到期,会立即调用send_timer()
  • check_pktCTRL()-- 用以发送被pktCTRL_指向的CTS和ACK包。首先检查这个指针是否指向。如果没有,返回-1,表示没有数据传送。(如果传送状态 tx_state_显示MAC正在传送a CTS or ACK包,函数也会返回??)然后函数将决定发送控制包的类型:
    • 如果是CTS, MAC将检查媒介占用的状态是否为 is_idle().

      • 如果信道忙,抛弃CTS包并置pktCTRL_为零
      • 如果信道闲,函数利用宏设置tx_state_ 以显示MAC正在传送一个CTS,并调用checkBackoffTimer().随后计算超时时间值(timeout value)--即MAC确认传送失败的等待时间值。
    • 如果是ACK,MAC不检查媒介占用,其他处理同上。
    • 最后调用transmi()( with pktCTRL_ and timeout value),此时phy开始传送控制包。
  • check_pktRTS()--用于发送RTS包。如果没有RTS包要发送,pktRTS_为空,函数返回值为-1。发送前检查信道:
    • 如信道忙则竞争窗口cw_加倍(由inline function inc_cw()),且backoff timer重新启动。函数返回。
    • 如信道闲,则将MAC的tx_state_of设置为RTS并调用checkBackoffTimer().计算等待CTS返回的超时值(timeout)
    • 最后调用transmi()( with RTS and timeout value),此时phy开始传送RTS包。
  •  check_pktTx()--用于发送数据包。如果没有数据包要发送,pktTx为空,函数返回值为-1。

    • 如果信道忙,调用sendRTS(??好像没有用),cw_加倍,backoff timer重新启动,MAC保持空闲直到其他节点完成发送。
  • checkBackoffTimer() --This inline function performs two checks.

    • 首先,如果信道空闲,且backOffTimer未暂停,则执行timer.
  •  

    • 如果介质忙且backOffTimer正在运行(busy and not paused),则暂停timer( the MAC only counts down it's backoff timer while the channel is idle)。 As per the specs, the timer should not be running while the channel is being used by another node.

recv()(up)--如果包来自底层(网络接口),则初始检查被忽略。此时phy只收到到达包的第一位,而MAC只在收到完整包后才做处理。

  • 如果收到包时MAC正在传送其他的包,则收到包将被忽略(包头将被设置错误标志)。
  • 如果此时MAC空闲,则rx_state_ 设置成RECV并调用checkBackoffTimer. 随后,到达包赋值给pktRx_,receive timer启动( for the txtime() of the packet)
  • 如果包到达时MAC正在接收包,它会就接收功率(received power)对新包和旧包比较,

    • 如果新包的功率小于旧包的下限值,新包将被忽略,调用capture()。
    • 如果power level很相近,则冲突发生,转由collision()处理,到达包将被抛弃。
    • 初始包不会被抛弃并直至接收完毕。
    • 不管什么时候,如果receive timer到期,控制将转回MAC,调用recvHandler(),回到recv_timer().

抱歉!评论已关闭.