+/****f* silcutil/SilcBufferAPI/silc_buffer_pull_tail
+ *
+ * SYNOPSIS
+ *
+ * static inline
+ * unsigned char *silc_buffer_pull_tail(SilcBuffer sb, SilcUInt32 len);
+ *
+ * DESCRIPTION
+ *
+ * Pulls current tail section towards end. Length of the current valid
+ * data area is also incremented. Returns a pointer to the data area
+ * before pulling. Returns NULL on error.
+ *
+ * EXAMPLE
+ *
+ * ---------------------------------
+ * | head | data | tail |
+ * ---------------------------------
+ * ^
+ * Pulls the start of the tail section.
+ *
+ * ---------------------------------
+ * | head | data | tail |
+ * ---------------------------------
+ * ^
+ *
+ * silc_buffer_pull_tail(sb, 23);
+ *
+ ***/
+
+static inline
+unsigned char *silc_buffer_pull_tail(SilcBuffer sb, SilcUInt32 len)
+{
+ unsigned char *old_tail = sb->tail;
+#if defined(SILC_DEBUG)
+ SILC_ASSERT(len <= silc_buffer_taillen(sb));
+#else
+ if (silc_unlikely(len > silc_buffer_taillen(sb)))
+ return NULL;
+#endif
+ sb->tail += len;
+ return old_tail;
+}
+
+/****f* silcutil/SilcBufferAPI/silc_buffer_push_tail
+ *
+ * SYNOPSIS
+ *
+ * static inline
+ * unsigned char *silc_buffer_push_tail(SilcBuffer sb, SilcUInt32 len);
+ *
+ * DESCRIPTION
+ *
+ * Pushes current tail section towards beginning. Length of the current
+ * valid data area is also decremented. Returns a pointer to the
+ * tail section before pushing. Returns NULL on error.
+ *
+ * EXAMPLE
+ *
+ * ---------------------------------
+ * | head | data | tail |
+ * ---------------------------------
+ * ^
+ * Pushes the start of the tail section.
+ *
+ * ---------------------------------
+ * | head | data | tail |
+ * ---------------------------------
+ * ^
+ *
+ * silc_buffer_push_tail(sb, 23);
+ *
+ ***/
+
+static inline
+unsigned char *silc_buffer_push_tail(SilcBuffer sb, SilcUInt32 len)
+{
+ unsigned char *old_tail = sb->tail;
+#if defined(SILC_DEBUG)
+ SILC_ASSERT((sb->tail - len) >= sb->data);
+#else
+ if (silc_unlikely((sb->tail - len) < sb->data))
+ return NULL;
+#endif
+ sb->tail -= len;
+ return old_tail;
+}
+
+/****f* silcutil/SilcBufferAPI/silc_buffer_put_head
+ *
+ * SYNOPSIS
+ *
+ * static inline
+ * unsigned char *silc_buffer_put_head(SilcBuffer sb,
+ * const unsigned char *data,
+ * SilcUInt32 len);
+ *
+ * DESCRIPTION
+ *
+ * Puts data at the head of the buffer. Returns pointer to the copied
+ * data area. Returns NULL on error.
+ *
+ * EXAMPLE
+ *
+ * ---------------------------------
+ * | head | data | tail |
+ * ---------------------------------
+ * ^
+ * Puts data to the head section.
+ *
+ * silc_buffer_put_head(sb, data, data_len);
+ *
+ ***/
+
+static inline
+unsigned char *silc_buffer_put_head(SilcBuffer sb,
+ const unsigned char *data,
+ SilcUInt32 len)
+{
+#if defined(SILC_DEBUG)
+ SILC_ASSERT(len <= silc_buffer_headlen(sb));
+#else
+ if (silc_unlikely(len > silc_buffer_headlen(sb)))
+ return NULL;
+#endif
+ return (unsigned char *)memcpy(sb->head, data, len);
+}