diff --git a/main/rtp.c b/main/rtp.c
index ab55a0590bd9d3429ff0270ddd701c46f649f56e..01f1b078c61e9e6910e08d6a805d8837189dbd9e 100644
--- a/main/rtp.c
+++ b/main/rtp.c
@@ -237,10 +237,34 @@ struct ast_rtcp {
 	int sendfur;
 };
 
+/*!
+ * \brief STUN support code
+ *
+ * This code provides some support for doing STUN transactions.
+ * Eventually it should be moved elsewhere as other protocols
+ * than RTP can benefit from it - e.g. SIP.
+ * STUN is described in RFC3489 and it is based on the exchange
+ * of UDP packets between a client and one or more servers to
+ * determine the externally visible address (and port) of the client
+ * once it has gone through the NAT boxes that connect it to the
+ * outside.
+ * The simplest request packet is just the header defined in
+ * struct stun_header, and from the response we may just look at
+ * one attribute, STUN_MAPPED_ADDRESS, that we find in the response.
+ * By doing more transactions with different server addresses we
+ * may determine more about the behaviour of the NAT boxes, of
+ * course - the details are in the RFC.
+ *
+ * All STUN packets start with a simple header made of a type,
+ * length (excluding the header) and a 16-byte random transaction id.
+ * Following the header we may have zero or more attributes, each
+ * structured as a type, length and a value (whose format depends
+ * on the type, but often contains addresses).
+ * Of course all fields are in network format.
+ */
 
 typedef struct { unsigned int id[4]; } __attribute__((packed)) stun_trans_id;
 
-/* XXX Maybe stun belongs in another file if it ever has use outside of RTP */
 struct stun_header {
 	unsigned short msgtype;
 	unsigned short msglen;
@@ -254,6 +278,9 @@ struct stun_attr {
 	unsigned char value[0];
 } __attribute__((packed));
 
+/*
+ * The format normally used for addresses carried by STUN messages.
+ */
 struct stun_addr {
 	unsigned char unused;
 	unsigned char family;
@@ -264,6 +291,13 @@ struct stun_addr {
 #define STUN_IGNORE		(0)
 #define STUN_ACCEPT		(1)
 
+/*! \brief STUN message types
+ * 'BIND' refers to transactions used to determine the externally
+ * visible addresses. 'SEC' refers to transactions used to establish
+ * a session key for subsequent requests.
+ * 'SEC' functionality is not supported here.
+ */
+ 
 #define STUN_BINDREQ	0x0001
 #define STUN_BINDRESP	0x0101
 #define STUN_BINDERR	0x0111
@@ -271,6 +305,9 @@ struct stun_addr {
 #define STUN_SECRESP	0x0102
 #define STUN_SECERR	0x0112
 
+/*! \brief Basic attribute types in stun messages.
+ * Messages can also contain custom attributes (codes above 0x7fff)
+ */
 #define STUN_MAPPED_ADDRESS	0x0001
 #define STUN_RESPONSE_ADDRESS	0x0002
 #define STUN_CHANGE_REQUEST	0x0003
@@ -283,6 +320,7 @@ struct stun_addr {
 #define STUN_UNKNOWN_ATTRIBUTES	0x000a
 #define STUN_REFLECTED_FROM	0x000b
 
+/*! \brief helper function to print message names */
 static const char *stun_msg2str(int msg)
 {
 	switch (msg) {
@@ -302,6 +340,7 @@ static const char *stun_msg2str(int msg)
 	return "Non-RFC3489 Message";
 }
 
+/*! \brief helper function to print attribute names */
 static const char *stun_attr2str(int msg)
 {
 	switch (msg) {
@@ -331,6 +370,7 @@ static const char *stun_attr2str(int msg)
 	return "Non-RFC3489 Attribute";
 }
 
+/*! \brief here we store credentials extracted from a message */
 struct stun_state {
 	const char *username;
 	const char *password;
@@ -356,6 +396,7 @@ static int stun_process_attr(struct stun_state *state, struct stun_attr *attr)
 	return 0;
 }
 
+/*! \brief append a string to an STUN message */
 static void append_attr_string(struct stun_attr **attr, int attrval, const char *s, int *len, int *left)
 {
 	int size = sizeof(**attr) + strlen(s);
@@ -369,6 +410,7 @@ static void append_attr_string(struct stun_attr **attr, int attrval, const char
 	}
 }
 
+/*! \brief append an address to an STUN message */
 static void append_attr_address(struct stun_attr **attr, int attrval, struct sockaddr_in *sin, int *len, int *left)
 {
 	int size = sizeof(**attr) + 8;
@@ -387,12 +429,14 @@ static void append_attr_address(struct stun_attr **attr, int attrval, struct soc
 	}
 }
 
+/*! \brief wrapper to send an STUN message */
 static int stun_send(int s, struct sockaddr_in *dst, struct stun_header *resp)
 {
 	return sendto(s, resp, ntohs(resp->msglen) + sizeof(*resp), 0,
 		      (struct sockaddr *)dst, sizeof(*dst));
 }
 
+/*! \brief helper function to generate a random request id */
 static void stun_req_id(struct stun_header *req)
 {
 	int x;
@@ -405,6 +449,9 @@ size_t ast_rtp_alloc_size(void)
 	return sizeof(struct ast_rtp);
 }
 
+/*! \brief send a STUN BIND request to the given destination.
+ * Optionally, add a username if specified.
+ */
 void ast_rtp_stun_request(struct ast_rtp *rtp, struct sockaddr_in *suggestion, const char *username)
 {
 	struct stun_header *req;
@@ -426,6 +473,13 @@ void ast_rtp_stun_request(struct ast_rtp *rtp, struct sockaddr_in *suggestion, c
 	stun_send(rtp->s, suggestion, req);
 }
 
+/*! \brief handle an incoming STUN message.
+ *
+ * Do some basic sanity checks on packet size and content,
+ * try to extract a bit of information, and possibly reply.
+ * At the moment this only processes BIND requests, and returns
+ * the externally visible address of the request.
+ */
 static int stun_handle_packet(int s, struct sockaddr_in *src, unsigned char *data, size_t len)
 {
 	struct stun_header *resp, *hdr = (struct stun_header *)data;
@@ -1259,6 +1313,11 @@ struct ast_frame *ast_rtp_read(struct ast_rtp *rtp)
 	/* Check RTP version */
 	version = (seqno & 0xC0000000) >> 30;
 	if (!version) {
+		/* If the two high bits are 0, this might be a
+		 * STUN message, so process it. stun_handle_packet()
+		 * answers to requests, and it returns STUN_ACCEPT
+		 * if the request is valid.
+		 */
 		if ((stun_handle_packet(rtp->s, &sin, rtp->rawdata + AST_FRIENDLY_OFFSET, res) == STUN_ACCEPT) &&
 			(!rtp->them.sin_port && !rtp->them.sin_addr.s_addr)) {
 			memcpy(&rtp->them, &sin, sizeof(rtp->them));