Merge "net: ipc_router: Add Optional header in IPC Router V2"

This commit is contained in:
Linux Build Service Account 2015-06-23 13:30:30 -07:00 committed by Gerrit - the friendly Code Review server
commit beb3684a67
2 changed files with 88 additions and 14 deletions

View File

@ -1,4 +1,4 @@
/* Copyright (c) 2011-2014, The Linux Foundation. All rights reserved.
/* Copyright (c) 2011-2015, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@ -54,6 +54,7 @@ struct rr_header_v1 {
* @version: Version information.
* @type: IPC Router Message Type.
* @control_flag: Flags to indicate flow control, optional header etc.
* @opt_len: Combined size of the all optional headers in units of words.
* @size: Size of the IPC Router payload.
* @src_node_id: Source Node ID of the message.
* @src_port_id: Source Port ID of the message.
@ -63,7 +64,8 @@ struct rr_header_v1 {
struct rr_header_v2 {
uint8_t version;
uint8_t type;
uint16_t control_flag;
uint8_t control_flag;
uint8_t opt_len;
uint32_t size;
uint16_t src_node_id;
uint16_t src_port_id;
@ -76,18 +78,31 @@ union rr_header {
struct rr_header_v2 hdr_v2;
};
/**
* rr_opt_hdr - Optional header for IPC Router header version 2
* @len: Total length of the optional header.
* @data: Pointer to the actual optional header.
*/
struct rr_opt_hdr {
size_t len;
unsigned char *data;
};
#define IPC_ROUTER_HDR_SIZE sizeof(union rr_header)
#define IPCR_WORD_SIZE 4
/**
* rr_packet - Router to Router packet structure
* @list: Pointer to prev & next packets in a port's rx list.
* @hdr: Header information extracted from or prepended to a packet.
* @opt_hdr: Optinal header information.
* @pkt_fragment_q: Queue of SKBs containing payload.
* @length: Length of data in the chain of SKBs
*/
struct rr_packet {
struct list_head list;
struct rr_header_v1 hdr;
struct rr_opt_hdr opt_hdr;
struct sk_buff_head *pkt_fragment_q;
uint32_t length;
};

View File

