[PATCH libcacard v2 07/35] tests: Test previously introduced applets

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



 * Make sure the GET PROPERTIES APDU returns something that can be parsed
   by our SimpleTLV parser

 * Make sure the GET ACR APDU returns something reasonable on ACA applet
   with valid and invalid parameters

 * Make sure the READ BUFFER APDU returns valid buffers

 * Validate PKI properties buffer matches the expected key size

 * Separate test for  GET RESPONSE APDU

Signed-off-by: Jakub Jelen <jjelen@xxxxxxxxxx>
Reviewed-by: Robert Relyea <rrelyea@xxxxxxxxxx>
---
 Makefile.am       |   6 +-
 tests/libcacard.c | 426 ++++++++++++++++++++++++++++++++++++++++++++--
 2 files changed, 418 insertions(+), 14 deletions(-)

diff --git a/Makefile.am b/Makefile.am
index 0044b60..1be09c6 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -77,7 +77,11 @@ test_programs =					\
 	tests/simpletlv				\
 	$(NULL)
 
-tests_libcacard_LDADD = libcacard.la
+tests_libcacard_LDADD =				\
+	libcacard.la				\
+	src/common.lo				\
+	src/simpletlv.lo			\
+	$(NULL)
 
 tests_simpletlv_LDADD =				\
 	libcacard.la				\
diff --git a/tests/libcacard.c b/tests/libcacard.c
index ccb3188..67ea089 100644
--- a/tests/libcacard.c
+++ b/tests/libcacard.c
@@ -1,5 +1,6 @@
 #include <glib.h>
 #include "libcacard.h"
+#include "simpletlv.h"
 
 #define ARGS "db=\"sql:%s\" use_hw=no soft=(,Test,CAC,,cert1,cert2,cert3)"
 
@@ -9,6 +10,12 @@ static guint nreaders;
 static GMutex mutex;
 static GCond cond;
 
+enum {
+    TEST_PKI,
+    TEST_CCC,
+    TEST_ACA
+};
+
 static gpointer
 events_thread(gpointer arg)
 {
@@ -130,6 +137,7 @@ static void test_xfer(void)
     int dwRecvLength = APDUBufSize;
     uint8_t pbRecvBuffer[APDUBufSize];
     uint8_t pbSendBuffer[] = {
+        /* Select Applet that is not there */
         0x00, 0xa4, 0x04, 0x00, 0x07, 0x62, 0x76, 0x01, 0xff, 0x00, 0x00, 0x00,
     };
 
@@ -141,37 +149,379 @@ static void test_xfer(void)
     vreader_free(reader); /* get by id ref */
 }
 
