| /* SCTP kernel implementation | |
| * Copyright (c) 2003 International Business Machines, Corp. | |
| * | |
| * This file is part of the SCTP kernel implementation | |
| * | |
| * These functions manipulate sctp SSN tracker. | |
| * | |
| * This SCTP implementation is free software; | |
| * you can redistribute it and/or modify it under the terms of | |
| * the GNU General Public License as published by | |
| * the Free Software Foundation; either version 2, or (at your option) | |
| * any later version. | |
| * | |
| * This SCTP implementation is distributed in the hope that it | |
| * will be useful, but WITHOUT ANY WARRANTY; without even the implied | |
| * ************************ | |
| * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. | |
| * See the GNU General Public License for more details. | |
| * | |
| * You should have received a copy of the GNU General Public License | |
| * along with GNU CC; see the file COPYING. If not, see | |
| * <http://www.gnu.org/licenses/>. | |
| * | |
| * Please send any bug reports or fixes you make to the | |
| * email address(es): | |
| * lksctp developers <linux-sctp@vger.kernel.org> | |
| * | |
| * Written or modified by: | |
| * Jon Grimm <jgrimm@us.ibm.com> | |
| */ | |
| #include <linux/types.h> | |
| #include <linux/slab.h> | |
| #include <net/sctp/sctp.h> | |
| #include <net/sctp/sm.h> | |
| static struct sctp_ssnmap *sctp_ssnmap_init(struct sctp_ssnmap *map, __u16 in, | |
| __u16 out); | |
| /* Storage size needed for map includes 2 headers and then the | |
| * specific needs of in or out streams. | |
| */ | |
| static inline size_t sctp_ssnmap_size(__u16 in, __u16 out) | |
| { | |
| return sizeof(struct sctp_ssnmap) + (in + out) * sizeof(__u16); | |
| } | |
| /* Create a new sctp_ssnmap. | |
| * Allocate room to store at least 'len' contiguous TSNs. | |
| */ | |
| struct sctp_ssnmap *sctp_ssnmap_new(__u16 in, __u16 out, | |
| gfp_t gfp) | |
| { | |
| struct sctp_ssnmap *retval; | |
| int size; | |
| size = sctp_ssnmap_size(in, out); | |
| if (size <= KMALLOC_MAX_SIZE) | |
| retval = kmalloc(size, gfp); | |
| else | |
| retval = (struct sctp_ssnmap *) | |
| __get_free_pages(gfp, get_order(size)); | |
| if (!retval) | |
| goto fail; | |
| if (!sctp_ssnmap_init(retval, in, out)) | |
| goto fail_map; | |
| SCTP_DBG_OBJCNT_INC(ssnmap); | |
| return retval; | |
| fail_map: | |
| if (size <= KMALLOC_MAX_SIZE) | |
| kfree(retval); | |
| else | |
| free_pages((unsigned long)retval, get_order(size)); | |
| fail: | |
| return NULL; | |
| } | |
| /* Initialize a block of memory as a ssnmap. */ | |
| static struct sctp_ssnmap *sctp_ssnmap_init(struct sctp_ssnmap *map, __u16 in, | |
| __u16 out) | |
| { | |
| memset(map, 0x00, sctp_ssnmap_size(in, out)); | |
| /* Start 'in' stream just after the map header. */ | |
| map->in.ssn = (__u16 *)&map[1]; | |
| map->in.len = in; | |
| /* Start 'out' stream just after 'in'. */ | |
| map->out.ssn = &map->in.ssn[in]; | |
| map->out.len = out; | |
| return map; | |
| } | |
| /* Clear out the ssnmap streams. */ | |
| void sctp_ssnmap_clear(struct sctp_ssnmap *map) | |
| { | |
| size_t size; | |
| size = (map->in.len + map->out.len) * sizeof(__u16); | |
| memset(map->in.ssn, 0x00, size); | |
| } | |
| /* Dispose of a ssnmap. */ | |
| void sctp_ssnmap_free(struct sctp_ssnmap *map) | |
| { | |
| int size; | |
| if (unlikely(!map)) | |
| return; | |
| size = sctp_ssnmap_size(map->in.len, map->out.len); | |
| if (size <= KMALLOC_MAX_SIZE) | |
| kfree(map); | |
| else | |
| free_pages((unsigned long)map, get_order(size)); | |
| SCTP_DBG_OBJCNT_DEC(ssnmap); | |
| } |