bgpd: check ATOMIC_AGGREGATE attr flags (BZ#678)

* bgp_attr.c
  * bgp_attr_atomic(): accept extra argument, add checks for
    "optional", "transitive" and "partial" bits, log each error
    condition independently
  * bgp_attr_parse(): provide extra argument
diff --git a/bgpd/bgp_attr.c b/bgpd/bgp_attr.c
index a986699..015ae59 100644
--- a/bgpd/bgp_attr.c
+++ b/bgpd/bgp_attr.c
@@ -1107,8 +1107,44 @@
 /* Atomic aggregate. */
 static int
 bgp_attr_atomic (struct peer *peer, bgp_size_t length, 
-		 struct attr *attr, u_char flag)
+		 struct attr *attr, u_char flag, u_char *startp)
 {
+  bgp_size_t total;
+
+  total = length + (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN) ? 4 : 3);
+  /* Flag checks. */
+  if (CHECK_FLAG (flag, BGP_ATTR_FLAG_OPTIONAL))
+    {
+      zlog (peer->log, LOG_ERR,
+	    "ATOMIC_AGGREGATE attribute must not be flagged as \"optional\" (%u)", flag);
+      bgp_notify_send_with_data (peer,
+				 BGP_NOTIFY_UPDATE_ERR,
+				 BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR,
+				 startp, total);
+      return -1;
+    }
+  if (! CHECK_FLAG (flag, BGP_ATTR_FLAG_TRANS))
+    {
+      zlog (peer->log, LOG_ERR,
+	    "ATOMIC_AGGREGATE attribute must be flagged as \"transitive\" (%u)", flag);
+      bgp_notify_send_with_data (peer,
+				 BGP_NOTIFY_UPDATE_ERR,
+				 BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR,
+				 startp, total);
+      return -1;
+    }
+  if (CHECK_FLAG (flag, BGP_ATTR_FLAG_PARTIAL))
+    {
+      zlog (peer->log, LOG_ERR,
+	    "ATOMIC_AGGREGATE attribute must not be flagged as \"partial\" (%u)", flag);
+      bgp_notify_send_with_data (peer,
+				 BGP_NOTIFY_UPDATE_ERR,
+				 BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR,
+				 startp, total);
+      return -1;
+    }
+
+  /* Length check. */
   if (length != 0)
     {
       zlog (peer->log, LOG_ERR, "Bad atomic aggregate length %d", length);
@@ -1764,7 +1800,7 @@
 	  ret = bgp_attr_local_pref (peer, length, attr, flag, startp);
 	  break;
 	case BGP_ATTR_ATOMIC_AGGREGATE:
-	  ret = bgp_attr_atomic (peer, length, attr, flag);
+	  ret = bgp_attr_atomic (peer, length, attr, flag, startp);
 	  break;
 	case BGP_ATTR_AGGREGATOR:
 	  ret = bgp_attr_aggregator (peer, length, attr, flag);