-static void test_cac(void)
+static void get_properties(VReader *reader, int object_type)
 {
-    VReader *reader = vreader_get_reader_by_id(0);
+    int dwRecvLength = APDUBufSize;
     VReaderStatus status;
+    uint8_t pbRecvBuffer[APDUBufSize], *p, *p_end;
+    uint8_t get_properties[] = {
+        /* Get properties */
+        0x80, 0x56, 0x01, 0x00, 0x00
+    };
+    int verified_pki_properties = 0;
+
+    status = vreader_xfr_bytes(reader,
+                               get_properties, sizeof(get_properties),
+                               pbRecvBuffer, &dwRecvLength);
+    g_assert_cmpint(status, ==, VREADER_OK);
+    /* for too long Le, the cards return LE_ERROR with correct length to ask */
+    g_assert_cmpint(dwRecvLength, ==, 2);
+    g_assert_cmpint(pbRecvBuffer[dwRecvLength-2], ==, VCARD7816_SW1_LE_ERROR);
+    g_assert_cmpint(pbRecvBuffer[dwRecvLength-1], >, 0);
+
+    /* Update the APDU to match Le field from response and resend */
+    get_properties[4] = pbRecvBuffer[1];
+    dwRecvLength = APDUBufSize;
+    status = vreader_xfr_bytes(reader,
+                               get_properties, sizeof(get_properties),
+                               pbRecvBuffer, &dwRecvLength);
+    g_assert_cmpint(status, ==, VREADER_OK);
+    g_assert_cmpint(dwRecvLength, >, 2);
+    g_assert_cmpint(pbRecvBuffer[dwRecvLength-2], ==, VCARD7816_SW1_SUCCESS);
+    g_assert_cmpint(pbRecvBuffer[dwRecvLength-1], ==, 0x00);
+
+    /* try to parse the response, if it makes sense */
+    p = pbRecvBuffer;
+    p_end = p + dwRecvLength - 2;
+    while (p < p_end) {
+        uint8_t tag;
+        size_t vlen;
+        if (simpletlv_read_tag(&p, p_end - p, &tag, &vlen) < 0) {
+            g_debug("The generated SimpleTLV can not be parsed");
+            g_assert_not_reached();
+        }
+        g_assert_cmpint(vlen, <=, p_end - p);
+        g_debug("Tag: 0x%02x, Len: %lu", tag, vlen);
+
+        if (tag == 0x51 /* PKI OBJECT */) {
+            /* recursive SimpleTLV structure */
+            uint8_t *p2 = p, *p2_end = p + vlen;
+            while (p2 < p2_end) {
+                uint8_t tag2;
+                size_t vlen2;
+                if (simpletlv_read_tag(&p2, p2_end - p2, &tag2, &vlen2) < 0) {
+                    g_debug("The generated SimpleTLV can not be parsed");
+                    g_assert_not_reached();
+                }
+                g_assert_cmpint(vlen2, <=, p2_end - p2);
+                g_debug("    Tag: 0x%02x, Len: %lu", tag2, vlen2);
+
+                if (tag2 == 0x43 /* PKI PROPERTIES */) {
+                    /* For now, expecting 2048 b RSA keys */
+                    g_assert_cmphex(p2[0], ==, 0x06);
+                    g_assert_cmphex(p2[1], ==, (2048 / 8 / 8));
+                    g_assert_cmphex(p2[2], ==, 0x01);
+                    g_assert_cmphex(p2[3], ==, 0x01);
+                    verified_pki_properties = 1;
+                }
+                p2 += vlen2;
+            }
+        }
+        p += vlen;
+    }
+
+    if (object_type == TEST_PKI) {
+        g_assert_cmpint(verified_pki_properties, ==, 1);
+    }
+}
+
+static void get_acr(VReader *reader)
+{
     int dwRecvLength = APDUBufSize;
+    VReaderStatus status;
     uint8_t pbRecvBuffer[APDUBufSize];
-    uint8_t selfile0[] = {
-        0x00, 0xa4, 0x04, 0x00, 0x07, 0xa0, 0x00, 0x00, 0x00, 0x79, 0x01, 0x00
+    uint8_t get_acr[] = {
+        /* Get ACR [TYPE] [ 0 ] [Le] */
+        0x80, 0x4c, 0x00, 0x00, 0x00
+    };
+    uint8_t get_acr_arg[] = {
+        /* Get ACR [TYPE] [ 0 ] [Lc] [data] [Le] */
+        0x80, 0x4c, 0x01, 0x00, 0x01, 0x0A, 0x00
+    };
+    uint8_t get_acr_coid[] = {
+        /* Get ACR [TYPE] [ 0 ] [Lc] [   data   ] [Le] */
+        0x80, 0x4c, 0x12, 0x00, 0x02, 0xDB, 0x00, 0x00
+    };
+    uint8_t get_acr_aid[] = {
+        /* Get ACR [TYPE] [ 0 ] [Lc] [               data                     ] [Le]*/
+        0x80, 0x4c, 0x11, 0x00, 0x07, 0xA0, 0x00, 0x00, 0x00, 0x79, 0x12, 0x02, 0x00
     };
     uint8_t getresp[] = {
-        0x00, 0xc0, 0x00, 0x00, 0x0d
+        /* Get Response (max we can get) */
+        0x00, 0xc0, 0x00, 0x00, 0x00
     };
 
-    g_assert_nonnull(reader);
+    /* P1=0x00: ACR table */
+    dwRecvLength = APDUBufSize;
+    status = vreader_xfr_bytes(reader,
+                               get_acr, sizeof(get_acr),
+                               pbRecvBuffer, &dwRecvLength);
+    g_assert_cmpint(status, ==, VREADER_OK);
+    g_assert_cmpint(dwRecvLength, >, 2);
+    g_assert_cmphex(pbRecvBuffer[dwRecvLength-2], ==, VCARD7816_SW1_SUCCESS);
+    g_assert_cmphex(pbRecvBuffer[dwRecvLength-1], ==, 0x00);
+
+    /* TODO parse the response */
+
+
+    /* P1=0x01: ACR table by ACRID=0x0A */
+    dwRecvLength = APDUBufSize;
+    status = vreader_xfr_bytes(reader,
+                               get_acr_arg, sizeof(get_acr_arg),
+                               pbRecvBuffer, &dwRecvLength);
+    g_assert_cmpint(status, ==, VREADER_OK);
+    g_assert_cmpint(dwRecvLength, >, 2);
+    g_assert_cmphex(pbRecvBuffer[dwRecvLength-2], ==, VCARD7816_SW1_SUCCESS);
+    g_assert_cmphex(pbRecvBuffer[dwRecvLength-1], ==, 0x00);
+
+    /* P1=0x01: ACR table by ACRID=0x0F (non-existing) */
+    get_acr_arg[5] = 0x0F;
+    dwRecvLength = APDUBufSize;
+    status = vreader_xfr_bytes(reader,
+                               get_acr_arg, sizeof(get_acr_arg),
+                               pbRecvBuffer, &dwRecvLength);
+    g_assert_cmpint(status, ==, VREADER_OK);
+    g_assert_cmpint(dwRecvLength, ==, 2);
+    g_assert_cmphex(pbRecvBuffer[dwRecvLength-2], ==, 0x6a);
+    g_assert_cmphex(pbRecvBuffer[dwRecvLength-1], ==, 0x88);
+
+
+    /* P1=0x10: Applet/Object ACR table */
+    get_acr[2] = 0x10;
+    dwRecvLength = APDUBufSize;
     status = vreader_xfr_bytes(reader,
-                               selfile0, sizeof(selfile0),
+                               get_acr, sizeof(get_acr),
                                pbRecvBuffer, &dwRecvLength);
     g_assert_cmpint(status, ==, VREADER_OK);
-    g_assert_cmphex(pbRecvBuffer[0], ==, VCARD7816_SW1_RESPONSE_BYTES);
-    g_assert_cmphex(pbRecvBuffer[1], ==, 0x0d);
+    /* This one is big, so we will get SW1 = 0x61 without the actual response */
+    g_assert_cmpint(dwRecvLength, ==, 2);
+    g_assert_cmphex(pbRecvBuffer[dwRecvLength-2], ==, VCARD7816_SW1_RESPONSE_BYTES);
+    g_assert_cmphex(pbRecvBuffer[dwRecvLength-1], ==, 0x00);
 
+    /* fetch the actual response */
     dwRecvLength = APDUBufSize;
     status = vreader_xfr_bytes(reader,
                                getresp, sizeof(getresp),
                                pbRecvBuffer, &dwRecvLength);
     g_assert_cmpint(status, ==, VREADER_OK);
-    g_assert_cmpint(dwRecvLength, ==, 15);
+    g_assert_cmpint(dwRecvLength, >, 2);
+    g_assert_cmphex(pbRecvBuffer[dwRecvLength-2], ==, VCARD7816_SW1_RESPONSE_BYTES);
+    g_assert_cmphex(pbRecvBuffer[dwRecvLength-1], >, 0x00);
+
+    /* ignore the rest for now */
+
+
+    /* P1=0x11: Applet/Object ACR table by AID */
+    dwRecvLength = APDUBufSize;
+    status = vreader_xfr_bytes(reader,
+                               get_acr_aid, sizeof(get_acr_aid),
+                               pbRecvBuffer, &dwRecvLength);
+    g_assert_cmpint(status, ==, VREADER_OK);
+    g_assert_cmpint(dwRecvLength, >, 2);
+    g_assert_cmphex(pbRecvBuffer[dwRecvLength-2], ==, VCARD7816_SW1_SUCCESS);
+    g_assert_cmphex(pbRecvBuffer[dwRecvLength-1], ==, 0x00);
+
+    /* P1=0x11: unknown AID should fail */
+    get_acr_aid[11] = 0x11;
+    dwRecvLength = APDUBufSize;
+    status = vreader_xfr_bytes(reader,
+                               get_acr_aid, sizeof(get_acr_aid),
+                               pbRecvBuffer, &dwRecvLength);
+    g_assert_cmpint(status, ==, VREADER_OK);
+    g_assert_cmpint(dwRecvLength, ==, 2);
+    g_assert_cmphex(pbRecvBuffer[dwRecvLength-2], ==, VCARD7816_SW1_P1_P2_ERROR);
+    g_assert_cmphex(pbRecvBuffer[dwRecvLength-1], ==, 0x88);
+
+
+    /* P1=0x12: Applet/Object ACR table by OID */
+    dwRecvLength = APDUBufSize;
+    status = vreader_xfr_bytes(reader,
+                               get_acr_coid, sizeof(get_acr_coid),
+                               pbRecvBuffer, &dwRecvLength);
+    g_assert_cmpint(status, ==, VREADER_OK);
+    g_assert_cmpint(dwRecvLength, >, 2);
+    g_assert_cmphex(pbRecvBuffer[dwRecvLength-2], ==, VCARD7816_SW1_SUCCESS);
+    g_assert_cmphex(pbRecvBuffer[dwRecvLength-1], ==, 0x00);
+
+    /* P1=0x12: unknown OID should fail */
+    get_acr_coid[6] = 0xDB;
+    dwRecvLength = APDUBufSize;
+    status = vreader_xfr_bytes(reader,
+                               get_acr_coid, sizeof(get_acr_coid),
+                               pbRecvBuffer, &dwRecvLength);
+    g_assert_cmpint(status, ==, VREADER_OK);
+    g_assert_cmpint(dwRecvLength, ==, 2);
+    g_assert_cmphex(pbRecvBuffer[dwRecvLength-2], ==, VCARD7816_SW1_P1_P2_ERROR);
+    g_assert_cmphex(pbRecvBuffer[dwRecvLength-1], ==, 0x80);
+
+
+    /* P1=0x20: Access Method Provider table */
+    get_acr[2] = 0x20;
+    dwRecvLength = APDUBufSize;
+    status = vreader_xfr_bytes(reader,
+                               get_acr, sizeof(get_acr),
+                               pbRecvBuffer, &dwRecvLength);
+    g_assert_cmpint(status, ==, VREADER_OK);
+    g_assert_cmpint(dwRecvLength, >, 2);
+    g_assert_cmphex(pbRecvBuffer[dwRecvLength-2], ==, VCARD7816_SW1_SUCCESS);
+    g_assert_cmphex(pbRecvBuffer[dwRecvLength-1], ==, 0x00);
+
+    /* P1=0x21: Service Applet Table */
+    get_acr[2] = 0x21;
+    dwRecvLength = APDUBufSize;
+    status = vreader_xfr_bytes(reader,
+                               get_acr, sizeof(get_acr),
+                               pbRecvBuffer, &dwRecvLength);
+    g_assert_cmpint(status, ==, VREADER_OK);
+    g_assert_cmpint(dwRecvLength, >, 2);
     g_assert_cmphex(pbRecvBuffer[dwRecvLength-2], ==, VCARD7816_SW1_SUCCESS);
-    g_assert_cmphex(pbRecvBuffer[dwRecvLength-1], ==, 0x0);
+    g_assert_cmphex(pbRecvBuffer[dwRecvLength-1], ==, 0x00);
+
+}
+
+static void read_buffer(VReader *reader, uint8_t type)
+{
+    int dwRecvLength = APDUBufSize, dwLength, dwReadLength, offset;
+    VReaderStatus status;
+    uint8_t pbRecvBuffer[APDUBufSize];
+    uint8_t read_buffer[] = {
+        /*Read Buffer  OFFSET         TYPE LENGTH a_Le */
+        0x80, 0x52, 0x00, 0x00, 0x02, 0x01, 0x02, 0x02
+    };
+
+    dwRecvLength = 4;
+    read_buffer[5] = type;
+    status = vreader_xfr_bytes(reader,
+                               read_buffer, sizeof(read_buffer),
+                               pbRecvBuffer, &dwRecvLength);
+    g_assert_cmpint(status, ==, VREADER_OK);
+    g_assert_cmpint(dwRecvLength, ==, 4);
+    g_assert_cmphex(pbRecvBuffer[2], ==, VCARD7816_SW1_SUCCESS);
+    g_assert_cmphex(pbRecvBuffer[3], ==, 0x00);
+
+    dwLength = (pbRecvBuffer[0] & 0xff) | ((pbRecvBuffer[1] << 8) & 0xff);
+    offset = 0x02;
+    do {
+        /* This returns only success -- get response is needed to get the actual data */
+        dwReadLength = MIN(255, dwLength);
+        dwRecvLength = dwReadLength+2;
+        read_buffer[2] = (unsigned char) ((offset >> 8) & 0xff);
+        read_buffer[3] = (unsigned char) (offset & 0xff);
+        read_buffer[6] = (unsigned char) (dwReadLength);
+        read_buffer[7] = (unsigned char) (dwReadLength);
+        status = vreader_xfr_bytes(reader,
+                                   read_buffer, sizeof(read_buffer),
+                                   pbRecvBuffer, &dwRecvLength);
+        g_assert_cmpint(status, ==, VREADER_OK);
+        g_assert_cmpint(dwRecvLength, ==, dwReadLength + 2);
+        g_assert_cmphex(pbRecvBuffer[dwRecvLength-2], ==, VCARD7816_SW1_SUCCESS);
+        g_assert_cmphex(pbRecvBuffer[dwRecvLength-1], ==, 0x00);
+
+        dwLength -= dwReadLength;
+        offset += dwLength;
+    } while (dwLength != 0);
+}
+
+static void select_aid(VReader *reader, int type)
+{
+    VReaderStatus status;
+    int dwRecvLength = APDUBufSize;
+    uint8_t pbRecvBuffer[APDUBufSize];
+    uint8_t selfile_ccc[] = {
+        /* Select CCC Applet */
+        0x00, 0xa4, 0x04, 0x00, 0x07, 0xa0, 0x00, 0x00, 0x01, 0x16, 0xDB, 0x00
+    };
+    uint8_t selfile_aca[] = {
+        /* Select ACA Applet */
+        0x00, 0xa4, 0x04, 0x00, 0x07, 0xa0, 0x00, 0x00, 0x00, 0x79, 0x03, 0x00
+    };
+    uint8_t selfile_pki[] = {
+        /* Select first PKI Applet */
+        0x00, 0xa4, 0x04, 0x00, 0x07, 0xa0, 0x00, 0x00, 0x00, 0x79, 0x01, 0x00
+    };
+    uint8_t *selfile = NULL;
+    size_t selfile_len = 0;
+
+    switch (type) {
+    case TEST_PKI:
+        selfile = selfile_pki;
+        selfile_len = sizeof(selfile_pki);
+        break;
+
+    case TEST_CCC:
+        selfile = selfile_ccc;
+        selfile_len = sizeof(selfile_ccc);
+        break;
+
+    case TEST_ACA:
+        selfile = selfile_aca;
+        selfile_len = sizeof(selfile_aca);
+        break;
+
+    default:
+        g_assert_not_reached();
+    }
+    g_assert_nonnull(selfile);
+
+    g_assert_nonnull(reader);
+    status = vreader_xfr_bytes(reader,
+                               selfile, selfile_len,
+                               pbRecvBuffer, &dwRecvLength);
+    g_assert_cmpint(status, ==, VREADER_OK);
+    g_assert_cmphex(pbRecvBuffer[dwRecvLength-2], ==, VCARD7816_SW1_RESPONSE_BYTES);
+    g_assert_cmphex(pbRecvBuffer[dwRecvLength-1], >, 0);
+}
+
+static void test_cac_pki(void)
+{
+    VReader *reader = vreader_get_reader_by_id(0);
+
+    /* select the first PKI applet */
+    select_aid(reader, TEST_PKI);
+
+    /* get properties */
+    get_properties(reader, TEST_PKI);
+
+    /* get the TAG buffer length */
+    read_buffer(reader, CAC_FILE_TAG);
+
+    /* get the VALUE buffer length */
+    read_buffer(reader, CAC_FILE_VALUE);
 
-    /* The old way of reading certificate does not work anymore */
+    vreader_free(reader); /* get by id ref */
+}
+
+static void test_cac_ccc(void)
+{
+    VReader *reader = vreader_get_reader_by_id(0);
+
+    /* select the CCC */
+    select_aid(reader, TEST_CCC);
+
+    /* get properties */
+    get_properties(reader, TEST_CCC);
+
+    /* get the TAG buffer length */
+    read_buffer(reader, CAC_FILE_TAG);
+
+    /* get the VALUE buffer length */
+    read_buffer(reader, CAC_FILE_VALUE);
+
+    vreader_free(reader); /* get by id ref */
+}
+
+static void test_cac_aca(void)
+{
+    VReader *reader = vreader_get_reader_by_id(0);
+
+    /* select the ACA */
+    select_aid(reader, TEST_ACA);
+
+    /* get properties */
+    get_properties(reader, TEST_ACA);
+
+    /* get ACR */
+    get_acr(reader);
 
     vreader_free(reader); /* get by id ref */
 }
@@ -192,6 +542,51 @@ static void test_remove(void)
     g_assert_null(reader);
 }
 
