Patchwork [PATCHv2,13/21] radius: parse tagged vlan information

login
register
mail settings
Submitter michael-dev@fami-braun.de
Date April 8, 2013, 12:36 p.m.
Message ID <0aa7f1a71a8b1d66d69ae6adea73e1628a308453.1370512966.git.michael-dev@fami-braun.de>
Download mbox | patch
Permalink /patch/249369/
State Superseded
Headers show

Comments

michael-dev@fami-braun.de - April 8, 2013, 12:36 p.m.
Signed-hostap: Michael Braun <michael-dev@fami-braun.de>

Patch

diff --git a/src/ap/ieee802_11_auth.c b/src/ap/ieee802_11_auth.c
index 9d077eb..b6829ba 100644
--- a/src/ap/ieee802_11_auth.c
+++ b/src/ap/ieee802_11_auth.c
@@ -540,8 +540,14 @@  hostapd_acl_recv_radius(struct radius_msg *msg, struct radius_msg *req,
 			cache->acct_interim_interval = 0;
 		}
 
-		vlan_alloc(&cache->vlan_id, radius_msg_get_vlanid(msg), 0,
-		           NULL);
+		{
+			int untagged, num_tagged, *tagged;
+        	        num_tagged = radius_msg_get_vlanid(msg, &untagged,
+			                                   &tagged);
+			vlan_alloc(&cache->vlan_id, untagged, num_tagged,
+			           tagged);
+			os_free(tagged);
+		}
 
 		decode_tunnel_passwords(hapd, shared_secret, shared_secret_len,
 					msg, req, cache);
