A Discrete-Event Network Simulator
Home
Tutorials ▼
English
Portuguese
Docs ▼
Wiki
Manual
Models
Develop ▼
API
Bugs
API
Main Page
Related Pages
Modules
Namespaces
Classes
Files
File List
File Members
All
Classes
Namespaces
Files
Functions
Variables
Typedefs
Enumerations
Enumerator
Properties
Friends
Macros
Groups
Pages
csma-net-device.cc
Go to the documentation of this file.
1
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
2
/*
3
* Copyright (c) 2007 Emmanuelle Laprise
4
*
5
* This program is free software; you can redistribute it and/or modify
6
* it under the terms of the GNU General Public License version 2 as
7
* published by the Free Software Foundation;
8
*
9
* This program is distributed in the hope that it will be useful,
10
* but WITHOUT ANY WARRANTY; without even the implied warranty of
11
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12
* GNU General Public License for more details.
13
*
14
* You should have received a copy of the GNU General Public License
15
* along with this program; if not, write to the Free Software
16
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17
*
18
* Author: Emmanuelle Laprise <emmanuelle.laprise@bluekazoo.ca>
19
*/
20
21
#include "ns3/log.h"
22
#include "ns3/queue.h"
23
#include "ns3/simulator.h"
24
#include "ns3/ethernet-header.h"
25
#include "ns3/ethernet-trailer.h"
26
#include "ns3/llc-snap-header.h"
27
#include "ns3/error-model.h"
28
#include "ns3/enum.h"
29
#include "ns3/boolean.h"
30
#include "ns3/uinteger.h"
31
#include "ns3/pointer.h"
32
#include "ns3/trace-source-accessor.h"
33
#include "
csma-net-device.h
"
34
#include "
csma-channel.h
"
35
36
NS_LOG_COMPONENT_DEFINE
(
"CsmaNetDevice"
);
37
38
namespace
ns3 {
39
40
NS_OBJECT_ENSURE_REGISTERED
(CsmaNetDevice);
41
42
TypeId
43
CsmaNetDevice::GetTypeId
(
void
)
44
{
45
static
TypeId
tid =
TypeId
(
"ns3::CsmaNetDevice"
)
46
.
SetParent
<
NetDevice
> ()
47
.AddConstructor<CsmaNetDevice> ()
48
.AddAttribute (
"Address"
,
49
"The MAC address of this device."
,
50
Mac48AddressValue
(
Mac48Address
(
"ff:ff:ff:ff:ff:ff"
)),
51
MakeMac48AddressAccessor (&
CsmaNetDevice::m_address
),
52
MakeMac48AddressChecker ())
53
.AddAttribute (
"Mtu"
,
"The MAC-level Maximum Transmission Unit"
,
54
UintegerValue
(
DEFAULT_MTU
),
55
MakeUintegerAccessor (&
CsmaNetDevice::SetMtu
,
56
&
CsmaNetDevice::GetMtu
),
57
MakeUintegerChecker<uint16_t> ())
58
.AddAttribute (
"EncapsulationMode"
,
59
"The link-layer encapsulation type to use."
,
60
EnumValue
(
DIX
),
61
MakeEnumAccessor
(&
CsmaNetDevice::SetEncapsulationMode
),
62
MakeEnumChecker
(
DIX
,
"Dix"
,
63
LLC
,
"Llc"
))
64
.AddAttribute (
"SendEnable"
,
65
"Enable or disable the transmitter section of the device."
,
66
BooleanValue
(
true
),
67
MakeBooleanAccessor (&
CsmaNetDevice::m_sendEnable
),
68
MakeBooleanChecker ())
69
.AddAttribute (
"ReceiveEnable"
,
70
"Enable or disable the receiver section of the device."
,
71
BooleanValue
(
true
),
72
MakeBooleanAccessor (&
CsmaNetDevice::m_receiveEnable
),
73
MakeBooleanChecker ())
74
.AddAttribute (
"ReceiveErrorModel"
,
75
"The receiver error model used to simulate packet loss"
,
76
PointerValue
(),
77
MakePointerAccessor (&
CsmaNetDevice::m_receiveErrorModel
),
78
MakePointerChecker<ErrorModel> ())
79
80
//
81
// Transmit queueing discipline for the device which includes its own set
82
// of trace hooks.
83
//
84
.AddAttribute (
"TxQueue"
,
85
"A queue to use as the transmit queue in the device."
,
86
PointerValue
(),
87
MakePointerAccessor (&
CsmaNetDevice::m_queue
),
88
MakePointerChecker<Queue> ())
89
90
//
91
// Trace sources at the "top" of the net device, where packets transition
92
// to/from higher layers.
93
//
94
.AddTraceSource (
"MacTx"
,
95
"Trace source indicating a packet has arrived for transmission by this device"
,
96
MakeTraceSourceAccessor
(&
CsmaNetDevice::m_macTxTrace
))
97
.AddTraceSource (
"MacTxDrop"
,
98
"Trace source indicating a packet has been dropped by the device before transmission"
,
99
MakeTraceSourceAccessor
(&
CsmaNetDevice::m_macTxDropTrace
))
100
.AddTraceSource (
"MacPromiscRx"
,
101
"A packet has been received by this device, has been passed up from the physical layer "
102
"and is being forwarded up the local protocol stack. This is a promiscuous trace,"
,
103
MakeTraceSourceAccessor
(&
CsmaNetDevice::m_macPromiscRxTrace
))
104
.AddTraceSource (
"MacRx"
,
105
"A packet has been received by this device, has been passed up from the physical layer "
106
"and is being forwarded up the local protocol stack. This is a non-promiscuous trace,"
,
107
MakeTraceSourceAccessor
(&
CsmaNetDevice::m_macRxTrace
))
108
#if 0
109
// Not currently implemented in this device
110
.AddTraceSource (
"MacRxDrop"
,
111
"Trace source indicating a packet was received, but dropped before being forwarded up the stack"
,
112
MakeTraceSourceAccessor
(&
CsmaNetDevice::m_macRxDropTrace
))
113
#endif
114
.AddTraceSource (
"MacTxBackoff"
,
115
"Trace source indicating a packet has been delayed by the CSMA backoff process"
,
116
MakeTraceSourceAccessor
(&
CsmaNetDevice::m_macTxBackoffTrace
))
117
//
118
// Trace souces at the "bottom" of the net device, where packets transition
119
// to/from the channel.
120
//
121
.AddTraceSource (
"PhyTxBegin"
,
122
"Trace source indicating a packet has begun transmitting over the channel"
,
123
MakeTraceSourceAccessor
(&
CsmaNetDevice::m_phyTxBeginTrace
))
124
.AddTraceSource (
"PhyTxEnd"
,
125
"Trace source indicating a packet has been completely transmitted over the channel"
,
126
MakeTraceSourceAccessor
(&
CsmaNetDevice::m_phyTxEndTrace
))
127
.AddTraceSource (
"PhyTxDrop"
,
128
"Trace source indicating a packet has been dropped by the device during transmission"
,
129
MakeTraceSourceAccessor
(&
CsmaNetDevice::m_phyTxDropTrace
))
130
#if 0
131
// Not currently implemented in this device
132
.AddTraceSource (
"PhyRxBegin"
,
133
"Trace source indicating a packet has begun being received by the device"
,
134
MakeTraceSourceAccessor
(&
CsmaNetDevice::m_phyRxBeginTrace
))
135
#endif
136
.AddTraceSource (
"PhyRxEnd"
,
137
"Trace source indicating a packet has been completely received by the device"
,
138
MakeTraceSourceAccessor
(&
CsmaNetDevice::m_phyRxEndTrace
))
139
.AddTraceSource (
"PhyRxDrop"
,
140
"Trace source indicating a packet has been dropped by the device during reception"
,
141
MakeTraceSourceAccessor
(&
CsmaNetDevice::m_phyRxDropTrace
))
142
//
143
// Trace sources designed to simulate a packet sniffer facility (tcpdump).
144
//
145
.AddTraceSource (
"Sniffer"
,
146
"Trace source simulating a non-promiscuous packet sniffer attached to the device"
,
147
MakeTraceSourceAccessor
(&
CsmaNetDevice::m_snifferTrace
))
148
.AddTraceSource (
"PromiscSniffer"
,
149
"Trace source simulating a promiscuous packet sniffer attached to the device"
,
150
MakeTraceSourceAccessor
(&
CsmaNetDevice::m_promiscSnifferTrace
))
151
;
152
return
tid;
153
}
154
155
CsmaNetDevice::CsmaNetDevice
()
156
: m_linkUp (false)
157
{
158
NS_LOG_FUNCTION
(
this
);
159
m_txMachineState
=
READY
;
160
m_tInterframeGap
=
Seconds
(0);
161
m_channel
= 0;
162
163
//
164
// We would like to let the attribute system take care of initializing the
165
// packet encapsulation stuff, but we also don't want to get caught up in
166
// initialization order changes. So we'll get the three problem variables
167
// into a consistent state here before the attribute calls, and then depend
168
// on the semantics of the setters to preserve a consistent state. This
169
// really doesn't have to be the same set of values as the initial values
170
// set by the attributes, but it does have to be a consistent set. That is,
171
// you can just change the default encapsulation mode above without having
172
// to change it here.
173
//
174
m_encapMode
=
DIX
;
175
}
176
177
CsmaNetDevice::~CsmaNetDevice
()
178
{
179
NS_LOG_FUNCTION_NOARGS
();
180
m_queue
= 0;
181
}
182
183
void
184
CsmaNetDevice::DoDispose
()
185
{
186
NS_LOG_FUNCTION_NOARGS
();
187
m_channel
= 0;
188
m_node
= 0;
189
NetDevice::DoDispose
();
190
}
191
192
void
193
CsmaNetDevice::SetEncapsulationMode
(
enum
EncapsulationMode
mode)
194
{
195
NS_LOG_FUNCTION
(mode);
196
197
m_encapMode
= mode;
198
199
NS_LOG_LOGIC
(
"m_encapMode = "
<<
m_encapMode
);
200
NS_LOG_LOGIC
(
"m_mtu = "
<<
m_mtu
);
201
}
202
203
CsmaNetDevice::EncapsulationMode
204
CsmaNetDevice::GetEncapsulationMode
(
void
)
205
{
206
NS_LOG_FUNCTION_NOARGS
();
207
return
m_encapMode
;
208
}
209
210
bool
211
CsmaNetDevice::SetMtu
(uint16_t mtu)
212
{
213
NS_LOG_FUNCTION
(
this
<< mtu);
214
m_mtu
= mtu;
215
216
NS_LOG_LOGIC
(
"m_encapMode = "
<<
m_encapMode
);
217
NS_LOG_LOGIC
(
"m_mtu = "
<<
m_mtu
);
218
219
return
true
;
220
}
221
222
uint16_t
223
CsmaNetDevice::GetMtu
(
void
)
const
224
{
225
NS_LOG_FUNCTION_NOARGS
();
226
return
m_mtu
;
227
}
228
229
230
void
231
CsmaNetDevice::SetSendEnable
(
bool
sendEnable)
232
{
233
NS_LOG_FUNCTION
(sendEnable);
234
m_sendEnable
= sendEnable;
235
}
236
237
void
238
CsmaNetDevice::SetReceiveEnable
(
bool
receiveEnable)
239
{
240
NS_LOG_FUNCTION
(receiveEnable);
241
m_receiveEnable
= receiveEnable;
242
}
243
244
bool
245
CsmaNetDevice::IsSendEnabled
(
void
)
246
{
247
NS_LOG_FUNCTION_NOARGS
();
248
return
m_sendEnable
;
249
}
250
251
bool
252
CsmaNetDevice::IsReceiveEnabled
(
void
)
253
{
254
NS_LOG_FUNCTION_NOARGS
();
255
return
m_receiveEnable
;
256
}
257
258
void
259
CsmaNetDevice::SetInterframeGap
(
Time
t)
260
{
261
NS_LOG_FUNCTION
(t);
262
m_tInterframeGap
= t;
263
}
264
265
void
266
CsmaNetDevice::SetBackoffParams
(
Time
slotTime, uint32_t minSlots, uint32_t maxSlots, uint32_t ceiling, uint32_t maxRetries)
267
{
268
NS_LOG_FUNCTION
(slotTime << minSlots << maxSlots << ceiling << maxRetries);
269
m_backoff
.
m_slotTime
= slotTime;
270
m_backoff
.
m_minSlots
= minSlots;
271
m_backoff
.
m_maxSlots
= maxSlots;
272
m_backoff
.
m_ceiling
= ceiling;
273
m_backoff
.
m_maxRetries
= maxRetries;
274
}
275
276
void
277
CsmaNetDevice::AddHeader
(
Ptr<Packet>
p,
Mac48Address
source,
Mac48Address
dest, uint16_t protocolNumber)
278
{
279
NS_LOG_FUNCTION
(p << source << dest << protocolNumber);
280
281
EthernetHeader
header (
false
);
282
header.
SetSource
(source);
283
header.
SetDestination
(dest);
284
285
EthernetTrailer
trailer;
286
287
NS_LOG_LOGIC
(
"p->GetSize () = "
<< p->
GetSize
());
288
NS_LOG_LOGIC
(
"m_encapMode = "
<<
m_encapMode
);
289
NS_LOG_LOGIC
(
"m_mtu = "
<<
m_mtu
);
290
291
uint16_t lengthType = 0;
292
switch
(
m_encapMode
)
293
{
294
case
DIX
:
295
NS_LOG_LOGIC
(
"Encapsulating packet as DIX (type interpretation)"
);
296
//
297
// This corresponds to the type interpretation of the lengthType field as
298
// in the old Ethernet Blue Book.
299
//
300
lengthType = protocolNumber;
301
302
//
303
// All Ethernet frames must carry a minimum payload of 46 bytes. We need
304
// to pad out if we don't have enough bytes. These must be real bytes
305
// since they will be written to pcap files and compared in regression
306
// trace files.
307
//
308
if
(p->
GetSize
() < 46)
309
{
310
uint8_t buffer[46];
311
memset (buffer, 0, 46);
312
Ptr<Packet>
padd = Create<Packet> (buffer, 46 - p->
GetSize
());
313
p->
AddAtEnd
(padd);
314
}
315
break
;
316
case
LLC
:
317
{
318
NS_LOG_LOGIC
(
"Encapsulating packet as LLC (length interpretation)"
);
319
320
LlcSnapHeader
llc;
321
llc.
SetType
(protocolNumber);
322
p->
AddHeader
(llc);
323
324
//
325
// This corresponds to the length interpretation of the lengthType
326
// field but with an LLC/SNAP header added to the payload as in
327
// IEEE 802.2
328
//
329
lengthType = p->
GetSize
();
330
331
//
332
// All Ethernet frames must carry a minimum payload of 46 bytes. The
333
// LLC SNAP header counts as part of this payload. We need to padd out
334
// if we don't have enough bytes. These must be real bytes since they
335
// will be written to pcap files and compared in regression trace files.
336
//
337
if
(p->
GetSize
() < 46)
338
{
339
uint8_t buffer[46];
340
memset (buffer, 0, 46);
341
Ptr<Packet>
padd = Create<Packet> (buffer, 46 - p->
GetSize
());
342
p->
AddAtEnd
(padd);
343
}
344
345
NS_ASSERT_MSG
(p->
GetSize
() <=
GetMtu
(),
346
"CsmaNetDevice::AddHeader(): 802.3 Length/Type field with LLC/SNAP: "
347
"length interpretation must not exceed device frame size minus overhead"
);
348
}
349
break
;
350
case
ILLEGAL
:
351
default
:
352
NS_FATAL_ERROR
(
"CsmaNetDevice::AddHeader(): Unknown packet encapsulation mode"
);
353
break
;
354
}
355
356
NS_LOG_LOGIC
(
"header.SetLengthType ("
<< lengthType <<
")"
);
357
header.
SetLengthType
(lengthType);
358
p->
AddHeader
(header);
359
360
if
(
Node::ChecksumEnabled
())
361
{
362
trailer.
EnableFcs
(
true
);
363
}
364
trailer.
CalcFcs
(p);
365
p->
AddTrailer
(trailer);
366
}
367
368
#if 0
369
bool
370
CsmaNetDevice::ProcessHeader (
Ptr<Packet>
p, uint16_t & param)
371
{
372
NS_LOG_FUNCTION
(p << param);
373
374
EthernetTrailer
trailer;
375
p->
RemoveTrailer
(trailer);
376
377
EthernetHeader
header (
false
);
378
p->
RemoveHeader
(header);
379
380
if
((header.GetDestination () !=
GetBroadcast
()) &&
381
(header.GetDestination () !=
GetAddress
()))
382
{
383
return
false
;
384
}
385
386
switch
(
m_encapMode
)
387
{
388
case
DIX
:
389
param = header.GetLengthType ();
390
break
;
391
case
LLC
:
392
{
393
LlcSnapHeader llc;
394
p->
RemoveHeader
(llc);
395
param = llc.GetType ();
396
}
397
break
;
398
case
ILLEGAL
:
399
default
:
400
NS_FATAL_ERROR
(
"CsmaNetDevice::ProcessHeader(): Unknown packet encapsulation mode"
);
401
break
;
402
}
403
return
true
;
404
}
405
#endif
406
407
void
408
CsmaNetDevice::TransmitStart
(
void
)
409
{
410
NS_LOG_FUNCTION_NOARGS
();
411
412
//
413
// This function is called to start the process of transmitting a packet. We
414
// expect that the packet to transmit will be found in m_currentPkt.
415
//
416
NS_ASSERT_MSG
(
m_currentPkt
!= 0,
"CsmaNetDevice::TransmitStart(): m_currentPkt not set"
);
417
418
NS_LOG_LOGIC
(
"m_currentPkt = "
<<
m_currentPkt
);
419
NS_LOG_LOGIC
(
"UID = "
<<
m_currentPkt
->
GetUid
());
420
421
//
422
// Only transmit if the send side of net device is enabled
423
//
424
if
(
IsSendEnabled
() ==
false
)
425
{
426
m_phyTxDropTrace
(
m_currentPkt
);
427
m_currentPkt
= 0;
428
return
;
429
}
430
431
//
432
// Somebody has called here telling us to start transmitting a packet. They
433
// can only do this if the state machine is in the READY or BACKOFF state.
434
// Specifically, if we are ready to start transmitting, we cannot already
435
// be transmitting (i.e., BUSY)
436
//
437
NS_ASSERT_MSG
((
m_txMachineState
==
READY
) || (
m_txMachineState
==
BACKOFF
),
438
"Must be READY to transmit. Tx state is: "
<<
m_txMachineState
);
439
440
//
441
// Now we have to sense the state of the medium and either start transmitting
442
// if it is idle, or backoff our transmission if someone else is on the wire.
443
//
444
if
(
m_channel
->
GetState
() !=
IDLE
)
445
{
446
//
447
// The channel is busy -- backoff and rechedule TransmitStart() unless
448
// we have exhausted all of our retries.
449
//
450
m_txMachineState
=
BACKOFF
;
451
452
if
(
m_backoff
.
MaxRetriesReached
())
453
{
454
//
455
// Too many retries, abort transmission of packet
456
//
457
TransmitAbort
();
458
}
459
else
460
{
461
m_macTxBackoffTrace
(
m_currentPkt
);
462
463
m_backoff
.
IncrNumRetries
();
464
Time
backoffTime =
m_backoff
.
GetBackoffTime
();
465
466
NS_LOG_LOGIC
(
"Channel busy, backing off for "
<< backoffTime.
GetSeconds
() <<
" sec"
);
467
468
Simulator::Schedule
(backoffTime, &
CsmaNetDevice::TransmitStart
,
this
);
469
}
470
}
471
else
472
{
473
//
474
// The channel is free, transmit the packet
475
//
476
if
(
m_channel
->
TransmitStart
(
m_currentPkt
,
m_deviceId
) ==
false
)
477
{
478
NS_LOG_WARN
(
"Channel TransmitStart returns an error"
);
479
m_phyTxDropTrace
(
m_currentPkt
);
480
m_currentPkt
= 0;
481
m_txMachineState
=
READY
;
482
}
483
else
484
{
485
//
486
// Transmission succeeded, reset the backoff time parameters and
487
// schedule a transmit complete event.
488
//
489
m_backoff
.
ResetBackoffTime
();
490
m_txMachineState
=
BUSY
;
491
m_phyTxBeginTrace
(
m_currentPkt
);
492
493
Time
tEvent =
Seconds
(
m_bps
.
CalculateTxTime
(
m_currentPkt
->
GetSize
()));
494
NS_LOG_LOGIC
(
"Schedule TransmitCompleteEvent in "
<< tEvent.
GetSeconds
() <<
"sec"
);
495
Simulator::Schedule
(tEvent, &
CsmaNetDevice::TransmitCompleteEvent
,
this
);
496
}
497
}
498
}
499
500
void
501
CsmaNetDevice::TransmitAbort
(
void
)
502
{
503
NS_LOG_FUNCTION_NOARGS
();
504
505
//
506
// When we started the process of transmitting the current packet, it was
507
// placed in m_currentPkt. So we had better find one there.
508
//
509
NS_ASSERT_MSG
(
m_currentPkt
!= 0,
"CsmaNetDevice::TransmitAbort(): m_currentPkt zero"
);
510
NS_LOG_LOGIC
(
"m_currentPkt="
<<
m_currentPkt
);
511
NS_LOG_LOGIC
(
"Pkt UID is "
<<
m_currentPkt
->
GetUid
() <<
")"
);
512
513
m_phyTxDropTrace
(
m_currentPkt
);
514
m_currentPkt
= 0;
515
516
NS_ASSERT_MSG
(
m_txMachineState
==
BACKOFF
,
"Must be in BACKOFF state to abort. Tx state is: "
<<
m_txMachineState
);
517
518
//
519
// We're done with that one, so reset the backoff algorithm and ready the
520
// transmit state machine.
521
//
522
m_backoff
.
ResetBackoffTime
();
523
m_txMachineState
=
READY
;
524
525
//
526
// If there is another packet on the input queue, we need to start trying to
527
// get that out. If the queue is empty we just wait until someone puts one
528
// in.
529
//
530
if
(
m_queue
->
IsEmpty
())
531
{
532
return
;
533
}
534
else
535
{
536
m_currentPkt
=
m_queue
->
Dequeue
();
537
NS_ASSERT_MSG
(
m_currentPkt
!= 0,
"CsmaNetDevice::TransmitAbort(): IsEmpty false but no Packet on queue?"
);
538
m_snifferTrace
(
m_currentPkt
);
539
m_promiscSnifferTrace
(
m_currentPkt
);
540
TransmitStart
();
541
}
542
}
543
544
void
545
CsmaNetDevice::TransmitCompleteEvent
(
void
)
546
{
547
NS_LOG_FUNCTION_NOARGS
();
548
549
//
550
// This function is called to finish the process of transmitting a packet.
551
// We need to tell the channel that we've stopped wiggling the wire and
552
// schedule an event that will be executed when it's time to re-enable
553
// the transmitter after the interframe gap.
554
//
555
NS_ASSERT_MSG
(
m_txMachineState
==
BUSY
,
"CsmaNetDevice::transmitCompleteEvent(): Must be BUSY if transmitting"
);
556
NS_ASSERT
(
m_channel
->
GetState
() ==
TRANSMITTING
);
557
m_txMachineState
=
GAP
;
558
559
//
560
// When we started transmitting the current packet, it was placed in
561
// m_currentPkt. So we had better find one there.
562
//
563
NS_ASSERT_MSG
(
m_currentPkt
!= 0,
"CsmaNetDevice::TransmitCompleteEvent(): m_currentPkt zero"
);
564
NS_LOG_LOGIC
(
"m_currentPkt="
<<
m_currentPkt
);
565
NS_LOG_LOGIC
(
"Pkt UID is "
<<
m_currentPkt
->
GetUid
() <<
")"
);
566
567
m_channel
->
TransmitEnd
();
568
m_phyTxEndTrace
(
m_currentPkt
);
569
m_currentPkt
= 0;
570
571
NS_LOG_LOGIC
(
"Schedule TransmitReadyEvent in "
<<
m_tInterframeGap
.
GetSeconds
() <<
"sec"
);
572
573
Simulator::Schedule
(
m_tInterframeGap
, &
CsmaNetDevice::TransmitReadyEvent
,
this
);
574
}
575
576
void
577
CsmaNetDevice::TransmitReadyEvent
(
void
)
578
{
579
NS_LOG_FUNCTION_NOARGS
();
580
581
//
582
// This function is called to enable the transmitter after the interframe
583
// gap has passed. If there are pending transmissions, we use this opportunity
584
// to start the next transmit.
585
//
586
NS_ASSERT_MSG
(
m_txMachineState
==
GAP
,
"CsmaNetDevice::TransmitReadyEvent(): Must be in interframe gap"
);
587
m_txMachineState
=
READY
;
588
589
//
590
// We expect that the packet we had been transmitting was cleared when the
591
// TransmitCompleteEvent() was executed.
592
//
593
NS_ASSERT_MSG
(
m_currentPkt
== 0,
"CsmaNetDevice::TransmitReadyEvent(): m_currentPkt nonzero"
);
594
595
//
596
// Get the next packet from the queue for transmitting
597
//
598
if
(
m_queue
->
IsEmpty
())
599
{
600
return
;
601
}
602
else
603
{
604
m_currentPkt
=
m_queue
->
Dequeue
();
605
NS_ASSERT_MSG
(
m_currentPkt
!= 0,
"CsmaNetDevice::TransmitReadyEvent(): IsEmpty false but no Packet on queue?"
);
606
m_snifferTrace
(
m_currentPkt
);
607
m_promiscSnifferTrace
(
m_currentPkt
);
608
TransmitStart
();
609
}
610
}
611
612
bool
613
CsmaNetDevice::Attach
(
Ptr<CsmaChannel>
ch)
614
{
615
NS_LOG_FUNCTION
(
this
<< &ch);
616
617
m_channel
= ch;
618
619
m_deviceId
=
m_channel
->
Attach
(
this
);
620
621
//
622
// The channel provides us with the transmitter data rate.
623
//
624
m_bps
=
m_channel
->
GetDataRate
();
625
626
//
627
// We use the Ethernet interframe gap of 96 bit times.
628
//
629
m_tInterframeGap
=
Seconds
(
m_bps
.
CalculateTxTime
(96/8));
630
631
//
632
// This device is up whenever a channel is attached to it.
633
//
634
NotifyLinkUp
();
635
return
true
;
636
}
637
638
void
639
CsmaNetDevice::SetQueue
(
Ptr<Queue>
q)
640
{
641
NS_LOG_FUNCTION
(q);
642
m_queue
= q;
643
}
644
645
void
646
CsmaNetDevice::SetReceiveErrorModel
(
Ptr<ErrorModel>
em)
647
{
648
NS_LOG_FUNCTION
(em);
649
m_receiveErrorModel
= em;
650
}
651
652
void
653
CsmaNetDevice::Receive
(
Ptr<Packet>
packet,
Ptr<CsmaNetDevice>
senderDevice)
654
{
655
NS_LOG_FUNCTION
(packet << senderDevice);
656
NS_LOG_LOGIC
(
"UID is "
<< packet->
GetUid
());
657
658
//
659
// We never forward up packets that we sent. Real devices don't do this since
660
// their receivers are disabled during send, so we don't.
661
//
662
if
(senderDevice ==
this
)
663
{
664
return
;
665
}
666
667
//
668
// Hit the trace hook. This trace will fire on all packets received from the
669
// channel except those originated by this device.
670
//
671
m_phyRxEndTrace
(packet);
672
673
//
674
// Only receive if the send side of net device is enabled
675
//
676
if
(
IsReceiveEnabled
() ==
false
)
677
{
678
m_phyRxDropTrace
(packet);
679
return
;
680
}
681
682
if
(
m_receiveErrorModel
&&
m_receiveErrorModel
->
IsCorrupt
(packet) )
683
{
684
NS_LOG_LOGIC
(
"Dropping pkt due to error model "
);
685
m_phyRxDropTrace
(packet);
686
return
;
687
}
688
689
//
690
// Trace sinks will expect complete packets, not packets without some of the
691
// headers.
692
//
693
Ptr<Packet>
originalPacket = packet->
Copy
();
694
695
EthernetTrailer
trailer;
696
packet->
RemoveTrailer
(trailer);
697
if
(
Node::ChecksumEnabled
())
698
{
699
trailer.
EnableFcs
(
true
);
700
}
701
702
trailer.
CheckFcs
(packet);
703
bool
crcGood = trailer.
CheckFcs
(packet);
704
if
(!crcGood)
705
{
706
NS_LOG_INFO
(
"CRC error on Packet "
<< packet);
707
m_phyRxDropTrace
(packet);
708
return
;
709
}
710
711
EthernetHeader
header (
false
);
712
packet->
RemoveHeader
(header);
713
714
NS_LOG_LOGIC
(
"Pkt source is "
<< header.
GetSource
());
715
NS_LOG_LOGIC
(
"Pkt destination is "
<< header.
GetDestination
());
716
717
uint16_t protocol;
718
//
719
// If the length/type is less than 1500, it corresponds to a length
720
// interpretation packet. In this case, it is an 802.3 packet and
721
// will also have an 802.2 LLC header. If greater than 1500, we
722
// find the protocol number (Ethernet type) directly.
723
//
724
if
(header.
GetLengthType
() <= 1500)
725
{
726
NS_ASSERT
(packet->
GetSize
() >= header.
GetLengthType
());
727
uint32_t padlen = packet->
GetSize
() - header.
GetLengthType
();
728
NS_ASSERT
(padlen <= 46);
729
if
(padlen > 0)
730
{
731
packet->
RemoveAtEnd
(padlen);
732
}
733
734
LlcSnapHeader
llc;
735
packet->
RemoveHeader
(llc);
736
protocol = llc.
GetType
();
737
}
738
else
739
{
740
protocol = header.
GetLengthType
();
741
}
742
743
//
744
// Classify the packet based on its destination.
745
//
746
PacketType
packetType;
747
748
if
(header.
GetDestination
().
IsBroadcast
())
749
{
750
packetType =
PACKET_BROADCAST
;
751
}
752
else
if
(header.
GetDestination
().
IsGroup
())
753
{
754
packetType =
PACKET_MULTICAST
;
755
}
756
else
if
(header.
GetDestination
() ==
m_address
)
757
{
758
packetType =
PACKET_HOST
;
759
}
760
else
761
{
762
packetType =
PACKET_OTHERHOST
;
763
}
764
765
//
766
// For all kinds of packetType we receive, we hit the promiscuous sniffer
767
// hook and pass a copy up to the promiscuous callback. Pass a copy to
768
// make sure that nobody messes with our packet.
769
//
770
m_promiscSnifferTrace
(originalPacket);
771
if
(!
m_promiscRxCallback
.
IsNull
())
772
{
773
m_macPromiscRxTrace
(originalPacket);
774
m_promiscRxCallback
(
this
, packet, protocol, header.
GetSource
(), header.
GetDestination
(), packetType);
775
}
776
777
//
778
// If this packet is not destined for some other host, it must be for us
779
// as either a broadcast, multicast or unicast. We need to hit the mac
780
// packet received trace hook and forward the packet up the stack.
781
//
782
if
(packetType !=
PACKET_OTHERHOST
)
783
{
784
m_snifferTrace
(originalPacket);
785
m_macRxTrace
(originalPacket);
786
m_rxCallback
(
this
, packet, protocol, header.
GetSource
());
787
}
788
}
789
790
Ptr<Queue>
791
CsmaNetDevice::GetQueue
(
void
)
const
792
{
793
NS_LOG_FUNCTION_NOARGS
();
794
return
m_queue
;
795
}
796
797
void
798
CsmaNetDevice::NotifyLinkUp
(
void
)
799
{
800
NS_LOG_FUNCTION_NOARGS
();
801
m_linkUp
=
true
;
802
m_linkChangeCallbacks
();
803
}
804
805
void
806
CsmaNetDevice::SetIfIndex
(
const
uint32_t index)
807
{
808
NS_LOG_FUNCTION
(index);
809
m_ifIndex
= index;
810
}
811
812
uint32_t
813
CsmaNetDevice::GetIfIndex
(
void
)
const
814
{
815
NS_LOG_FUNCTION_NOARGS
();
816
return
m_ifIndex
;
817
}
818
819
Ptr<Channel>
820
CsmaNetDevice::GetChannel
(
void
)
const
821
{
822
NS_LOG_FUNCTION_NOARGS
();
823
return
m_channel
;
824
}
825
826
void
827
CsmaNetDevice::SetAddress
(
Address
address)
828
{
829
NS_LOG_FUNCTION_NOARGS
();
830
m_address
=
Mac48Address::ConvertFrom
(address);
831
}
832
833
Address
834
CsmaNetDevice::GetAddress
(
void
)
const
835
{
836
NS_LOG_FUNCTION_NOARGS
();
837
return
m_address
;
838
}
839
840
bool
841
CsmaNetDevice::IsLinkUp
(
void
)
const
842
{
843
NS_LOG_FUNCTION_NOARGS
();
844
return
m_linkUp
;
845
}
846
847
void
848
CsmaNetDevice::AddLinkChangeCallback
(
Callback<void>
callback)
849
{
850
NS_LOG_FUNCTION
(&callback);
851
m_linkChangeCallbacks
.
ConnectWithoutContext
(callback);
852
}
853
854
bool
855
CsmaNetDevice::IsBroadcast
(
void
)
const
856
{
857
NS_LOG_FUNCTION_NOARGS
();
858
return
true
;
859
}
860
861
Address
862
CsmaNetDevice::GetBroadcast
(
void
)
const
863
{
864
NS_LOG_FUNCTION_NOARGS
();
865
return
Mac48Address
(
"ff:ff:ff:ff:ff:ff"
);
866
}
867
868
bool
869
CsmaNetDevice::IsMulticast
(
void
)
const
870
{
871
NS_LOG_FUNCTION_NOARGS
();
872
return
true
;
873
}
874
875
Address
876
CsmaNetDevice::GetMulticast
(
Ipv4Address
multicastGroup)
const
877
{
878
NS_LOG_FUNCTION
(multicastGroup);
879
880
Mac48Address
ad =
Mac48Address::GetMulticast
(multicastGroup);
881
882
//
883
// Implicit conversion (operator Address ()) is defined for Mac48Address, so
884
// use it by just returning the EUI-48 address which is automagically converted
885
// to an Address.
886
//
887
NS_LOG_LOGIC
(
"multicast address is "
<< ad);
888
889
return
ad;
890
}
891
892
bool
893
CsmaNetDevice::IsPointToPoint
(
void
)
const
894
{
895
NS_LOG_FUNCTION_NOARGS
();
896
return
false
;
897
}
898
899
bool
900
CsmaNetDevice::IsBridge
(
void
)
const
901
{
902
NS_LOG_FUNCTION_NOARGS
();
903
return
false
;
904
}
905
906
bool
907
CsmaNetDevice::Send
(
Ptr<Packet>
packet,
const
Address
& dest, uint16_t protocolNumber)
908
{
909
NS_LOG_FUNCTION
(packet << dest << protocolNumber);
910
return
SendFrom
(packet,
m_address
, dest, protocolNumber);
911
}
912
913
bool
914
CsmaNetDevice::SendFrom
(
Ptr<Packet>
packet,
const
Address
& src,
const
Address
& dest, uint16_t protocolNumber)
915
{
916
NS_LOG_FUNCTION
(packet << src << dest << protocolNumber);
917
NS_LOG_LOGIC
(
"packet ="
<< packet);
918
NS_LOG_LOGIC
(
"UID is "
<< packet->
GetUid
() <<
")"
);
919
920
NS_ASSERT
(
IsLinkUp
());
921
922
//
923
// Only transmit if send side of net device is enabled
924
//
925
if
(
IsSendEnabled
() ==
false
)
926
{
927
m_macTxDropTrace
(packet);
928
return
false
;
929
}
930
931
Mac48Address
destination =
Mac48Address::ConvertFrom
(dest);
932
Mac48Address
source =
Mac48Address::ConvertFrom
(src);
933
AddHeader
(packet, source, destination, protocolNumber);
934
935
m_macTxTrace
(packet);
936
937
//
938
// Place the packet to be sent on the send queue. Note that the
939
// queue may fire a drop trace, but we will too.
940
//
941
if
(
m_queue
->
Enqueue
(packet) ==
false
)
942
{
943
m_macTxDropTrace
(packet);
944
return
false
;
945
}
946
947
//
948
// If the device is idle, we need to start a transmission. Otherwise,
949
// the transmission will be started when the current packet finished
950
// transmission (see TransmitCompleteEvent)
951
//
952
if
(
m_txMachineState
==
READY
)
953
{
954
if
(
m_queue
->
IsEmpty
() ==
false
)
955
{
956
m_currentPkt
=
m_queue
->
Dequeue
();
957
NS_ASSERT_MSG
(
m_currentPkt
!= 0,
"CsmaNetDevice::SendFrom(): IsEmpty false but no Packet on queue?"
);
958
m_promiscSnifferTrace
(
m_currentPkt
);
959
m_snifferTrace
(
m_currentPkt
);
960
TransmitStart
();
961
}
962
}
963
return
true
;
964
}
965
966
Ptr<Node>
967
CsmaNetDevice::GetNode
(
void
)
const
968
{
969
NS_LOG_FUNCTION_NOARGS
();
970
return
m_node
;
971
}
972
973
void
974
CsmaNetDevice::SetNode
(
Ptr<Node>
node)
975
{
976
NS_LOG_FUNCTION
(node);
977
978
m_node
= node;
979
}
980
981
bool
982
CsmaNetDevice::NeedsArp
(
void
)
const
983
{
984
NS_LOG_FUNCTION_NOARGS
();
985
return
true
;
986
}
987
988
void
989
CsmaNetDevice::SetReceiveCallback
(
NetDevice::ReceiveCallback
cb)
990
{
991
NS_LOG_FUNCTION
(&cb);
992
m_rxCallback
= cb;
993
}
994
995
Address
CsmaNetDevice::GetMulticast
(
Ipv6Address
addr)
const
996
{
997
Mac48Address
ad =
Mac48Address::GetMulticast
(addr);
998
999
NS_LOG_LOGIC
(
"MAC IPv6 multicast address is "
<< ad);
1000
return
ad;
1001
}
1002
1003
void
1004
CsmaNetDevice::SetPromiscReceiveCallback
(
NetDevice::PromiscReceiveCallback
cb)
1005
{
1006
NS_LOG_FUNCTION
(&cb);
1007
m_promiscRxCallback
= cb;
1008
}
1009
1010
bool
1011
CsmaNetDevice::SupportsSendFrom
()
const
1012
{
1013
NS_LOG_FUNCTION_NOARGS
();
1014
return
true
;
1015
}
1016
1017
int64_t
1018
CsmaNetDevice::AssignStreams
(int64_t stream)
1019
{
1020
return
m_backoff
.
AssignStreams
(stream);
1021
}
1022
1023
}
// namespace ns3
src
csma
model
csma-net-device.cc
Generated on Tue Oct 9 2012 16:45:36 for ns-3 by
1.8.1.2