+/*
+ * Check that access method without provided buffer returns valid
+ * SW and allow us to get the response with the following APDU
+ */
+static void test_get_response(void)
+{
+    VReader *reader = vreader_get_reader_by_id(0);
+    int dwRecvLength = APDUBufSize;
+    VReaderStatus status;
+    uint8_t pbRecvBuffer[APDUBufSize];
+    uint8_t getresp[] = {
+        /* Get Response (max we can get) */
+        0x00, 0xc0, 0x00, 0x00, 0x00
+    };
+    uint8_t read_buffer[] = {
+        /*Read Buffer  OFFSET         TYPE LENGTH */
+        0x80, 0x52, 0x00, 0x00, 0x02, 0x01, 0x02 /* no L_e */
+    };
+
+    /* select CCC */
+    select_aid(reader, TEST_CCC);
+
+    /* read buffer without response buffer */
+    dwRecvLength = 2;
+    read_buffer[5] = 0x01;
+    status = vreader_xfr_bytes(reader,
+                               read_buffer, sizeof(read_buffer),
+                               pbRecvBuffer, &dwRecvLength);
+    g_assert_cmpint(status, ==, VREADER_OK);
+    g_assert_cmpint(dwRecvLength, ==, 2);
+    g_assert_cmpint(pbRecvBuffer[0], ==, VCARD7816_SW1_RESPONSE_BYTES);
+    g_assert_cmpint(pbRecvBuffer[1], ==, 0x02);
+
+    /* fetch the actual response */
+    dwRecvLength = 4;
+    status = vreader_xfr_bytes(reader,
+                               getresp, sizeof(getresp),
+                               pbRecvBuffer, &dwRecvLength);
+    g_assert_cmpint(status, ==, VREADER_OK);
+    g_assert_cmpint(dwRecvLength, ==, 4);
+    g_assert_cmphex(pbRecvBuffer[2], ==, VCARD7816_SW1_SUCCESS);
+    g_assert_cmphex(pbRecvBuffer[3], ==, 0x00);
+
+    vreader_free(reader); /* get by id ref */
+}
 
 static void libcacard_finalize(void)
 {
@@ -221,7 +616,10 @@ int main(int argc, char *argv[])
     g_test_add_func("/libcacard/list", test_list);
     g_test_add_func("/libcacard/card-remove-insert", test_card_remove_insert);
     g_test_add_func("/libcacard/xfer", test_xfer);
-    g_test_add_func("/libcacard/cac", test_cac);
+    g_test_add_func("/libcacard/cac-pki", test_cac_pki);
+    g_test_add_func("/libcacard/cac-ccc", test_cac_ccc);
+    g_test_add_func("/libcacard/cac-aca", test_cac_aca);
+    g_test_add_func("/libcacard/get-response", test_get_response);
     g_test_add_func("/libcacard/remove", test_remove);
 
     ret = g_test_run();
@@ -231,3 +629,5 @@ int main(int argc, char *argv[])
     libcacard_finalize();
     return ret;
 }
+
+/* vim: set ts=4 sw=4 tw=0 noet expandtab: */
-- 
2.17.1

_______________________________________________
Spice-devel mailing list
Spice-devel@xxxxxxxxxxxxxxxxxxxxx
https://lists.freedesktop.org/mailman/listinfo/spice-devel




[Index of Archives]     [Linux Virtualization]     [Linux Virtualization]     [Linux ARM Kernel]     [Linux ARM]     [Linux Omap]     [Fedora ARM]     [IETF Annouce]     [Security]     [Bugtraq]     [Linux OMAP]     [Linux MIPS]     [ECOS]     [Asterisk Internet PBX]     [Linux API]     [Monitors]