160c778b25972e095df8981dd41e99d161e8738f9Vlad Yasevich/* SCTP kernel implementation
21da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Copyright (c) 2003 International Business Machines, Corp.
31da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
460c778b25972e095df8981dd41e99d161e8738f9Vlad Yasevich * This file is part of the SCTP kernel implementation
51da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
61da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * These functions manipulate sctp SSN tracker.
71da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
860c778b25972e095df8981dd41e99d161e8738f9Vlad Yasevich * This SCTP implementation is free software;
91da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * you can redistribute it and/or modify it under the terms of
101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * the GNU General Public License as published by
111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * the Free Software Foundation; either version 2, or (at your option)
121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * any later version.
131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
1460c778b25972e095df8981dd41e99d161e8738f9Vlad Yasevich * This SCTP implementation is distributed in the hope that it
151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * will be useful, but WITHOUT ANY WARRANTY; without even the implied
161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *                 ************************
171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * See the GNU General Public License for more details.
191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * You should have received a copy of the GNU General Public License
214b2f13a25133b115eb56771bd4a8e71a82aea968Jeff Kirsher * along with GNU CC; see the file COPYING.  If not, see
224b2f13a25133b115eb56771bd4a8e71a82aea968Jeff Kirsher * <http://www.gnu.org/licenses/>.
231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Please send any bug reports or fixes you make to the
251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * email address(es):
2691705c61b52029ab5da67a15a23eef08667bf40eDaniel Borkmann *    lksctp developers <linux-sctp@vger.kernel.org>
271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Written or modified by:
291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *    Jon Grimm             <jgrimm@us.ibm.com>
301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/types.h>
335a0e3ad6af8660be21ca98a971cd00f331318c05Tejun Heo#include <linux/slab.h>
341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <net/sctp/sctp.h>
351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <net/sctp/sm.h>
361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct sctp_ssnmap *sctp_ssnmap_init(struct sctp_ssnmap *map, __u16 in,
381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					    __u16 out);
391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* Storage size needed for map includes 2 headers and then the
411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * specific needs of in or out streams.
421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic inline size_t sctp_ssnmap_size(__u16 in, __u16 out)
441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return sizeof(struct sctp_ssnmap) + (in + out) * sizeof(__u16);
461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* Create a new sctp_ssnmap.
501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Allocate room to store at least 'len' contiguous TSNs.
511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
523182cd84f0e132558bbe106c070405ae49f1f0e3Alexey Dobriyanstruct sctp_ssnmap *sctp_ssnmap_new(__u16 in, __u16 out,
53dd0fc66fb33cd610bc1a5db8a5e232d34879b4d7Al Viro				    gfp_t gfp)
541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct sctp_ssnmap *retval;
561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int size;
571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	size = sctp_ssnmap_size(in, out);
593f736868b47687d1336fe88185560b22bb92021eCong Wang	if (size <= KMALLOC_MAX_SIZE)
601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		retval = kmalloc(size, gfp);
611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	else
621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		retval = (struct sctp_ssnmap *)
631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			  __get_free_pages(gfp, get_order(size));
641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!retval)
651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto fail;
661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!sctp_ssnmap_init(retval, in, out))
681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto fail_map;
691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	SCTP_DBG_OBJCNT_INC(ssnmap);
711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return retval;
731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsfail_map:
753f736868b47687d1336fe88185560b22bb92021eCong Wang	if (size <= KMALLOC_MAX_SIZE)
761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		kfree(retval);
771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	else
781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		free_pages((unsigned long)retval, get_order(size));
791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsfail:
801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return NULL;
811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* Initialize a block of memory as a ssnmap.  */
851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct sctp_ssnmap *sctp_ssnmap_init(struct sctp_ssnmap *map, __u16 in,
861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					    __u16 out)
871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	memset(map, 0x00, sctp_ssnmap_size(in, out));
891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Start 'in' stream just after the map header. */
911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	map->in.ssn = (__u16 *)&map[1];
921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	map->in.len = in;
931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Start 'out' stream just after 'in'. */
951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	map->out.ssn = &map->in.ssn[in];
961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	map->out.len = out;
971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return map;
991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
1001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* Clear out the ssnmap streams.  */
1021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsvoid sctp_ssnmap_clear(struct sctp_ssnmap *map)
1031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
1041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	size_t size;
1051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	size = (map->in.len + map->out.len) * sizeof(__u16);
1071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	memset(map->in.ssn, 0x00, size);
1081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
1091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* Dispose of a ssnmap.  */
1111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsvoid sctp_ssnmap_free(struct sctp_ssnmap *map)
1121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
113542c2d832087aa78566be49aa4284779a0a687b3Daniel Borkmann	int size;
114542c2d832087aa78566be49aa4284779a0a687b3Daniel Borkmann
115542c2d832087aa78566be49aa4284779a0a687b3Daniel Borkmann	if (unlikely(!map))
116542c2d832087aa78566be49aa4284779a0a687b3Daniel Borkmann		return;
117542c2d832087aa78566be49aa4284779a0a687b3Daniel Borkmann
118542c2d832087aa78566be49aa4284779a0a687b3Daniel Borkmann	size = sctp_ssnmap_size(map->in.len, map->out.len);
119542c2d832087aa78566be49aa4284779a0a687b3Daniel Borkmann	if (size <= KMALLOC_MAX_SIZE)
120542c2d832087aa78566be49aa4284779a0a687b3Daniel Borkmann		kfree(map);
121542c2d832087aa78566be49aa4284779a0a687b3Daniel Borkmann	else
122542c2d832087aa78566be49aa4284779a0a687b3Daniel Borkmann		free_pages((unsigned long)map, get_order(size));
123542c2d832087aa78566be49aa4284779a0a687b3Daniel Borkmann
124542c2d832087aa78566be49aa4284779a0a687b3Daniel Borkmann	SCTP_DBG_OBJCNT_DEC(ssnmap);
1251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
126