diff --git a/src/ap/ieee802_1x.c b/src/ap/ieee802_1x.c
index 1bc5fb2..1492a43 100644
--- a/src/ap/ieee802_1x.c
+++ b/src/ap/ieee802_1x.c
@@ -1444,8 +1444,11 @@  ieee802_1x_receive_auth(struct radius_msg *msg, struct radius_msg *req,
 #ifndef CONFIG_NO_VLAN
 		else {
 			vlan_alloc_copy(&old_vlanid, &sta->vlan_id);
-			vlan_alloc(&sta->vlan_id, radius_msg_get_vlanid(msg),
-			           0, NULL);
+			int *tagged, untagged, num_tagged;
+			num_tagged = radius_msg_get_vlanid(msg, &untagged,
+			                                   &tagged);
+			vlan_alloc(&sta->vlan_id, untagged, num_tagged, tagged);
+			os_free(tagged);
 		}
 		if (vlan_notempty(&sta->vlan_id) &&
 		    vlan_untagged(&sta->vlan_id) > 0 &&
diff --git a/src/radius/radius.c b/src/radius/radius.c
index d1feec9..dd5ad91 100644
--- a/src/radius/radius.c
+++ b/src/radius/radius.c
@@ -214,6 +214,8 @@  static struct radius_attr_type radius_attrs[] =
 	  RADIUS_ATTR_INT32 },
 	{ RADIUS_ATTR_EVENT_TIMESTAMP, "Event-Timestamp",
 	  RADIUS_ATTR_INT32 },
+	{ RADIUS_ATTR_EGRESS_VLANID, "Egress-VLANID",
+	  RADIUS_ATTR_INT32 },
 	{ RADIUS_ATTR_NAS_PORT_TYPE, "NAS-Port-Type", RADIUS_ATTR_INT32 },
 	{ RADIUS_ATTR_TUNNEL_TYPE, "Tunnel-Type", RADIUS_ATTR_HEXDUMP },
 	{ RADIUS_ATTR_TUNNEL_MEDIUM_TYPE, "Tunnel-Medium-Type",
@@ -1331,10 +1333,15 @@  struct radius_tunnel_attrs {
 
 /**
  * radius_msg_get_vlanid - Parse RADIUS attributes for VLAN tunnel information
+ * 
  * @msg: RADIUS message
- * Returns: VLAN ID for the first tunnel configuration of -1 if none is found
+ * @untagged: pointer to store untagged vlan_id
+ * @tagged: pointer to store pointer to tagged list
+ *
+ * Returns: number of tagged tunnel configurations, -1 if neither tagged nor
+ *          untagged configuration is found
  */
-int radius_msg_get_vlanid(struct radius_msg *msg)
+int radius_msg_get_vlanid(struct radius_msg *msg, int *untagged, int **tagged)
 {
 	struct radius_tunnel_attrs tunnel[RADIUS_TUNNEL_TAGS], *tun;
 	size_t i;
@@ -1342,8 +1349,17 @@  int radius_msg_get_vlanid(struct radius_msg *msg)
 	const u8 *data;
 	char buf[10];
 	size_t dlen;
+	int num_tagged = 0;
+	int vlan_id;
+#ifdef CONFIG_VLAN_TAGGED
+	int tagged_size = 0, new_size, *tmp;
+#endif /* CONFIG_VLAN_TAGGED */
 
 	os_memset(&tunnel, 0, sizeof(tunnel));
+	if (untagged)
+		*untagged = 0;
+	if (tagged)
+		*tagged = NULL;
 
 	for (i = 0; i < msg->attr_used; i++) {
 		attr = radius_get_attr_hdr(msg, i);
@@ -1380,24 +1396,65 @@  int radius_msg_get_vlanid(struct radius_msg *msg)
 				break;
 			os_memcpy(buf, data, dlen);
 			buf[dlen] = '\0';
+			vlan_id = atoi(buf);
+			if (vlan_id <= 0)
+				break;
 			tun->tag_used++;
-			tun->vlanid = atoi(buf);
+			tun->vlanid = vlan_id;
+			break;
+		case RADIUS_ATTR_EGRESS_VLANID: /* RFC 4675 */
+			if (attr->length != 6)
+				break;
+			vlan_id = WPA_GET_BE24(data + 1);
+			if (vlan_id <= 0)
+				break;
+			if (data[0] == 0x31 && tagged) { /* tagged vlan */
+				#ifdef CONFIG_VLAN_TAGGED
+				if (num_tagged >= tagged_size) {
+					new_size = 2 * tagged_size;
+					if (new_size < 1)
+						new_size = 1;
+					tmp = os_realloc_array(tagged,
+					      new_size, sizeof(*tagged));
+					if (!tmp)
+						break;
+					if (tagged_size > 0)
+						os_memcpy(tmp, *tagged,
+						          sizeof(int) *
+							  tagged_size);
+					tagged_size = new_size;
+					*tagged = tmp;
+				}
+				(*tagged)[num_tagged] = vlan_id;
+				num_tagged++;
+				#endif /* CONFIG_VLAN_TAGGED */
+			} else if (data[0] == 0x32 && untagged) {
+			        /* untagged vlan */
+				*untagged = vlan_id;
+			}
 			break;
 		}
 	}
 
+	/* use  tunnel with lowest tag for untagged vlan id */
 	for (i = 0; i < RADIUS_TUNNEL_TAGS; i++) {
 		tun = &tunnel[i];
 		if (tun->tag_used &&
 		    tun->type == RADIUS_TUNNEL_TYPE_VLAN &&
 		    tun->medium_type == RADIUS_TUNNEL_MEDIUM_TYPE_802 &&
-		    tun->vlanid > 0)
-			return tun->vlanid;
+		    tun->vlanid > 0 &&
+		    untagged)
+		{
+			*untagged = tun->vlanid;
+			break;
+		}
 	}
 
-	return -1;
-}
+	if (!(untagged && *untagged) && !num_tagged)
+		return -1;
 
+	return num_tagged;
+}
 
 /**
  * radius_msg_get_tunnel_password - Parse RADIUS attribute Tunnel-Password
diff --git a/src/radius/radius.h b/src/radius/radius.h
index 2031054..562339e 100644
--- a/src/radius/radius.h
+++ b/src/radius/radius.h
@@ -79,6 +79,7 @@  enum { RADIUS_ATTR_USER_NAME = 1,
        RADIUS_ATTR_ACCT_INPUT_GIGAWORDS = 52,
        RADIUS_ATTR_ACCT_OUTPUT_GIGAWORDS = 53,
        RADIUS_ATTR_EVENT_TIMESTAMP = 55,
+       RADIUS_ATTR_EGRESS_VLANID = 56,
        RADIUS_ATTR_NAS_PORT_TYPE = 61,
        RADIUS_ATTR_TUNNEL_TYPE = 64,
        RADIUS_ATTR_TUNNEL_MEDIUM_TYPE = 65,
@@ -239,7 +240,7 @@  radius_msg_add_attr_user_password(struct radius_msg *msg,
 				  const u8 *data, size_t data_len,
 				  const u8 *secret, size_t secret_len);
 int radius_msg_get_attr(struct radius_msg *msg, u8 type, u8 *buf, size_t len);
-int radius_msg_get_vlanid(struct radius_msg *msg);
+int radius_msg_get_vlanid(struct radius_msg *msg, int *untagged, int **tagged);
 char * radius_msg_get_tunnel_password(struct radius_msg *msg, int *keylen,
 				      const u8 *secret, size_t secret_len,
 				      struct radius_msg *sent_msg, size_t n);