@ -500,7 +500,17 @@ struct rr_packet *clone_pkt(struct rr_packet *pkt)
return NULL;
}
memcpy(&(cloned_pkt->hdr), &(pkt->hdr), sizeof(struct rr_header_v1));
/* TODO: Copy optional headers, if available */
if (pkt->opt_hdr.len > 0) {
cloned_pkt->opt_hdr.data = kmalloc(pkt->opt_hdr.len,
GFP_KERNEL);
if (!cloned_pkt->opt_hdr.data) {
IPC_RTR_ERR("%s: Memory allocation Failed\n", __func__);
} else {
cloned_pkt->opt_hdr.len = pkt->opt_hdr.len;
memcpy(cloned_pkt->opt_hdr.data, pkt->opt_hdr.data,
pkt->opt_hdr.len);
}
}
pkt_fragment_q = kmalloc(sizeof(struct sk_buff_head), GFP_KERNEL);
if (!pkt_fragment_q) {
@ -526,7 +536,8 @@ fail_clone:
kfree_skb(temp_skb);
}
kfree(pkt_fragment_q);
/* TODO: Free optional headers, if present */
if (cloned_pkt->opt_hdr.len > 0)
kfree(cloned_pkt->opt_hdr.data);
kfree(cloned_pkt);
return NULL;
}
@ -583,7 +594,8 @@ void release_pkt(struct rr_packet *pkt)
kfree_skb(temp_skb);
}
kfree(pkt->pkt_fragment_q);
/* TODO: Free Optional headers, if present */
if (pkt->opt_hdr.len > 0)
kfree(pkt->opt_hdr.data);
kfree(pkt);
return;
}
@ -692,6 +704,42 @@ void msm_ipc_router_free_skb(struct sk_buff_head *skb_head)
kfree(skb_head);
}
/**
* extract_optional_header() - Extract the optional header from skb
* @pkt: Packet structure into which the header has to be extracted.
* @opt_len: The optional header length in word size.
*
* @return: Length of optional header in bytes if success, zero otherwise.
*/
static int extract_optional_header(struct rr_packet *pkt, uint8_t opt_len)
{
size_t offset = 0, buf_len = 0, copy_len, opt_hdr_len;
struct sk_buff *temp;
struct sk_buff_head *skb_head;
opt_hdr_len = opt_len * IPCR_WORD_SIZE;
pkt->opt_hdr.data = kmalloc(opt_hdr_len, GFP_KERNEL);
if (!pkt->opt_hdr.data) {
IPC_RTR_ERR("%s: Memory allocation Failed\n", __func__);
return 0;
}
skb_head = pkt->pkt_fragment_q;
buf_len = opt_hdr_len;
skb_queue_walk(skb_head, temp) {
copy_len = buf_len < temp->len ? buf_len : temp->len;
memcpy(pkt->opt_hdr.data + offset, temp->data, copy_len);
offset += copy_len;
buf_len -= copy_len;
skb_pull(temp, copy_len);
if (temp->len == 0) {
skb_dequeue(skb_head);
kfree_skb(temp);
}
}
pkt->opt_hdr.len = opt_hdr_len;
return opt_hdr_len;
}
/**
* extract_header_v1() - Extract IPC Router header of version 1
* @pkt: Packet structure into which the header has to be extraced.
@ -722,6 +770,9 @@ static int extract_header_v1(struct rr_packet *pkt, struct sk_buff *skb)
static int extract_header_v2(struct rr_packet *pkt, struct sk_buff *skb)
{
struct rr_header_v2 *hdr;
uint8_t opt_len;
size_t opt_hdr_len;
size_t total_hdr_size = sizeof(*hdr);
if (!pkt || !skb) {
IPC_RTR_ERR("%s: Invalid pkt or skb\n", __func__);
@ -737,8 +788,13 @@ static int extract_header_v2(struct rr_packet *pkt, struct sk_buff *skb)
pkt->hdr.control_flag = (uint32_t)hdr->control_flag;
pkt->hdr.dst_node_id = (uint32_t)hdr->dst_node_id;
pkt->hdr.dst_port_id = (uint32_t)hdr->dst_port_id;
skb_pull(skb, sizeof(struct rr_header_v2));
pkt->length -= sizeof(struct rr_header_v2);
opt_len = hdr->opt_len;
skb_pull(skb, total_hdr_size);
if (opt_len > 0) {
opt_hdr_len = extract_optional_header(pkt, opt_len);
total_hdr_size += opt_hdr_len;
}
pkt->length -= total_hdr_size;
return 0;
}
@ -771,7 +827,6 @@ static int extract_header(struct rr_packet *pkt)
ret = extract_header_v1(pkt, temp_skb);
} else if (temp_skb->data[0] == IPC_ROUTER_V2) {
ret = extract_header_v2(pkt, temp_skb);
/* TODO: Extract optional headers if present */
} else {
IPC_RTR_ERR("%s: Invalid Header version %02x\n",
__func__, temp_skb->data[0]);
@ -814,8 +869,7 @@ static int calc_tx_header_size(struct rr_packet *pkt,
hdr_size = sizeof(struct rr_header_v1);
} else if (xprt_version == IPC_ROUTER_V2) {
pkt->hdr.version = IPC_ROUTER_V2;
hdr_size = sizeof(struct rr_header_v2);
/* TODO: Calculate optional header length, if present */
hdr_size = sizeof(struct rr_header_v2) + pkt->opt_hdr.len;
} else {
IPC_RTR_ERR("%s: Invalid xprt_version %d\n",
__func__, xprt_version);
@ -923,13 +977,18 @@ static int prepend_header_v2(struct rr_packet *pkt, int hdr_size)
hdr = (struct rr_header_v2 *)skb_push(temp_skb, hdr_size);
hdr->version = (uint8_t)pkt->hdr.version;
hdr->type = (uint8_t)pkt->hdr.type;
hdr->control_flag = (uint16_t)pkt->hdr.control_flag;
hdr->control_flag = (uint8_t)pkt->hdr.control_flag;
hdr->size = (uint32_t)pkt->hdr.size;
hdr->src_node_id = (uint16_t)pkt->hdr.src_node_id;
hdr->src_port_id = (uint16_t)pkt->hdr.src_port_id;
hdr->dst_node_id = (uint16_t)pkt->hdr.dst_node_id;
hdr->dst_port_id = (uint16_t)pkt->hdr.dst_port_id;
/* TODO: Add optional headers, if present */
if (pkt->opt_hdr.len > 0) {
hdr->opt_len = pkt->opt_hdr.len/IPCR_WORD_SIZE;
memcpy(hdr + sizeof(*hdr), pkt->opt_hdr.data, pkt->opt_hdr.len);
} else {
hdr->opt_len = 0;
}
if (temp_skb != skb_peek(pkt->pkt_fragment_q))
skb_queue_head(pkt->pkt_fragment_q, temp_skb);
pkt->length += hdr_size;
@ -1088,13 +1147,13 @@ int ipc_router_peek_pkt_size(char *data)
return -EINVAL;
}
/* FUTURE: Calculate optional header len in V2 header*/
if (data[0] == IPC_ROUTER_V1)
size = ((struct rr_header_v1 *)data)->size +
sizeof(struct rr_header_v1);
else if (data[0] == IPC_ROUTER_V2)
size = ((struct rr_header_v2 *)data)->size +
sizeof(struct rr_header_v2);
((struct rr_header_v2 *)data)->opt_len * IPCR_WORD_SIZE
+ sizeof(struct rr_header_v2);
else
return -EINVAL;