1 /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
2 /*
3  * Copyright (c) 2007-2009 Strasbourg University
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: Sebastien Vincent <vincent@clarinet.u-strasbg.fr>
19  */
20 
21 #include "ipv6-end-point-demux.h"
22 #include "ipv6-end-point.h"
23 #include "ns3/log.h"
24 
25 namespace ns3 {
26 
27 NS_LOG_COMPONENT_DEFINE ("Ipv6EndPointDemux");
28 
Ipv6EndPointDemux()29 Ipv6EndPointDemux::Ipv6EndPointDemux ()
30   : m_ephemeral (49152),
31     m_portFirst (49152),
32     m_portLast (65535)
33 {
34   NS_LOG_FUNCTION (this);
35 }
36 
~Ipv6EndPointDemux()37 Ipv6EndPointDemux::~Ipv6EndPointDemux ()
38 {
39   NS_LOG_FUNCTION (this);
40   for (EndPointsI i = m_endPoints.begin (); i != m_endPoints.end (); i++)
41     {
42       Ipv6EndPoint *endPoint = *i;
43       delete endPoint;
44     }
45   m_endPoints.clear ();
46 }
47 
LookupPortLocal(uint16_t port)48 bool Ipv6EndPointDemux::LookupPortLocal (uint16_t port)
49 {
50   NS_LOG_FUNCTION (this << port);
51   for (EndPointsI i = m_endPoints.begin (); i != m_endPoints.end (); i++)
52     {
53       if ((*i)->GetLocalPort  () == port)
54         {
55           return true;
56         }
57     }
58   return false;
59 }
60 
LookupLocal(Ptr<NetDevice> boundNetDevice,Ipv6Address addr,uint16_t port)61 bool Ipv6EndPointDemux::LookupLocal (Ptr<NetDevice> boundNetDevice, Ipv6Address addr, uint16_t port)
62 {
63   NS_LOG_FUNCTION (this << addr << port);
64   for (EndPointsI i = m_endPoints.begin (); i != m_endPoints.end (); i++)
65     {
66       if ((*i)->GetLocalPort () == port &&
67           (*i)->GetLocalAddress () == addr &&
68           (*i)->GetBoundNetDevice () == boundNetDevice)
69         {
70           return true;
71         }
72     }
73   return false;
74 }
75 
Allocate()76 Ipv6EndPoint* Ipv6EndPointDemux::Allocate ()
77 {
78   NS_LOG_FUNCTION (this);
79   uint16_t port = AllocateEphemeralPort ();
80   if (port == 0)
81     {
82       NS_LOG_WARN ("Ephemeral port allocation failed.");
83       return 0;
84     }
85   Ipv6EndPoint *endPoint = new Ipv6EndPoint (Ipv6Address::GetAny (), port);
86   m_endPoints.push_back (endPoint);
87   NS_LOG_DEBUG ("Now have >>" << m_endPoints.size () << "<< endpoints.");
88   return endPoint;
89 }
90 
Allocate(Ipv6Address address)91 Ipv6EndPoint* Ipv6EndPointDemux::Allocate (Ipv6Address address)
92 {
93   NS_LOG_FUNCTION (this << address);
94   uint16_t port = AllocateEphemeralPort ();
95   if (port == 0)
96     {
97       NS_LOG_WARN ("Ephemeral port allocation failed.");
98       return 0;
99     }
100   Ipv6EndPoint *endPoint = new Ipv6EndPoint (address, port);
101   m_endPoints.push_back (endPoint);
102   NS_LOG_DEBUG ("Now have >>" << m_endPoints.size () << "<< endpoints.");
103   return endPoint;
104 }
105 
Allocate(Ptr<NetDevice> boundNetDevice,uint16_t port)106 Ipv6EndPoint* Ipv6EndPointDemux::Allocate (Ptr<NetDevice> boundNetDevice, uint16_t port)
107 {
108   NS_LOG_FUNCTION (this << boundNetDevice << port);
109 
110   return Allocate (boundNetDevice, Ipv6Address::GetAny (), port);
111 }
112 
Allocate(Ptr<NetDevice> boundNetDevice,Ipv6Address address,uint16_t port)113 Ipv6EndPoint* Ipv6EndPointDemux::Allocate (Ptr<NetDevice> boundNetDevice, Ipv6Address address, uint16_t port)
114 {
115   NS_LOG_FUNCTION (this << boundNetDevice << address << port);
116   if (LookupLocal (boundNetDevice, address, port) || LookupLocal (0, address, port))
117     {
118       NS_LOG_WARN ("Duplicated endpoint.");
119       return 0;
120     }
121   Ipv6EndPoint *endPoint = new Ipv6EndPoint (address, port);
122   m_endPoints.push_back (endPoint);
123   NS_LOG_DEBUG ("Now have >>" << m_endPoints.size () << "<< endpoints.");
124   return endPoint;
125 }
126 
Allocate(Ptr<NetDevice> boundNetDevice,Ipv6Address localAddress,uint16_t localPort,Ipv6Address peerAddress,uint16_t peerPort)127 Ipv6EndPoint* Ipv6EndPointDemux::Allocate (Ptr<NetDevice> boundNetDevice,
128                                            Ipv6Address localAddress, uint16_t localPort,
129                                            Ipv6Address peerAddress, uint16_t peerPort)
130 {
131   NS_LOG_FUNCTION (this << boundNetDevice << localAddress << localPort << peerAddress << peerPort);
132   for (EndPointsI i = m_endPoints.begin (); i != m_endPoints.end (); i++)
133     {
134       if ((*i)->GetLocalPort () == localPort &&
135           (*i)->GetLocalAddress () == localAddress &&
136           (*i)->GetPeerPort () == peerPort &&
137           (*i)->GetPeerAddress () == peerAddress &&
138           ((*i)->GetBoundNetDevice () == boundNetDevice || (*i)->GetBoundNetDevice () == 0))
139         {
140           NS_LOG_WARN ("Duplicated endpoint.");
141           return 0;
142         }
143     }
144   Ipv6EndPoint *endPoint = new Ipv6EndPoint (localAddress, localPort);
145   endPoint->SetPeer (peerAddress, peerPort);
146   m_endPoints.push_back (endPoint);
147 
148   NS_LOG_DEBUG ("Now have >>" << m_endPoints.size () << "<< endpoints.");
149 
150   return endPoint;
151 }
152 
DeAllocate(Ipv6EndPoint * endPoint)153 void Ipv6EndPointDemux::DeAllocate (Ipv6EndPoint *endPoint)
154 {
155   NS_LOG_FUNCTION (this);
156   for (EndPointsI i = m_endPoints.begin (); i != m_endPoints.end (); i++)
157     {
158       if (*i == endPoint)
159         {
160           delete endPoint;
161           m_endPoints.erase (i);
162           break;
163         }
164     }
165 }
166 
167 /*
168  * If we have an exact match, we return it.
169  * Otherwise, if we find a generic match, we return it.
170  * Otherwise, we return 0.
171  */
Lookup(Ipv6Address daddr,uint16_t dport,Ipv6Address saddr,uint16_t sport,Ptr<Ipv6Interface> incomingInterface)172 Ipv6EndPointDemux::EndPoints Ipv6EndPointDemux::Lookup (Ipv6Address daddr, uint16_t dport,
173                                                         Ipv6Address saddr, uint16_t sport,
174                                                         Ptr<Ipv6Interface> incomingInterface)
175 {
176   NS_LOG_FUNCTION (this << daddr << dport << saddr << sport << incomingInterface);
177 
178   EndPoints retval1; /* Matches exact on local port, wildcards on others */
179   EndPoints retval2; /* Matches exact on local port/adder, wildcards on others */
180   EndPoints retval3; /* Matches all but local address */
181   EndPoints retval4; /* Exact match on all 4 */
182 
183   NS_LOG_DEBUG ("Looking up endpoint for destination address " << daddr);
184   for (EndPointsI i = m_endPoints.begin (); i != m_endPoints.end (); i++)
185     {
186       Ipv6EndPoint* endP = *i;
187 
188       NS_LOG_DEBUG ("Looking at endpoint dport=" << endP->GetLocalPort ()
189                                                  << " daddr=" << endP->GetLocalAddress ()
190                                                  << " sport=" << endP->GetPeerPort ()
191                                                  << " saddr=" << endP->GetPeerAddress ());
192 
193       if (!endP->IsRxEnabled ())
194         {
195           NS_LOG_LOGIC ("Skipping endpoint " << &endP
196                         << " because endpoint can not receive packets");
197           continue;
198         }
199 
200       if (endP->GetLocalPort () != dport)
201         {
202           NS_LOG_LOGIC ("Skipping endpoint " << &endP
203                                              << " because endpoint dport "
204                                              << endP->GetLocalPort ()
205                                              << " does not match packet dport " << dport);
206           continue;
207         }
208 
209       if (endP->GetBoundNetDevice ())
210         {
211           if (!incomingInterface)
212             {
213               continue;
214             }
215           if (endP->GetBoundNetDevice () != incomingInterface->GetDevice ())
216             {
217               NS_LOG_LOGIC ("Skipping endpoint " << &endP
218                                                  << " because endpoint is bound to specific device and"
219                                                  << endP->GetBoundNetDevice ()
220                                                  << " does not match packet device " << incomingInterface->GetDevice ());
221               continue;
222             }
223         }
224 
225       /*    Ipv6Address incomingInterfaceAddr = incomingInterface->GetAddress (); */
226       NS_LOG_DEBUG ("dest addr " << daddr);
227 
228       bool localAddressMatchesWildCard = endP->GetLocalAddress () == Ipv6Address::GetAny ();
229       bool localAddressMatchesExact = endP->GetLocalAddress () == daddr;
230       bool localAddressMatchesAllRouters = endP->GetLocalAddress () == Ipv6Address::GetAllRoutersMulticast ();
231 
232       /* if no match here, keep looking */
233       if (!(localAddressMatchesExact || localAddressMatchesWildCard))
234         {
235           continue;
236         }
237       bool remotePeerMatchesExact = endP->GetPeerPort () == sport;
238       bool remotePeerMatchesWildCard = endP->GetPeerPort () == 0;
239       bool remoteAddressMatchesExact = endP->GetPeerAddress () == saddr;
240       bool remoteAddressMatchesWildCard = endP->GetPeerAddress () == Ipv6Address::GetAny ();
241 
242       /* If remote does not match either with exact or wildcard,i
243          skip this one */
244       if (!(remotePeerMatchesExact || remotePeerMatchesWildCard))
245         {
246           continue;
247         }
248       if (!(remoteAddressMatchesExact || remoteAddressMatchesWildCard))
249         {
250           continue;
251         }
252 
253       /* Now figure out which return list to add this one to */
254       if (localAddressMatchesWildCard
255           && remotePeerMatchesWildCard
256           && remoteAddressMatchesWildCard)
257         { /* Only local port matches exactly */
258           retval1.push_back (endP);
259         }
260       if ((localAddressMatchesExact || (localAddressMatchesAllRouters))
261           && remotePeerMatchesWildCard
262           && remoteAddressMatchesWildCard)
263         { /* Only local port and local address matches exactly */
264           retval2.push_back (endP);
265         }
266       if (localAddressMatchesWildCard
267           && remotePeerMatchesExact
268           && remoteAddressMatchesExact)
269         { /* All but local address */
270           retval3.push_back (endP);
271         }
272       if (localAddressMatchesExact
273           && remotePeerMatchesExact
274           && remoteAddressMatchesExact)
275         { /* All 4 match */
276           retval4.push_back (endP);
277         }
278     }
279 
280   // Here we find the most exact match
281   EndPoints retval;
282   if (!retval4.empty ()) retval = retval4;
283   else if (!retval3.empty ()) retval = retval3;
284   else if (!retval2.empty ()) retval = retval2;
285   else retval = retval1;
286 
287   NS_ABORT_MSG_IF (retval.size () > 1, "Too many endpoints - perhaps you created too many sockets without binding them to different NetDevices.");
288   return retval;  // might be empty if no matches
289 }
290 
SimpleLookup(Ipv6Address dst,uint16_t dport,Ipv6Address src,uint16_t sport)291 Ipv6EndPoint* Ipv6EndPointDemux::SimpleLookup (Ipv6Address dst, uint16_t dport, Ipv6Address src, uint16_t sport)
292 {
293   uint32_t genericity = 3;
294   Ipv6EndPoint *generic = 0;
295 
296   for (EndPointsI i = m_endPoints.begin (); i != m_endPoints.end (); i++)
297     {
298       uint32_t tmp = 0;
299 
300       if ((*i)->GetLocalPort () != dport)
301         {
302           continue;
303         }
304 
305       if ((*i)->GetLocalAddress () == dst && (*i)->GetPeerPort () == sport
306           && (*i)->GetPeerAddress () == src)
307         {
308           /* this is an exact match. */
309           return *i;
310         }
311 
312       if ((*i)->GetLocalAddress () == Ipv6Address::GetAny ())
313         {
314           tmp++;
315         }
316 
317       if ((*i)->GetPeerAddress () == Ipv6Address::GetAny ())
318         {
319           tmp++;
320         }
321 
322       if (tmp < genericity)
323         {
324           generic = (*i);
325           genericity = tmp;
326         }
327     }
328   return generic;
329 }
330 
AllocateEphemeralPort()331 uint16_t Ipv6EndPointDemux::AllocateEphemeralPort ()
332 {
333   NS_LOG_FUNCTION (this);
334   uint16_t port = m_ephemeral;
335   int count = m_portLast - m_portFirst;
336   do
337     {
338       if (count-- < 0)
339         {
340           return 0;
341         }
342       ++port;
343       if (port < m_portFirst || port > m_portLast)
344         {
345           port = m_portFirst;
346         }
347     }
348   while (LookupPortLocal (port));
349   m_ephemeral = port;
350   return port;
351 }
352 
GetEndPoints() const353 Ipv6EndPointDemux::EndPoints Ipv6EndPointDemux::GetEndPoints () const
354 {
355   return m_endPoints;
356 }
357 
358 } /* namespace ns3 */
359 
360