Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 742c663a authored by Ravinder Konka's avatar Ravinder Konka Committed by Gerrit - the friendly Code Review server
Browse files

netfilter: Enable/Disable SIP Segmentation Support



Add a proc entry to enable or disable SIP segmentation
support.

Change-Id: I0e2fdc7dfa43f5d1cc00daa5c3103231c979ac43
Signed-off-by: default avatarRavinder Konka <rkonka@codeaurora.org>
parent 2bb491da
Loading
Loading
Loading
Loading
+105 −49
Original line number Diff line number Diff line
@@ -58,7 +58,12 @@ EXPORT_SYMBOL(nf_nat_sip_hooks);
static struct ctl_table_header *sip_sysctl_header;
static unsigned nf_ct_disable_sip_alg;
static int sip_direct_media = 1;
static unsigned nf_ct_enable_sip_segmentation;
static int packet_count;
static
int proc_sip_segment(struct ctl_table *ctl, int write,
		     void __user *buffer, size_t *lenp, loff_t *ppos);

static struct ctl_table sip_sysctl_tbl[] = {
	{
		.procname     = "nf_conntrack_disable_sip_alg",
@@ -74,6 +79,13 @@ static struct ctl_table sip_sysctl_tbl[] = {
		.mode         = 0644,
		.proc_handler = proc_dointvec,
	},
	{
		.procname     = "nf_conntrack_enable_sip_segmentation",
		.data         = &nf_ct_enable_sip_segmentation,
		.maxlen       = sizeof(unsigned int),
		.mode         = 0644,
		.proc_handler = proc_sip_segment,
	},
	{}
};

@@ -81,6 +93,36 @@ unsigned int (*nf_nat_sip_hook)(struct sk_buff *skb, unsigned int protoff,
				unsigned int dataoff, const char **dptr,
				unsigned int *datalen) __read_mostly;

static void sip_calculate_parameters(s16 *diff, s16 *tdiff,
				     unsigned int *dataoff, const char **dptr,
				     unsigned int *datalen,
				     unsigned int msglen, unsigned int origlen)
{
	*diff	 = msglen - origlen;
	*tdiff	+= *diff;
	*dataoff += msglen;
	*dptr	+= msglen;
	*datalen  = *datalen + *diff - msglen;
}

static void sip_update_params(enum ip_conntrack_dir dir,
			      unsigned int *msglen, unsigned int *origlen,
			      const char **dptr, unsigned int *datalen,
			      bool skb_is_combined, struct nf_conn *ct)
{
	if (skb_is_combined) {
		/* The msglen of first skb has the total msg length of
		 * the two fragments. hence after combining,we update
		 * the msglen to that of the msglen of first skb
		 */
		*msglen = (dir == IP_CT_DIR_ORIGINAL) ?
		  ct->segment.msg_length[0] : ct->segment.msg_length[1];
		*origlen = *msglen;
		*dptr = ct->dptr_prev;
		*datalen = *msglen;
	}
}

/* This function is to save all the information of the first segment
 * that will be needed for combining the two segments
 */
@@ -197,6 +239,7 @@ static struct sip_list *sip_coalesce_segments(struct nf_conn *ct,
				if (skb_try_coalesce(sip_entry->entry->skb,
						     *skb_ref, &fragstolen,
							&delta_truesize)) {
					pr_debug(" Combining segments\n");
					*combined_skb_ref =
							  sip_entry->entry->skb;
					*success = true;
@@ -323,6 +366,23 @@ static const struct nf_queue_handler nf_sip_qh = {
	.outfn	= &nf_sip_enqueue_packet,
};

static
int proc_sip_segment(struct ctl_table *ctl, int write,
		     void __user *buffer, size_t *lenp, loff_t *ppos)
{
	int ret;

	ret = proc_dointvec(ctl, write, buffer, lenp, ppos);
	if (nf_ct_enable_sip_segmentation) {
		pr_debug("registering queue handler\n");
		nf_register_queue_handler(&nf_sip_qh);
	} else {
		pr_debug("de-registering queue handler\n");
		nf_unregister_queue_handler();
	}
	return ret;
}

static int digits_len(const struct nf_conn *ct, const char *dptr,
		      const char *limit, int *shift)
{
@@ -1799,9 +1859,13 @@ static int sip_help_tcp(struct sk_buff *skb, unsigned int protoff,
		if (ct_sip_get_header(ct, dptr, 0, datalen,
				      SIP_HDR_CONTENT_LENGTH,
				      &matchoff, &matchlen) <= 0){
			if (nf_ct_enable_sip_segmentation) {
				do_not_process = true;
				content_len_exists = 0;
				goto destination;
			} else {
				break;
			}
		}

		clen = simple_strtoul(dptr + matchoff, (char **)&end, 10);
@@ -1829,13 +1893,15 @@ destination:
			origlen = end - dptr;
			msglen = origlen;
		}
		pr_debug("mslgen %d datalen %d\n", msglen, datalen);
		dir = CTINFO2DIR(ctinfo);
		combined_skb = skb;

		if (nf_ct_enable_sip_segmentation) {
			/* Segmented Packet */
			if (msglen > datalen) {
			skip = sip_save_segment_info(ct, skb, msglen, datalen,
						     dptr, ctinfo);
				skip = sip_save_segment_info(ct, skb, msglen,
							     datalen, dptr,
							     ctinfo);
				if (!skip)
					return NF_QUEUE;
			}
@@ -1843,31 +1909,28 @@ destination:
			/*Traverse the list if list non empty */
			if (((&ct->sip_segment_list)->next) !=
				(&ct->sip_segment_list)) {
			/* Combine segments if they are fragments of the same
			 * message.
				/* Combine segments if they are fragments of
				 *  the same message.
				*/
			sip_entry = sip_coalesce_segments(ct,
							  &skb, dataoff,
				sip_entry = sip_coalesce_segments(ct, &skb,
								  dataoff,
								  &combined_skb,
					&skip_sip_process, do_not_process,
					ctinfo, &skb_is_combined);
							&skip_sip_process,
								do_not_process,
								  ctinfo,
							&skb_is_combined);
				sip_update_params(dir, &msglen, &origlen, &dptr,
						  &datalen,
						  skb_is_combined, ct);

		if (skb_is_combined) {
			/* The msglen of first skb has the total msg length of
			 * the two fragments. hence after combining,we update
			 * the msglen to that of the msglen of first skb
			 */
			msglen = (dir == IP_CT_DIR_ORIGINAL) ?
			ct->segment.msg_length[0] : ct->segment.msg_length[1];
			origlen = msglen;
			dptr = ct->dptr_prev;
			datalen = msglen;
		}
				if (skip_sip_process)
					goto here;
				} else if (do_not_process) {
					goto here;
				}
		} else if (msglen > datalen) {
			return NF_ACCEPT;
		}
		/* process the combined skb having the complete SIP message */
		ret = process_sip_msg(combined_skb, ct, protoff, dataoff,
				      &dptr, &msglen);
@@ -1875,13 +1938,9 @@ destination:
		/* process_sip_* functions report why this packet is dropped */
		if (ret != NF_ACCEPT)
			break;

		diff	 = msglen - origlen;
		tdiff	+= diff;
		dataoff += msglen;
		dptr	+= msglen;
		datalen  = datalen + diff - msglen;
		if (skb_is_combined)
		sip_calculate_parameters(&diff, &tdiff, &dataoff, &dptr,
					 &datalen, msglen, origlen);
		if (nf_ct_enable_sip_segmentation && skb_is_combined)
			break;
	}
	if (skb_is_combined) {
@@ -2058,9 +2117,6 @@ static int __init nf_conntrack_sip_init(void)
			}
		}
	}

	nf_register_queue_handler(&nf_sip_qh);

	return 0;
}