blob: 5023b54d5d8657156655e12a74461429084731b3 [file] [log] [blame]
Ari Saha89831742015-06-26 10:31:48 -07001/*
2 * Copyright 2015 AT&T Foundry
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16package org.onosproject.aaa;
17
18import com.google.common.base.Strings;
Jonathan Harta46dddf2015-06-30 15:31:20 -070019import com.google.common.collect.Maps;
Ari Saha89831742015-06-26 10:31:48 -070020import org.apache.felix.scr.annotations.Activate;
21import org.apache.felix.scr.annotations.Component;
22import org.apache.felix.scr.annotations.Deactivate;
23import org.apache.felix.scr.annotations.Modified;
24import org.apache.felix.scr.annotations.Property;
25import org.apache.felix.scr.annotations.Reference;
26import org.apache.felix.scr.annotations.ReferenceCardinality;
Jonathan Harta46dddf2015-06-30 15:31:20 -070027import org.onlab.packet.DeserializationException;
28import org.onlab.packet.EAP;
29import org.onlab.packet.EAPOL;
30import org.onlab.packet.EthType;
Ari Saha89831742015-06-26 10:31:48 -070031import org.onlab.packet.Ethernet;
32import org.onlab.packet.IPv4;
33import org.onlab.packet.Ip4Address;
34import org.onlab.packet.IpAddress;
35import org.onlab.packet.MacAddress;
Jonathan Harta46dddf2015-06-30 15:31:20 -070036import org.onlab.packet.RADIUS;
37import org.onlab.packet.RADIUSAttribute;
Ari Saha89831742015-06-26 10:31:48 -070038import org.onlab.packet.UDP;
39import org.onlab.packet.VlanId;
40import org.onlab.util.Tools;
Ari Saha89831742015-06-26 10:31:48 -070041import org.onosproject.cfg.ComponentConfigService;
42import org.onosproject.core.ApplicationId;
43import org.onosproject.core.CoreService;
44import org.onosproject.net.ConnectPoint;
45import org.onosproject.net.DeviceId;
46import org.onosproject.net.Host;
47import org.onosproject.net.PortNumber;
48import org.onosproject.net.flow.DefaultTrafficSelector;
49import org.onosproject.net.flow.DefaultTrafficTreatment;
Ari Saha89831742015-06-26 10:31:48 -070050import org.onosproject.net.flow.TrafficSelector;
51import org.onosproject.net.flow.TrafficTreatment;
52import org.onosproject.net.host.HostService;
Ari Saha89831742015-06-26 10:31:48 -070053import org.onosproject.net.packet.DefaultOutboundPacket;
54import org.onosproject.net.packet.InboundPacket;
55import org.onosproject.net.packet.OutboundPacket;
56import org.onosproject.net.packet.PacketContext;
57import org.onosproject.net.packet.PacketPriority;
58import org.onosproject.net.packet.PacketProcessor;
59import org.onosproject.net.packet.PacketService;
Ari Saha89831742015-06-26 10:31:48 -070060import org.onosproject.xosintegration.VoltTenantService;
61import org.osgi.service.component.ComponentContext;
62import org.slf4j.Logger;
63
64import java.net.InetAddress;
65import java.net.UnknownHostException;
66import java.nio.ByteBuffer;
67import java.util.Collections;
68import java.util.Dictionary;
Ari Saha89831742015-06-26 10:31:48 -070069import java.util.Iterator;
70import java.util.Map;
71import java.util.Optional;
72import java.util.Set;
73
74import static org.slf4j.LoggerFactory.getLogger;
75
76
77/**
Jonathan Harta46dddf2015-06-30 15:31:20 -070078 * AAA application for ONOS.
Ari Saha89831742015-06-26 10:31:48 -070079 */
80@Component(immediate = true)
81public class AAA {
82 // a list of our dependencies :
83 // to register with ONOS as an application - described next
84 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
85 protected CoreService coreService;
86
Ari Saha89831742015-06-26 10:31:48 -070087 // to receive Packet-in events that we'll respond to
88 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
89 protected PacketService packetService;
90
Ari Saha89831742015-06-26 10:31:48 -070091 // end host information
92 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
93 protected HostService hostService;
94
95 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
96 protected VoltTenantService voltTenantService;
97
Ari Saha89831742015-06-26 10:31:48 -070098 // for verbose output
99 private final Logger log = getLogger(getClass());
100
101 // our application-specific event handler
102 private ReactivePacketProcessor processor = new ReactivePacketProcessor();
103
104 // our unique identifier
105 private ApplicationId appId;
106
107 // Map of state machines. Each state machine is represented by an
108 // unique identifier on the switch: dpid + port number
109 Map stateMachineMap = null;
110
111 // RADIUS server IP address
112 private static final String DEFAULT_RADIUS_IP = "192.168.1.10";
113 // NAS IP address
114 private static final String DEFAULT_NAS_IP = "192.168.1.11";
115 // RADIUS uplink port
116 private static final int DEFAULT_RADIUS_UPLINK = 2;
117 // RADIUS server shared secret
118 private static final String DEFAULT_RADIUS_SECRET = "ONOSecret";
Jonathan Harta46dddf2015-06-30 15:31:20 -0700119 // RADIUS MAC address
Ari Saha89831742015-06-26 10:31:48 -0700120 private static final String RADIUS_MAC_ADDRESS = "00:00:00:00:01:10";
Jonathan Harta46dddf2015-06-30 15:31:20 -0700121 // NAS MAC address
Ari Saha89831742015-06-26 10:31:48 -0700122 private static final String NAS_MAC_ADDRESS = "00:00:00:00:10:01";
Jonathan Harta46dddf2015-06-30 15:31:20 -0700123 // Radius Switch Id
Ari Saha89831742015-06-26 10:31:48 -0700124 private static final String DEFAULT_RADIUS_SWITCH = "of:5e3e486e73000187";
Jonathan Harta46dddf2015-06-30 15:31:20 -0700125 // Radius Port Number
Ari Saha89831742015-06-26 10:31:48 -0700126 private static final String DEFAULT_RADIUS_PORT = "5";
127
128 @Property(name = "radiusIpAddress", value = DEFAULT_RADIUS_IP,
129 label = "RADIUS IP Address")
130 private String radiusIpAddress = DEFAULT_RADIUS_IP;
131
132 @Property(name = "nasIpAddress", value = DEFAULT_NAS_IP,
133 label = "NAP IP Address")
134 private String nasIpAddress = DEFAULT_NAS_IP;
135
136 @Property(name = "radiusMacAddress", value = RADIUS_MAC_ADDRESS,
137 label = "RADIUS MAC Address")
138 private String radiusMacAddress = RADIUS_MAC_ADDRESS;
139
140 @Property(name = "nasMacAddress", value = NAS_MAC_ADDRESS,
141 label = "NAP MAC Address")
142 private String nasMacAddress = NAS_MAC_ADDRESS;
143
144 @Property(name = "radiusSecret", value = DEFAULT_RADIUS_SECRET,
145 label = "RADIUS shared secret")
146 private String radiusSecret = DEFAULT_RADIUS_SECRET;
147
148 @Property(name = "radiusSwitchId", value = DEFAULT_RADIUS_SWITCH,
149 label = "Radius switch")
150 private String radiusSwitch = DEFAULT_RADIUS_SWITCH;
151
152 @Property(name = "radiusPortNumber", value = DEFAULT_RADIUS_PORT,
153 label = "Radius port")
154 private String radiusPort = DEFAULT_RADIUS_PORT;
155
156 // Parsed RADIUS server IP address
157 protected InetAddress parsedRadiusIpAddress;
158
159 // Parsed NAS IP address
160 protected InetAddress parsedNasIpAddress;
161
162 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
163 protected ComponentConfigService cfgService;
164
165 @Modified
166 public void modified(ComponentContext context) {
167 Dictionary<?, ?> properties = context.getProperties();
168
169 String s = Tools.get(properties, "radiusIpAddress");
170 try {
171 parsedRadiusIpAddress = InetAddress.getByName(s);
172 radiusIpAddress = Strings.isNullOrEmpty(s) ? DEFAULT_RADIUS_IP : s;
173 } catch (UnknownHostException e) {
174 log.error("Invalid RADIUS IP address specification: {}", s);
175 }
176 try {
177 s = Tools.get(properties, "nasIpAddress");
178 parsedNasIpAddress = InetAddress.getByName(s);
179 nasIpAddress = Strings.isNullOrEmpty(s) ? DEFAULT_NAS_IP : s;
180 } catch (UnknownHostException e) {
181 log.error("Invalid NAS IP address specification: {}", s);
182 }
183
184 s = Tools.get(properties, "radiusMacAddress");
185 radiusMacAddress = Strings.isNullOrEmpty(s) ? RADIUS_MAC_ADDRESS : s;
186
187 s = Tools.get(properties, "nasMacAddress");
188 nasMacAddress = Strings.isNullOrEmpty(s) ? NAS_MAC_ADDRESS : s;
189
190 s = Tools.get(properties, "radiusSecret");
191 radiusSecret = Strings.isNullOrEmpty(s) ? DEFAULT_RADIUS_SECRET : s;
192
193 s = Tools.get(properties, "radiusSwitchId");
194 radiusSwitch = Strings.isNullOrEmpty(s) ? DEFAULT_RADIUS_SWITCH : s;
195
196 s = Tools.get(properties, "radiusPortNumber");
197 radiusPort = Strings.isNullOrEmpty(s) ? DEFAULT_RADIUS_PORT : s;
198 }
199
200 @Activate
201 public void activate(ComponentContext context) {
202 cfgService.registerProperties(getClass());
203 modified(context);
204 // "org.onosproject.aaa" is the FQDN of our app
205 appId = coreService.registerApplication("org.onosproject.aaa");
206 // register our event handler
207 packetService.addProcessor(processor, PacketProcessor.ADVISOR_MAX + 2);
208 TrafficSelector.Builder selector = DefaultTrafficSelector.builder();
209
Jonathan Harta46dddf2015-06-30 15:31:20 -0700210 selector.matchEthType(EthType.EtherType.EAPOL.ethType().toShort());
Ari Saha89831742015-06-26 10:31:48 -0700211 packetService.requestPackets(selector.build(),
212 PacketPriority.CONTROL, appId);
213
214 // Instantiate the map of the state machines
Jonathan Harta46dddf2015-06-30 15:31:20 -0700215 stateMachineMap = Collections.synchronizedMap(Maps.newHashMap());
Ari Saha89831742015-06-26 10:31:48 -0700216
217 hostService.startMonitoringIp(IpAddress.valueOf(radiusIpAddress));
218
219 }
220
221 @Deactivate
222 public void deactivate() {
223 cfgService.unregisterProperties(getClass(), false);
224 // de-register and null our handler
225 packetService.removeProcessor(processor);
226 processor = null;
227 }
228
Jonathan Harta46dddf2015-06-30 15:31:20 -0700229 /**
230 * Builds an EAPOL packet based on the given parameters.
231 *
232 * @param dstMac destination MAC address
233 * @param srcMac source MAC address
234 * @param eapolType EAPOL type
235 * @param eap EAP payload
236 * @return Ethernet frame
237 */
238 private static Ethernet buildEapolResponse(MacAddress dstMac, MacAddress srcMac,
239 short vlan, byte eapolType, EAP eap) {
240
241 Ethernet eth = new Ethernet();
242 eth.setDestinationMACAddress(dstMac.toBytes());
243 eth.setSourceMACAddress(srcMac.toBytes());
244 eth.setEtherType(EthType.EtherType.EAPOL.ethType().toShort());
245 if (vlan != Ethernet.VLAN_UNTAGGED) {
246 eth.setVlanID(vlan);
247 }
248 //eapol header
249 EAPOL eapol = new EAPOL();
250 eapol.setEapolType(eapolType);
251 eapol.setPacketLength(eap.getLength());
252
253 //eap part
254 eapol.setPayload(eap);
255
256 eth.setPayload(eapol);
257 eth.setPad(true);
258 return eth;
259 }
260
Ari Saha89831742015-06-26 10:31:48 -0700261 // our handler defined as a private inner class
262
263 /**
264 * Packet processor responsible for forwarding packets along their paths.
265 */
266 private class ReactivePacketProcessor implements PacketProcessor {
267 @Override
268 public void process(PacketContext context) {
269
270 // Extract the original Ethernet frame from the packet information
271 InboundPacket pkt = context.inPacket();
272 Ethernet ethPkt = pkt.parsed();
273 if (ethPkt == null) {
274 return;
275 }
Jonathan Harta46dddf2015-06-30 15:31:20 -0700276 // identify if incoming packet comes from supplicant (EAP) or RADIUS
277 switch (EthType.EtherType.lookup(ethPkt.getEtherType())) {
278 case EAPOL:
279 handleSupplicantPacket(context.inPacket());
Ari Saha89831742015-06-26 10:31:48 -0700280 break;
Jonathan Harta46dddf2015-06-30 15:31:20 -0700281 case IPV4:
Ari Saha89831742015-06-26 10:31:48 -0700282 IPv4 ipv4Packet = (IPv4) ethPkt.getPayload();
283 Ip4Address srcIp = Ip4Address.valueOf(ipv4Packet.getSourceAddress());
284 Ip4Address radiusIp4Address = Ip4Address.valueOf(parsedRadiusIpAddress);
285 if (srcIp.equals(radiusIp4Address) && ipv4Packet.getProtocol() == IPv4.PROTOCOL_UDP) {
286 // TODO: check for port as well when it's configurable
287 UDP udpPacket = (UDP) ipv4Packet.getPayload();
Jonathan Harta46dddf2015-06-30 15:31:20 -0700288
Ari Saha89831742015-06-26 10:31:48 -0700289 byte[] datagram = udpPacket.getPayload().serialize();
Jonathan Harta46dddf2015-06-30 15:31:20 -0700290 RADIUS radiusPacket;
291 try {
292 radiusPacket = RADIUS.deserializer().deserialize(datagram, 0, datagram.length);
293 } catch (DeserializationException e) {
294 log.warn("Unable to deserialize RADIUS packet:", e);
295 return;
296 }
Ari Saha89831742015-06-26 10:31:48 -0700297 handleRadiusPacket(radiusPacket);
298 }
299 break;
300 default:
301 return;
302 }
303 }
304
305
306 /**
Jonathan Harta46dddf2015-06-30 15:31:20 -0700307 * Handles PAE packets (supplicant).
308 *
309 * @param inPacket Ethernet packet coming from the supplicant
Ari Saha89831742015-06-26 10:31:48 -0700310 */
Jonathan Harta46dddf2015-06-30 15:31:20 -0700311 private void handleSupplicantPacket(InboundPacket inPacket) {
312 Ethernet ethPkt = inPacket.parsed();
Ari Saha89831742015-06-26 10:31:48 -0700313 // Where does it come from?
314 MacAddress srcMAC = ethPkt.getSourceMAC();
315
Jonathan Harta46dddf2015-06-30 15:31:20 -0700316 DeviceId deviceId = inPacket.receivedFrom().deviceId();
317 PortNumber portNumber = inPacket.receivedFrom().port();
Ari Saha89831742015-06-26 10:31:48 -0700318 String sessionId = deviceId.toString() + portNumber.toString();
319 StateMachine stateMachine = getStateMachine(sessionId);
Jonathan Harta46dddf2015-06-30 15:31:20 -0700320
321 EAPOL eapol = (EAPOL) ethPkt.getPayload();
Ari Saha89831742015-06-26 10:31:48 -0700322
323 switch (eapol.getEapolType()) {
324 case EAPOL.EAPOL_START:
325 try {
326 stateMachine.start();
Jonathan Harta46dddf2015-06-30 15:31:20 -0700327 stateMachine.supplicantConnectpoint = inPacket.receivedFrom();
Ari Saha89831742015-06-26 10:31:48 -0700328
329 //send an EAP Request/Identify to the supplicant
330 EAP eapPayload = new EAP(EAP.REQUEST, stateMachine.getIdentifier(), EAP.ATTR_IDENTITY, null);
Jonathan Harta46dddf2015-06-30 15:31:20 -0700331 Ethernet eth = buildEapolResponse(srcMAC, MacAddress.valueOf(1L),
332 ethPkt.getVlanID(), EAPOL.EAPOL_PACKET,
333 eapPayload);
Ari Saha89831742015-06-26 10:31:48 -0700334 stateMachine.supplicantAddress = srcMAC;
335 stateMachine.vlanId = ethPkt.getVlanID();
336
337 this.sendPacketToSupplicant(eth, stateMachine.supplicantConnectpoint);
338 } catch (StateMachineException e) {
339 e.printStackTrace();
340 }
341
342 break;
343 case EAPOL.EAPOL_PACKET:
Jonathan Harta46dddf2015-06-30 15:31:20 -0700344 //check if this is a Response/Identify or a Response/TLS
Ari Saha89831742015-06-26 10:31:48 -0700345 EAP eapPacket = (EAP) eapol.getPayload();
346
347 byte dataType = eapPacket.getDataType();
348 switch (dataType) {
349 case EAP.ATTR_IDENTITY:
350 try {
351 //request id access to RADIUS
352 RADIUS radiusPayload = new RADIUS(RADIUS.RADIUS_CODE_ACCESS_REQUEST,
353 eapPacket.getIdentifier());
354 radiusPayload.setIdentifier(stateMachine.getIdentifier());
355 radiusPayload.setAttribute(RADIUSAttribute.RADIUS_ATTR_USERNAME,
356 eapPacket.getData());
357 stateMachine.setUsername(eapPacket.getData());
358 radiusPayload.setAttribute(RADIUSAttribute.RADIUS_ATTR_NAS_IP,
359 AAA.this.parsedNasIpAddress.getAddress());
360
361 radiusPayload.encapsulateMessage(eapPacket);
362
363 // set Request Authenticator in StateMachine
364 stateMachine.setRequestAuthenticator(radiusPayload.generateAuthCode());
365 radiusPayload.addMessageAuthenticator(AAA.this.radiusSecret);
366 sendRadiusMessage(radiusPayload);
367
368 //change the state to "PENDING"
369 stateMachine.requestAccess();
370 } catch (StateMachineException e) {
371 e.printStackTrace();
372 }
373 break;
374 case EAP.ATTR_MD5:
375 //verify if the EAP identifier corresponds to the challenge identifier from the client state
376 //machine.
377 if (eapPacket.getIdentifier() == stateMachine.getChallengeIdentifier()) {
378 //send the RADIUS challenge response
379 RADIUS radiusPayload = new RADIUS(RADIUS.RADIUS_CODE_ACCESS_REQUEST,
380 eapPacket.getIdentifier());
381 radiusPayload.setIdentifier(stateMachine.getChallengeIdentifier());
382 radiusPayload.setAttribute(RADIUSAttribute.RADIUS_ATTR_USERNAME,
383 stateMachine.getUsername());
384 radiusPayload.setAttribute(RADIUSAttribute.RADIUS_ATTR_NAS_IP,
385 AAA.this.parsedNasIpAddress.getAddress());
386
387 radiusPayload.encapsulateMessage(eapPacket);
388
389 radiusPayload.setAttribute(RADIUSAttribute.RADIUS_ATTR_STATE,
390 stateMachine.getChallengeState());
391 radiusPayload.addMessageAuthenticator(AAA.this.radiusSecret);
392 sendRadiusMessage(radiusPayload);
393 }
394 break;
395 case EAP.ATTR_TLS:
396 try {
397 //request id access to RADIUS
398 RADIUS radiusPayload = new RADIUS(RADIUS.RADIUS_CODE_ACCESS_REQUEST,
399 eapPacket.getIdentifier());
400 radiusPayload.setIdentifier(stateMachine.getIdentifier());
401 radiusPayload.setAttribute(RADIUSAttribute.RADIUS_ATTR_USERNAME,
402 stateMachine.getUsername());
403 radiusPayload.setAttribute(RADIUSAttribute.RADIUS_ATTR_NAS_IP,
404 AAA.this.parsedNasIpAddress.getAddress());
405
406 radiusPayload.encapsulateMessage(eapPacket);
407
408 radiusPayload.setAttribute(RADIUSAttribute.RADIUS_ATTR_STATE,
409 stateMachine.getChallengeState());
410 stateMachine.setRequestAuthenticator(radiusPayload.generateAuthCode());
411
412 radiusPayload.addMessageAuthenticator(AAA.this.radiusSecret);
413
414 sendRadiusMessage(radiusPayload);
415 // TODO: this gets called on every fragment, should only be called at TLS-Start
416 stateMachine.requestAccess();
417 } catch (StateMachineException e) {
418 e.printStackTrace();
419 }
420 break;
421 default:
422 return;
423 }
424 break;
425 default:
426 return;
427 }
428 }
429
430 /**
Jonathan Harta46dddf2015-06-30 15:31:20 -0700431 * Handles RADIUS packets.
432 *
Ari Saha89831742015-06-26 10:31:48 -0700433 * @param radiusPacket RADIUS packet coming from the RADIUS server.
434 */
435 private void handleRadiusPacket(RADIUS radiusPacket) {
436 StateMachine stateMachine = getStateMachineById(radiusPacket.getIdentifier());
437 if (stateMachine == null) {
438 log.error("Invalid session identifier, exiting...");
439 return;
440 }
441
Ari Saha89831742015-06-26 10:31:48 -0700442 EAP eapPayload = new EAP();
443 Ethernet eth = null;
444 switch (radiusPacket.getCode()) {
445 case RADIUS.RADIUS_CODE_ACCESS_CHALLENGE:
446 byte[] challengeState = radiusPacket.getAttribute(RADIUSAttribute.RADIUS_ATTR_STATE).getValue();
447 eapPayload = radiusPacket.decapsulateMessage();
448 stateMachine.setChallengeInfo(eapPayload.getIdentifier(), challengeState);
Jonathan Harta46dddf2015-06-30 15:31:20 -0700449 eth = buildEapolResponse(stateMachine.supplicantAddress,
Ari Saha89831742015-06-26 10:31:48 -0700450 MacAddress.valueOf(1L), stateMachine.vlanId, EAPOL.EAPOL_PACKET, eapPayload);
451 this.sendPacketToSupplicant(eth, stateMachine.supplicantConnectpoint);
452 break;
453 case RADIUS.RADIUS_CODE_ACCESS_ACCEPT:
454 try {
455 //send an EAPOL - Success to the supplicant.
Jonathan Harta46dddf2015-06-30 15:31:20 -0700456 byte[] eapMessage =
Ari Saha89831742015-06-26 10:31:48 -0700457 radiusPacket.getAttribute(RADIUSAttribute.RADIUS_ATTR_EAP_MESSAGE).getValue();
458 eapPayload = new EAP();
459 eapPayload = (EAP) eapPayload.deserialize(eapMessage, 0, eapMessage.length);
Jonathan Harta46dddf2015-06-30 15:31:20 -0700460 eth = buildEapolResponse(stateMachine.supplicantAddress,
Ari Saha89831742015-06-26 10:31:48 -0700461 MacAddress.valueOf(1L), stateMachine.vlanId, EAPOL.EAPOL_PACKET, eapPayload);
462 this.sendPacketToSupplicant(eth, stateMachine.supplicantConnectpoint);
463
464 stateMachine.authorizeAccess();
465 } catch (StateMachineException e) {
466 e.printStackTrace();
467 }
468 break;
469 case RADIUS.RADIUS_CODE_ACCESS_REJECT:
470 try {
471 stateMachine.denyAccess();
472 } catch (StateMachineException e) {
473 e.printStackTrace();
474 }
475 break;
476 default:
477 log.warn("Unknown RADIUS message received with code: {}", radiusPacket.getCode());
478 }
479 }
480
481 private StateMachine getStateMachineById(byte identifier) {
482 StateMachine stateMachine = null;
483 Set stateMachineSet = stateMachineMap.entrySet();
484
485 synchronized (stateMachineMap) {
486 Iterator itr = stateMachineSet.iterator();
487 while (itr.hasNext()) {
488 Map.Entry entry = (Map.Entry) itr.next();
489 stateMachine = (StateMachine) entry.getValue();
490 if (identifier == stateMachine.getIdentifier()) {
491 //the state machine has already been created for this session session
492 stateMachine = (StateMachine) entry.getValue();
493 break;
494 }
495 }
496 }
497
498 return stateMachine;
499 }
500
501 private StateMachine getStateMachine(String sessionId) {
502 StateMachine stateMachine = null;
503 Set stateMachineSet = stateMachineMap.entrySet();
504
505 synchronized (stateMachineMap) {
506 Iterator itr = stateMachineSet.iterator();
507 while (itr.hasNext()) {
508
509 Map.Entry entry = (Map.Entry) itr.next();
510 if (sessionId.equals(entry.getKey())) {
511 //the state machine has already been created for this session session
512 stateMachine = (StateMachine) entry.getValue();
513 break;
514 }
515 }
516 }
517
518 if (stateMachine == null) {
519 stateMachine = new StateMachine(sessionId, voltTenantService);
520 stateMachineMap.put(sessionId, stateMachine);
521 }
522
523 return stateMachine;
524 }
525
526 private void sendRadiusMessage(RADIUS radiusMessage) {
527 Set<Host> hosts = hostService.getHostsByIp(IpAddress.valueOf(radiusIpAddress));
528 Optional<Host> odst = hosts.stream().filter(h -> h.vlan().toShort() == VlanId.UNTAGGED).findFirst();
529
530 Host dst;
531 if (!odst.isPresent()) {
532 log.info("Radius server {} is not present", radiusIpAddress);
533 return;
534 } else {
535 dst = odst.get();
536 }
537
538 UDP udp = new UDP();
539 IPv4 ip4Packet = new IPv4();
540 Ethernet ethPkt = new Ethernet();
541 radiusMessage.setParent(udp);
542 udp.setDestinationPort((short) 1812);
543 udp.setSourcePort((short) 1812); // TODO: make this configurable
544 udp.setPayload(radiusMessage);
545 udp.setParent(ip4Packet);
546 ip4Packet.setSourceAddress(AAA.this.nasIpAddress);
547 ip4Packet.setDestinationAddress(AAA.this.radiusIpAddress);
548 ip4Packet.setProtocol(IPv4.PROTOCOL_UDP);
549 ip4Packet.setPayload(udp);
550 ip4Packet.setParent(ethPkt);
551 ethPkt.setDestinationMACAddress(radiusMacAddress);
552 ethPkt.setSourceMACAddress(nasMacAddress);
553 ethPkt.setEtherType(Ethernet.TYPE_IPV4);
554 ethPkt.setPayload(ip4Packet);
555
556 TrafficTreatment treatment = DefaultTrafficTreatment.builder()
557 .setOutput(PortNumber.portNumber(Integer.parseInt(radiusPort))).build();
558 OutboundPacket packet = new DefaultOutboundPacket(DeviceId.deviceId(radiusSwitch),
559 treatment, ByteBuffer.wrap(ethPkt.serialize()));
560 packetService.emit(packet);
561
562 }
563
Ari Saha89831742015-06-26 10:31:48 -0700564 /**
565 * Send the ethernet packet to the supplicant.
Jonathan Harta46dddf2015-06-30 15:31:20 -0700566 *
Ari Saha89831742015-06-26 10:31:48 -0700567 * @param ethernetPkt the ethernet packet
Jonathan Harta46dddf2015-06-30 15:31:20 -0700568 * @param connectPoint the connect point to send out
Ari Saha89831742015-06-26 10:31:48 -0700569 */
570 private void sendPacketToSupplicant(Ethernet ethernetPkt, ConnectPoint connectPoint) {
571 TrafficTreatment treatment = DefaultTrafficTreatment.builder().setOutput(connectPoint.port()).build();
572 OutboundPacket packet = new DefaultOutboundPacket(connectPoint.deviceId(),
573 treatment, ByteBuffer.wrap(ethernetPkt.serialize()));
574 packetService.emit(packet);
575 }
576
577 }
578
579}