This defines the message datastructures, the IOCTLs, etc.

Signed-off-by: Tony Ibbs <t...@tonyibbs.co.uk>
---
 include/linux/kbus_defns.h |  613 ++++++++++++++++++++++++++++++++++++++++++++
 1 files changed, 613 insertions(+), 0 deletions(-)
 create mode 100644 include/linux/kbus_defns.h

diff --git a/include/linux/kbus_defns.h b/include/linux/kbus_defns.h
new file mode 100644
index 0000000..d43c498
--- /dev/null
+++ b/include/linux/kbus_defns.h
@@ -0,0 +1,613 @@
+/* Kbus kernel module external headers
+ *
+ * This file provides the definitions (datastructures and ioctls) needed to
+ * communicate with the KBUS character device driver.
+ */
+
+/*
+ * ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is the KBUS Lightweight Linux-kernel mediated
+ * message system
+ *
+ * The Initial Developer of the Original Code is Kynesim, Cambridge UK.
+ * Portions created by the Initial Developer are Copyright (C) 2009
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *   Kynesim, Cambridge UK
+ *   Tony Ibbs <t...@tonyibbs.co.uk>
+ *
+ * Alternatively, the contents of this file may be used under the terms of the
+ * GNU Public License version 2 (the "GPL"), in which case the provisions of
+ * the GPL are applicable instead of the above.  If you wish to allow the use
+ * of your version of this file only under the terms of the GPL and not to
+ * allow others to use your version of this file under the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL.  If you do not delete the
+ * provisions above, a recipient may use your version of this file under either
+ * the MPL or the GPL.
+ *
+ * ***** END LICENSE BLOCK *****
+ */
+
+#ifndef _kbus_defns
+#define _kbus_defns
+
+#if !__KERNEL__ && defined(__cplusplus)
+extern "C" {
+#endif
+
+#if __KERNEL__
+#include <linux/kernel.h>
+#include <linux/ioctl.h>
+#else
+#include <stdint.h>
+#include <sys/ioctl.h>
+#endif
+
+/*
+ * A message id is made up of two fields.
+ *
+ * If the network id is 0, then it is up to us (KBUS) to assign the
+ * serial number. In other words, this is a local message.
+ *
+ * If the network id is non-zero, then this message is presumed to
+ * have originated from another "network", and we preserve both the
+ * network id and the serial number.
+ *
+ * The message id {0,0} is special and reserved (for use by KBUS).
+ */
+struct kbus_msg_id {
+       __u32 network_id;
+       __u32 serial_num;
+};
+
+/*
+ * kbus_orig_from is used for the "originally from" and "finally to" ids
+ * in the message header. These in turn are used when messages are
+ * being sent between KBUS systems (via KBUS "Limpets"). KBUS the kernel
+ * module transmits them, unaltered, but does not use them (although
+ * debug messages may report them).
+ *
+ * An "originally from" or "finally to" id is made up of two fields, the
+ * network id (which indicates the Limpet, if any, that originally gated the
+ * message), and a local id, which is the Ksock id of the original sender
+ * of the message, on its local KBUS.
+ *
+ * If the network id is 0, then the "originally from" id is not being used.
+ *
+ * Limpets and these fields are discussed in more detail in the userspace
+ * KBUS documentation - see http://kbus-messaging.org/ for pointers to
+ * more information.
+ */
+struct kbus_orig_from {
+       __u32 network_id;
+       __u32 local_id;
+};
+
+/* When the user asks to bind a message name to an interface, they use: */
+struct kbus_bind_request {
+       __u32 is_replier;       /* are we a replier? */
+       __u32 name_len;
+       char *name;
+};
+
+/* When the user requests the id of the replier to a message, they use: */
+struct kbus_bind_query {
+       __u32 return_id;
+       __u32 name_len;
+       char *name;
+};
+
+/* When the user writes/reads a message, they use: */
+struct kbus_message_header {
+       /*
+        * The guards
+        * ----------
+        *
+        * * 'start_guard' is notionally "Kbus", and 'end_guard' (the 32 bit
+        *   word after the rest of the message datastructure) is notionally
+        *   "subK". Obviously that depends on how one looks at the 32-bit
+        *   word. Every message datastructure shall start with a start guard
+        *   and end with an end guard.
+        *
+        * These provide some help in checking that a message is well formed,
+        * and in particular the end guard helps to check for broken length
+        * fields.
+        *
+        * - 'id' identifies this particular message.
+        *
+        *   When a user writes a new message, they should set this to {0,0}.
+        *   KBUS will then set a new message id for the message.
+        *
+        *   When a user reads a message, this will have been set by KBUS.
+        *
+        *   When a user replies to a message, they should copy this value
+        *   into the 'in_reply_to' field, so that the recipient will know
+        *   what message this was a reply to.
+        *
+        * - 'in_reply_to' identifies the message this is a reply to.
+        *
+        *   This shall be set to {0,0} unless this message *is* a reply to a
+        *   previous message. In other words, if this value is non-0, then
+        *   the message *is* a reply.
+        *
+        * - 'to' is who the message is to be sent to.
+        *
+        *   When a user writes a new message, this should normally be set
+        *   to {0,0}, meaning "anyone listening" (but see below if "state"
+        *   is being maintained).
+        *
+        *   When replying to a message, it shall be set to the 'from' value
+        *   of the orginal message.
+        *
+        *   When constructing a request message (a message wanting a reply),
+        *   the user can set it to a specific replier id, to produce a stateful
+        *   request. This is normally done by copying the 'from' of a previous
+        *   Reply from the appropriate replier. When such a message is sent,
+        *   if the replier bound (at that time) does not have that specific
+        *   id, then the send will fail.
+        *
+        *   Note that if 'to' is set, then 'orig_from' should also be set.
+        *
+        * - 'from' indicates who sent the message.
+        *
+        *   When a user is writing a new message, they should set this
+        *   to {0,0}.
+        *
+        *   When a user is reading a message, this will have been set
+        *   by KBUS.
+        *
+        *   When a user replies to a message, the reply should have its
+        *   'to' set to the original messages 'from', and its 'from' set
+        *   to {0,0} (see the "hmm" caveat under 'to' above, though).
+        *
+        * - 'orig_from' and 'final_to' are used when Limpets are mediating
+        *   KBUS messages between KBUS devices (possibly on different
+        *   machines). See the description by the datastructure definition
+        *   above. The KBUS kernel preserves and propagates their values,
+        *   but does not alter or use them.
+        *
+        * - 'extra' is currently unused, and KBUS will set it to zero.
+        *   Future versions of KBUS may treat it differently.
+        *
+        * - 'flags' indicates the type of message.
+        *
+        *   When a user writes a message, this can be used to indicate
+        *   that:
+        *
+        *   * the message is URGENT
+        *   * a reply is wanted
+        *
+        *   When a user reads a message, this indicates if:
+        *
+        *   * the message is URGENT
+        *   * a reply is wanted
+        *
+        *   When a user writes a reply, this field should be set to 0.
+        *
+        *   The top half of the 'flags' is not touched by KBUS, and may
+        *   be used for any purpose the user wishes.
+        *
+        * - 'name_len' is the length of the message name in bytes.
+        *
+        *   This must be non-zero.
+        *
+        * - 'data_len' is the length of the message data in bytes. It may be
+        *   zero if there is no data.
+        *
+        * - 'name' is a pointer to the message name. This should be null
+        *   terminated, as is the normal case for C strings.
+        *
+        *   NB: If this is zero, then the name will be present, but after
+        *   the end of this datastructure, and padded out to a multiple of
+        *   four bytes (see kbus_entire_message). When doing this padding,
+        *   remember to allow for the terminating null byte. If this field is
+        *   zero, then 'data' shall also be zero.
+        *
+        * - 'data' is a pointer to the data. If there is no data (if
+        *   'data_len' is zero), then this shall also be zero. The data is
+        *   not touched by KBUS, and may include any values.
+        *
+        *   NB: If this is zero, then the data will occur immediately
+        *   after the message name, padded out to a multiple of four bytes.
+        *   See the note for 'name' above.
+        *
+        */
+       __u32 start_guard;
+       struct kbus_msg_id id;  /* Unique to this message */
+       struct kbus_msg_id in_reply_to; /* Which message this is a reply to */
+       __u32 to;               /* 0 (empty) or a replier id */
+       __u32 from;             /* 0 (KBUS) or the sender's id */
+       struct kbus_orig_from orig_from;/* Cross-network linkage */
+       struct kbus_orig_from final_to; /* Cross-network linkage */
+       __u32 extra;    /* ignored field - future proofing */
+       __u32 flags;    /* Message type/flags */
+       __u32 name_len; /* Message name's length, in bytes */
+       __u32 data_len; /* Message length, also in bytes */
+       char *name;
+       void *data;
+       __u32 end_guard;
+};
+
+#define KBUS_MSG_START_GUARD   0x7375624B
+#define KBUS_MSG_END_GUARD     0x4B627573
+
+/*
+ * When a message is returned by 'read', it is actually returned using the
+ * following datastructure, in which:
+ *
+ * - 'header.name' will point to 'rest[0]'
+ * - 'header.data' will point to 'rest[(header.name_len+3)/4]'
+ *
+ * followed by the name (padded to 4 bytes, remembering to allow for the
+ * terminating null byte), followed by the data (padded to 4 bytes) followed by
+ * (another) end_guard.
+ */
+struct kbus_entire_message {
+       struct kbus_message_header header;
+       __u32 rest[];
+};
+
+/*
+ * We limit a message name to at most 1000 characters (some limit seems
+ * sensible, after all)
+ */
+#define KBUS_MAX_NAME_LEN      1000
+
+/*
+ * The length (in bytes) of the name after padding, allowing for a terminating
+ * null byte.
+ */
+#define KBUS_PADDED_NAME_LEN(name_len)   (4 * ((name_len + 1 + 3) / 4))
+
+/*
+ * The length (in bytes) of the data after padding
+ */
+#define KBUS_PADDED_DATA_LEN(data_len)   (4 * ((data_len + 3) / 4))
+
+/*
+ * Given name_len (in bytes) and data_len (in bytes), return the
+ * length of the appropriate kbus_entire_message_struct, in bytes
+ *
+ * Note that we're allowing for a zero byte after the end of the message name.
+ *
+ * Remember that "sizeof" doesn't count the 'rest' field in our message
+ * structure.
+ */
+#define KBUS_ENTIRE_MSG_LEN(name_len, data_len)    \
+       (sizeof(struct kbus_entire_message) + \
+        KBUS_PADDED_NAME_LEN(name_len) + \
+        KBUS_PADDED_DATA_LEN(data_len) + 4)
+
+/*
+ * The message name starts at entire->rest[0].
+ * The message data starts after the message name - given the message
+ * name's length (in bytes), that is at index:
+ */
+#define KBUS_ENTIRE_MSG_DATA_INDEX(name_len)     ((name_len+1+3)/4)
+/*
+ * Given the message name length (in bytes) and the message data length (also
+ * in bytes), the index of the entire message end guard is thus:
+ */
+#define KBUS_ENTIRE_MSG_END_GUARD_INDEX(name_len, data_len)  \
+       ((name_len+1+3)/4 + (data_len+3)/4)
+
+/*
+ * Find a pointer to the message's name.
+ *
+ * It's either the given name pointer, or just after the header (if the pointer
+ * is NULL)
+ */
+static inline char *kbus_msg_name_ptr(const struct kbus_message_header
+                                     *hdr)
+{
+       if (hdr->name) {
+               return hdr->name;
+       } else {
+               struct kbus_entire_message *entire;
+               entire = (struct kbus_entire_message *)hdr;
+               return (char *)&entire->rest[0];
+       }
+}
+
+/*
+ * Find a pointer to the message's data.
+ *
+ * It's either the given data pointer, or just after the name (if the pointer
+ * is NULL)
+ */
+static inline void *kbus_msg_data_ptr(const struct kbus_message_header
+                                     *hdr)
+{
+       if (hdr->data) {
+               return hdr->data;
+       } else {
+               struct kbus_entire_message *entire;
+               __u32 data_idx;
+
+               entire = (struct kbus_entire_message *)hdr;
+               data_idx = KBUS_ENTIRE_MSG_DATA_INDEX(hdr->name_len);
+               return (void *)&entire->rest[data_idx];
+       }
+}
+
+/*
+ * Find a pointer to the message's (second/final) end guard.
+ */
+static inline __u32 *kbus_msg_end_ptr(struct kbus_entire_message
+                                        *entire)
+{
+       __u32 end_guard_idx =
+               KBUS_ENTIRE_MSG_END_GUARD_INDEX(entire->header.name_len,
+                                               entire->header.data_len);
+       return (__u32 *) &entire->rest[end_guard_idx];
+}
+
+/*
+ * Things KBUS changes in a message
+ * --------------------------------
+ * In general, KBUS leaves the content of a message alone. However, it does
+ * change:
+ *
+ * - the message id (if id.network_id is unset - it assigns a new serial
+ *   number unique to this message)
+ * - the from id (if from.network_id is unset - it sets the local_id to
+ *   indicate the Ksock this message was sent from)
+ * - the KBUS_BIT_WANT_YOU_TO_REPLY bit in the flags (set or cleared
+ *   as appropriate)
+ * - the SYNTHETIC bit, which KBUS will always unset in a user message
+ */
+
+/*
+ * Flags for the message 'flags' word
+ * ----------------------------------
+ * The KBUS_BIT_WANT_A_REPLY bit is set by the sender to indicate that a
+ * reply is wanted. This makes the message into a request.
+ *
+ *     Note that setting the WANT_A_REPLY bit (i.e., a request) and
+ *     setting 'in_reply_to' (i.e., a reply) is bound to lead to
+ *     confusion, and the results are undefined (i.e., don't do it).
+ *
+ * The KBUS_BIT_WANT_YOU_TO_REPLY bit is set by KBUS on a particular message
+ * to indicate that the particular recipient is responsible for replying
+ * to (this instance of the) message. Otherwise, KBUS clears it.
+ *
+ * The KBUS_BIT_SYNTHETIC bit is set by KBUS when it generates a synthetic
+ * message (an exception, if you will), for instance when a replier has
+ * gone away and therefore a reply will never be generated for a request
+ * that has already been queued.
+ *
+ *     Note that KBUS does not check that a sender has not set this
+ *     on a message, but doing so may lead to confusion.
+ *
+ * The KBUS_BIT_URGENT bit is set by the sender if this message is to be
+ * treated as urgent - i.e., it should be added to the *front* of the
+ * recipient's message queue, not the back.
+ *
+ * Send flags
+ * ==========
+ * There are two "send" flags, KBUS_BIT_ALL_OR_WAIT and KBUS_BIT_ALL_OR_FAIL.
+ * Either one may be set, or both may be unset.
+ *
+ *    If both bits are set, the message will be rejected as invalid.
+ *
+ *    Both flags are ignored in reply messages (i.e., messages with the
+ *    'in_reply_to' field set).
+ *
+ * If both are unset, then a send will behave in the default manner. That is,
+ * the message will be added to a listener's queue if there is room but
+ * otherwise the listener will (silently) not receive the message.
+ *
+ *     (Obviously, if the listener is a replier, and the message is a request,
+ *     then a KBUS message will be synthesised in the normal manner when a
+ *     request is lost.)
+ *
+ * If the KBUS_BIT_ALL_OR_WAIT bit is set, then a send should block until
+ * all recipients can be sent the message. Specifically, before the message is
+ * sent, all recipients must have room on their message queues for this
+ * message, and if they do not, the send will block until there is room for the
+ * message on all the queues.
+ *
+ * If the KBUS_BIT_ALL_OR_FAIL bit is set, then a send should fail if all
+ * recipients cannot be sent the message. Specifically, before the message is
+ * sent, all recipients must have room on their message queues for this
+ * message, and if they do not, the send will fail.
+ */
+
+/*
+ * When a $.KBUS.ReplierBindEvent message is constructed, we use the
+ * following to encapsulate its data.
+ *
+ * This indicates whether it is a bind or unbind event, who is doing the
+ * bind or unbind, and for what message name. The message name is padded
+ * out to a multiple of four bytes, allowing for a terminating null byte,
+ * but the name length is the length without said padding (so, in C terms,
+ * strlen(name)).
+ *
+ * As for the message header data structure, the actual data "goes off the end"
+ * of the datastructure.
+ */
+struct kbus_replier_bind_event_data {
+       __u32 is_bind;  /* 1=bind, 0=unbind */
+       __u32 binder;   /* Ksock id of binder */
+       __u32 name_len; /* Length of name */
+       __u32 rest[];   /* Message name */
+};
+
+#if !__KERNEL__
+#define BIT(num)                 (((unsigned)1) << (num))
+#endif
+
+#define        KBUS_BIT_WANT_A_REPLY           BIT(0)
+#define KBUS_BIT_WANT_YOU_TO_REPLY     BIT(1)
+#define KBUS_BIT_SYNTHETIC             BIT(2)
+#define KBUS_BIT_URGENT                        BIT(3)
+
+#define KBUS_BIT_ALL_OR_WAIT           BIT(8)
+#define KBUS_BIT_ALL_OR_FAIL           BIT(9)
+
+/*
+ * Standard message names
+ * ======================
+ * KBUS itself has some predefined message names.
+ *
+ * Synthetic Replies with no data
+ * ------------------------------
+ * These are sent to the original Sender of a Request when KBUS knows that the
+ * Replier is not going to Reply. In all cases, you can identify which message
+ * they concern by looking at the "in_reply_to" field:
+ *
+ * * Replier.GoneAway - the Replier has gone away before reading the Request.
+ * * Replier.Ignored - the Replier has gone away after reading a Request, but
+ *   before replying to it.
+ * * Replier.Unbound - the Replier has unbound (as Replier) from the message
+ *   name, and is thus not going to reply to this Request in its unread message
+ *   queue.
+ * * Replier.Disappeared - the Replier has disappeared when an attempt is made
+ *   to send a Request whilst polling (i.e., after EAGAIN was returned from an
+ *   earlier attempt to send a message). This typically means that the Ksock
+ *   bound as Replier closed.
+ * * ErrorSending - an unexpected error occurred when trying to send a Request
+ *   to its Replier whilst polling.
+ */
+#define KBUS_MSG_NAME_REPLIER_GONEAWAY         "$.KBUS.Replier.GoneAway"
+#define KBUS_MSG_NAME_REPLIER_IGNORED          "$.KBUS.Replier.Ignored"
+#define KBUS_MSG_NAME_REPLIER_UNBOUND          "$.KBUS.Replier.Unbound"
+#define KBUS_MSG_NAME_REPLIER_DISAPPEARED      "$.KBUS.Replier.Disappeared"
+#define KBUS_MSG_NAME_ERROR_SENDING            "$.KBUS.ErrorSending"
+
+#define KBUS_IOC_MAGIC 'k'     /* 0x6b - which seems fair enough for now */
+/*
+ * RESET: reserved for future use
+ */
+#define KBUS_IOC_RESET     _IO(KBUS_IOC_MAGIC,  1)
+/*
+ * BIND - bind a Ksock to a message name
+ * arg: struct kbus_bind_request, indicating what to bind to
+ * retval: 0 for success, negative for failure
+ */
+#define KBUS_IOC_BIND     _IOW(KBUS_IOC_MAGIC,  2, char *)
+/*
+ * UNBIND - unbind a Ksock from a message id
+ * arg: struct kbus_bind_request, indicating what to unbind from
+ * retval: 0 for success, negative for failure
+ */
+#define KBUS_IOC_UNBIND           _IOW(KBUS_IOC_MAGIC,  3, char *)
+/*
+ * KSOCKID - determine a Ksock's Ksock id
+ *
+ * The network_id for the current Ksock is, by definition, 0, so we don't need
+ * to return it.
+ *
+ * arg (out): __u32, indicating this Ksock's local_id
+ * retval: 0 for success, negative for failure
+ */
+#define KBUS_IOC_KSOCKID   _IOR(KBUS_IOC_MAGIC,  4, char *)
+/*
+ * REPLIER - determine the Ksock id of the replier for a message name
+ * arg: struct kbus_bind_query
+ *
+ *    - on input, specify the message name to ask about.
+ *    - on output, KBUS fills in the relevant Ksock id in the return_value,
+ *      or 0 if there is no bound replier
+ *
+ * retval: 0 for success, negative for failure
+ */
+#define KBUS_IOC_REPLIER  _IOWR(KBUS_IOC_MAGIC,  5, char *)
+/*
+ * NEXTMSG - pop the next message from the read queue
+ * arg (out): __u32, number of bytes in the next message, 0 if there is no
+ *            next message
+ * retval: 0 for success, negative for failure
+ */
+#define KBUS_IOC_NEXTMSG   _IOR(KBUS_IOC_MAGIC,  6, char *)
+/*
+ * LENLEFT - determine how many bytes are left to read of the current message
+ * arg (out): __u32, number of bytes left, 0 if there is no current read
+ *            message
+ * retval: 1 if there was a message, 0 if there wasn't, negative for failure
+ */
+#define KBUS_IOC_LENLEFT   _IOR(KBUS_IOC_MAGIC,  7, char *)
+/*
+ * SEND - send the current message
+ * arg (out): struct kbus_msg_id, the message id of the sent message
+ * retval: 0 for success, negative for failure
+ */
+#define KBUS_IOC_SEND     _IOR(KBUS_IOC_MAGIC,  8, char *)
+/*
+ * DISCARD - discard the message currently being written (if any)
+ * arg: none
+ * retval: 0 for success, negative for failure
+ */
+#define KBUS_IOC_DISCARD    _IO(KBUS_IOC_MAGIC,  9)
+/*
+ * LASTSENT - determine the message id of the last message SENT
+ * arg (out): struct kbus_msg_id, {0,0} if there was no last message
+ * retval: 0 for success, negative for failure
+ */
+#define KBUS_IOC_LASTSENT  _IOR(KBUS_IOC_MAGIC, 10, char *)
+/*
+ * MAXMSGS - set the maximum number of messages on a Ksock read queue
+ * arg (in): __u32, the requested length of the read queue, or 0 to just
+ *           request how many there are
+ * arg (out): __u32, the length of the read queue after this call has
+ *            succeeded
+ * retval: 0 for success, negative for failure
+ */
+#define KBUS_IOC_MAXMSGS  _IOWR(KBUS_IOC_MAGIC, 11, char *)
+/*
+ * NUMMSGS - determine how many messages are in the read queue for this Ksock
+ * arg (out): __u32, the number of messages in the read queue.
+ * retval: 0 for success, negative for failure
+ */
+#define KBUS_IOC_NUMMSGS   _IOR(KBUS_IOC_MAGIC, 12, char *)
+/*
+ * UNREPLIEDTO - determine the number of requests (marked "WANT_YOU_TO_REPLY")
+ * which we still need to reply to.
+ * arg(out): __u32, said number
+ * retval: 0 for success, negative for failure
+ */
+#define KBUS_IOC_UNREPLIEDTO _IOR(KBUS_IOC_MAGIC, 13, char *)
+
+/*
+ * IOCTL 14 is not used, because it is introduced in the next revision,
+ * (obviously, in real history this was done in a different order) and
+ * I don't want to alter the number for VERBOSE.
+ */
+
+/*
+ * VERBOSE - should KBUS output verbose "printk" messages (for this device)?
+ *
+ * This IOCTL tells a Ksock whether it should output debugging messages. It is
+ * only effective if the kernel module has been built with the 
VERBOSE_DEBUGGING
+ * flag set.
+ *
+ * arg(in): __u32, 1 to change to "verbose", 0 to change to "quiet",
+ * 0xFFFFFFFF to just return the current/previous state.
+ * arg(out): __u32, the previous state.
+ * retval: 0 for success, negative for failure (-EINVAL if arg in was not one
+ * of the specified values)
+ */
+#define KBUS_IOC_VERBOSE  _IOWR(KBUS_IOC_MAGIC, 15, char *)
+
+/* If adding another IOCTL, remember to increment the next number! */
+#define KBUS_IOC_MAXNR 15
+
+#if !__KERNEL__ && defined(__cplusplus)
+}
+#endif
+
+#endif /* _kbus_defns */
-- 
1.7.4.1

--
To unsubscribe from this list: send the line "unsubscribe linux-embedded" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to