2008-01-11 17:57:09 +03:00
/* SCTP kernel implementation
2005-04-17 02:20:36 +04:00
* Copyright ( c ) 2003 International Business Machines , Corp .
*
2008-01-11 17:57:09 +03:00
* This file is part of the SCTP kernel implementation
2005-04-17 02:20:36 +04:00
*
2008-01-11 17:57:09 +03:00
* This SCTP implementation is free software ;
2005-04-17 02:20:36 +04:00
* 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 .
*
2008-01-11 17:57:09 +03:00
* This SCTP implementation is distributed in the hope that it
2005-04-17 02:20:36 +04:00
* 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 , write to
* the Free Software Foundation , 59 Temple Place - Suite 330 ,
* Boston , MA 02111 - 1307 , USA .
*
* Please send any bug reports or fixes you make to the
* email address ( es ) :
* lksctp developers < lksctp - developers @ lists . sourceforge . net >
*
* Or submit a bug report through the following website :
* http : //www.sf.net/projects/lksctp
*
* Written or modified by :
* Sridhar Samudrala < sri @ us . ibm . com >
*
* Any bugs reported given to us we will try to fix . . . any fixes shared will
* be incorporated into the next SCTP release .
*/
# include <linux/types.h>
# include <linux/seq_file.h>
# include <linux/init.h>
# include <net/sctp/sctp.h>
2008-02-10 10:23:44 +03:00
# include <net/ip.h> /* for snmp_fold_field */
2005-04-17 02:20:36 +04:00
static struct snmp_mib sctp_snmp_list [ ] = {
SNMP_MIB_ITEM ( " SctpCurrEstab " , SCTP_MIB_CURRESTAB ) ,
SNMP_MIB_ITEM ( " SctpActiveEstabs " , SCTP_MIB_ACTIVEESTABS ) ,
SNMP_MIB_ITEM ( " SctpPassiveEstabs " , SCTP_MIB_PASSIVEESTABS ) ,
SNMP_MIB_ITEM ( " SctpAborteds " , SCTP_MIB_ABORTEDS ) ,
SNMP_MIB_ITEM ( " SctpShutdowns " , SCTP_MIB_SHUTDOWNS ) ,
SNMP_MIB_ITEM ( " SctpOutOfBlues " , SCTP_MIB_OUTOFBLUES ) ,
SNMP_MIB_ITEM ( " SctpChecksumErrors " , SCTP_MIB_CHECKSUMERRORS ) ,
SNMP_MIB_ITEM ( " SctpOutCtrlChunks " , SCTP_MIB_OUTCTRLCHUNKS ) ,
SNMP_MIB_ITEM ( " SctpOutOrderChunks " , SCTP_MIB_OUTORDERCHUNKS ) ,
SNMP_MIB_ITEM ( " SctpOutUnorderChunks " , SCTP_MIB_OUTUNORDERCHUNKS ) ,
SNMP_MIB_ITEM ( " SctpInCtrlChunks " , SCTP_MIB_INCTRLCHUNKS ) ,
SNMP_MIB_ITEM ( " SctpInOrderChunks " , SCTP_MIB_INORDERCHUNKS ) ,
SNMP_MIB_ITEM ( " SctpInUnorderChunks " , SCTP_MIB_INUNORDERCHUNKS ) ,
SNMP_MIB_ITEM ( " SctpFragUsrMsgs " , SCTP_MIB_FRAGUSRMSGS ) ,
SNMP_MIB_ITEM ( " SctpReasmUsrMsgs " , SCTP_MIB_REASMUSRMSGS ) ,
SNMP_MIB_ITEM ( " SctpOutSCTPPacks " , SCTP_MIB_OUTSCTPPACKS ) ,
SNMP_MIB_ITEM ( " SctpInSCTPPacks " , SCTP_MIB_INSCTPPACKS ) ,
2006-08-22 11:15:33 +04:00
SNMP_MIB_ITEM ( " SctpT1InitExpireds " , SCTP_MIB_T1_INIT_EXPIREDS ) ,
SNMP_MIB_ITEM ( " SctpT1CookieExpireds " , SCTP_MIB_T1_COOKIE_EXPIREDS ) ,
SNMP_MIB_ITEM ( " SctpT2ShutdownExpireds " , SCTP_MIB_T2_SHUTDOWN_EXPIREDS ) ,
SNMP_MIB_ITEM ( " SctpT3RtxExpireds " , SCTP_MIB_T3_RTX_EXPIREDS ) ,
SNMP_MIB_ITEM ( " SctpT4RtoExpireds " , SCTP_MIB_T4_RTO_EXPIREDS ) ,
SNMP_MIB_ITEM ( " SctpT5ShutdownGuardExpireds " , SCTP_MIB_T5_SHUTDOWN_GUARD_EXPIREDS ) ,
SNMP_MIB_ITEM ( " SctpDelaySackExpireds " , SCTP_MIB_DELAY_SACK_EXPIREDS ) ,
SNMP_MIB_ITEM ( " SctpAutocloseExpireds " , SCTP_MIB_AUTOCLOSE_EXPIREDS ) ,
SNMP_MIB_ITEM ( " SctpT3Retransmits " , SCTP_MIB_T3_RETRANSMITS ) ,
SNMP_MIB_ITEM ( " SctpPmtudRetransmits " , SCTP_MIB_PMTUD_RETRANSMITS ) ,
SNMP_MIB_ITEM ( " SctpFastRetransmits " , SCTP_MIB_FAST_RETRANSMITS ) ,
SNMP_MIB_ITEM ( " SctpInPktSoftirq " , SCTP_MIB_IN_PKT_SOFTIRQ ) ,
SNMP_MIB_ITEM ( " SctpInPktBacklog " , SCTP_MIB_IN_PKT_BACKLOG ) ,
SNMP_MIB_ITEM ( " SctpInPktDiscards " , SCTP_MIB_IN_PKT_DISCARDS ) ,
SNMP_MIB_ITEM ( " SctpInDataChunkDiscards " , SCTP_MIB_IN_DATA_CHUNK_DISCARDS ) ,
2005-08-23 21:12:04 +04:00
SNMP_MIB_SENTINEL
2005-04-17 02:20:36 +04:00
} ;
/* Display sctp snmp mib statistics(/proc/net/sctp/snmp). */
static int sctp_snmp_seq_show ( struct seq_file * seq , void * v )
{
int i ;
for ( i = 0 ; sctp_snmp_list [ i ] . name ! = NULL ; i + + )
seq_printf ( seq , " %-32s \t %ld \n " , sctp_snmp_list [ i ] . name ,
2008-02-10 10:23:44 +03:00
snmp_fold_field ( ( void * * ) sctp_statistics ,
2005-04-17 02:20:36 +04:00
sctp_snmp_list [ i ] . entry ) ) ;
return 0 ;
}
/* Initialize the seq file operations for 'snmp' object. */
static int sctp_snmp_seq_open ( struct inode * inode , struct file * file )
{
return single_open ( file , sctp_snmp_seq_show , NULL ) ;
}
2007-02-12 11:55:36 +03:00
static const struct file_operations sctp_snmp_seq_fops = {
2005-04-17 02:20:36 +04:00
. owner = THIS_MODULE ,
. open = sctp_snmp_seq_open ,
. read = seq_read ,
. llseek = seq_lseek ,
. release = single_release ,
} ;
/* Set up the proc fs entry for 'snmp' object. */
int __init sctp_snmp_proc_init ( void )
{
struct proc_dir_entry * p ;
2008-02-29 01:13:16 +03:00
p = proc_create ( " snmp " , S_IRUGO , proc_net_sctp , & sctp_snmp_seq_fops ) ;
2005-04-17 02:20:36 +04:00
if ( ! p )
return - ENOMEM ;
return 0 ;
}
/* Cleanup the proc fs entry for 'snmp' object. */
void sctp_snmp_proc_exit ( void )
{
remove_proc_entry ( " snmp " , proc_net_sctp ) ;
}
/* Dump local addresses of an association/endpoint. */
static void sctp_seq_dump_local_addrs ( struct seq_file * seq , struct sctp_ep_common * epb )
{
2005-06-14 02:11:57 +04:00
struct sctp_association * asoc ;
2005-04-17 02:20:36 +04:00
struct sctp_sockaddr_entry * laddr ;
2005-06-14 02:11:57 +04:00
struct sctp_transport * peer ;
union sctp_addr * addr , * primary = NULL ;
2005-04-17 02:20:36 +04:00
struct sctp_af * af ;
2005-06-14 02:11:57 +04:00
if ( epb - > type = = SCTP_EP_TYPE_ASSOCIATION ) {
asoc = sctp_assoc ( epb ) ;
peer = asoc - > peer . primary_path ;
2006-11-21 04:05:23 +03:00
primary = & peer - > saddr ;
2005-06-14 02:11:57 +04:00
}
2008-04-13 05:54:24 +04:00
list_for_each_entry ( laddr , & epb - > bind_addr . address_list , list ) {
2006-11-21 04:05:23 +03:00
addr = & laddr - > a ;
2005-04-17 02:20:36 +04:00
af = sctp_get_af_specific ( addr - > sa . sa_family ) ;
2005-06-14 02:11:57 +04:00
if ( primary & & af - > cmp_addr ( addr , primary ) ) {
seq_printf ( seq , " * " ) ;
}
2006-11-21 04:05:23 +03:00
af - > seq_dump_addr ( seq , addr ) ;
2005-04-17 02:20:36 +04:00
}
}
/* Dump remote addresses of an association. */
static void sctp_seq_dump_remote_addrs ( struct seq_file * seq , struct sctp_association * assoc )
{
struct sctp_transport * transport ;
2005-06-14 02:11:57 +04:00
union sctp_addr * addr , * primary ;
2005-04-17 02:20:36 +04:00
struct sctp_af * af ;
2006-11-21 04:06:04 +03:00
primary = & assoc - > peer . primary_addr ;
2008-04-13 05:54:24 +04:00
list_for_each_entry ( transport , & assoc - > peer . transport_addr_list ,
transports ) {
2006-11-21 04:05:23 +03:00
addr = & transport - > ipaddr ;
2005-04-17 02:20:36 +04:00
af = sctp_get_af_specific ( addr - > sa . sa_family ) ;
2006-11-21 04:06:04 +03:00
if ( af - > cmp_addr ( addr , primary ) ) {
2005-06-14 02:11:57 +04:00
seq_printf ( seq , " * " ) ;
}
2006-11-21 04:05:23 +03:00
af - > seq_dump_addr ( seq , addr ) ;
2005-04-17 02:20:36 +04:00
}
}
2005-06-14 02:11:57 +04:00
static void * sctp_eps_seq_start ( struct seq_file * seq , loff_t * pos )
{
2006-01-17 22:53:06 +03:00
if ( * pos > = sctp_ep_hashsize )
2005-06-14 02:11:57 +04:00
return NULL ;
if ( * pos < 0 )
* pos = 0 ;
if ( * pos = = 0 )
seq_printf ( seq , " ENDPT SOCK STY SST HBKT LPORT UID INODE LADDRS \n " ) ;
return ( void * ) pos ;
}
static void sctp_eps_seq_stop ( struct seq_file * seq , void * v )
{
return ;
}
static void * sctp_eps_seq_next ( struct seq_file * seq , void * v , loff_t * pos )
{
2006-01-17 22:53:06 +03:00
if ( + + * pos > = sctp_ep_hashsize )
2005-06-14 02:11:57 +04:00
return NULL ;
return pos ;
}
2005-04-17 02:20:36 +04:00
/* Display sctp endpoints (/proc/net/sctp/eps). */
static int sctp_eps_seq_show ( struct seq_file * seq , void * v )
{
struct sctp_hashbucket * head ;
struct sctp_ep_common * epb ;
struct sctp_endpoint * ep ;
struct sock * sk ;
2007-11-09 19:43:40 +03:00
struct hlist_node * node ;
2006-01-17 22:54:06 +03:00
int hash = * ( loff_t * ) v ;
2005-06-14 02:11:57 +04:00
2006-01-17 22:53:06 +03:00
if ( hash > = sctp_ep_hashsize )
2005-06-14 02:11:57 +04:00
return - ENOMEM ;
2006-01-17 22:53:06 +03:00
head = & sctp_ep_hashtable [ hash ] ;
2005-06-14 02:11:57 +04:00
sctp_local_bh_disable ( ) ;
read_lock ( & head - > lock ) ;
2007-11-09 19:43:40 +03:00
sctp_for_each_hentry ( epb , node , & head - > chain ) {
2005-06-14 02:11:57 +04:00
ep = sctp_ep ( epb ) ;
sk = epb - > sk ;
seq_printf ( seq , " %8p %8p %-3d %-3d %-4d %-5d %5d %5lu " , ep , sk ,
2006-01-17 22:53:06 +03:00
sctp_sk ( sk ) - > type , sk - > sk_state , hash ,
2005-06-14 02:11:57 +04:00
epb - > bind_addr . port ,
sock_i_uid ( sk ) , sock_i_ino ( sk ) ) ;
sctp_seq_dump_local_addrs ( seq , epb ) ;
seq_printf ( seq , " \n " ) ;
2005-04-17 02:20:36 +04:00
}
2005-06-14 02:11:57 +04:00
read_unlock ( & head - > lock ) ;
sctp_local_bh_enable ( ) ;
2005-04-17 02:20:36 +04:00
return 0 ;
}
2007-07-11 10:07:31 +04:00
static const struct seq_operations sctp_eps_ops = {
2005-06-14 02:11:57 +04:00
. start = sctp_eps_seq_start ,
. next = sctp_eps_seq_next ,
. stop = sctp_eps_seq_stop ,
. show = sctp_eps_seq_show ,
} ;
2005-04-17 02:20:36 +04:00
/* Initialize the seq file operations for 'eps' object. */
static int sctp_eps_seq_open ( struct inode * inode , struct file * file )
{
2005-06-14 02:11:57 +04:00
return seq_open ( file , & sctp_eps_ops ) ;
2005-04-17 02:20:36 +04:00
}
2007-02-12 11:55:36 +03:00
static const struct file_operations sctp_eps_seq_fops = {
2005-04-17 02:20:36 +04:00
. open = sctp_eps_seq_open ,
. read = seq_read ,
. llseek = seq_lseek ,
2005-06-14 02:11:57 +04:00
. release = seq_release ,
2005-04-17 02:20:36 +04:00
} ;
/* Set up the proc fs entry for 'eps' object. */
int __init sctp_eps_proc_init ( void )
{
struct proc_dir_entry * p ;
2008-02-29 22:24:45 +03:00
p = proc_create ( " eps " , S_IRUGO , proc_net_sctp , & sctp_eps_seq_fops ) ;
2005-04-17 02:20:36 +04:00
if ( ! p )
return - ENOMEM ;
return 0 ;
}
/* Cleanup the proc fs entry for 'eps' object. */
void sctp_eps_proc_exit ( void )
{
remove_proc_entry ( " eps " , proc_net_sctp ) ;
}
2005-06-14 02:11:57 +04:00
static void * sctp_assocs_seq_start ( struct seq_file * seq , loff_t * pos )
{
2006-01-17 22:53:06 +03:00
if ( * pos > = sctp_assoc_hashsize )
2005-06-14 02:11:57 +04:00
return NULL ;
if ( * pos < 0 )
* pos = 0 ;
if ( * pos = = 0 )
2008-02-29 22:40:56 +03:00
seq_printf ( seq , " ASSOC SOCK STY SST ST HBKT "
" ASSOC-ID TX_QUEUE RX_QUEUE UID INODE LPORT "
" RPORT LADDRS <-> RADDRS "
" HBINT INS OUTS MAXRT T1X T2X RTXC \n " ) ;
2005-06-14 02:11:57 +04:00
return ( void * ) pos ;
}
static void sctp_assocs_seq_stop ( struct seq_file * seq , void * v )
{
return ;
}
static void * sctp_assocs_seq_next ( struct seq_file * seq , void * v , loff_t * pos )
{
2006-01-17 22:53:06 +03:00
if ( + + * pos > = sctp_assoc_hashsize )
2005-06-14 02:11:57 +04:00
return NULL ;
return pos ;
}
2005-04-17 02:20:36 +04:00
/* Display sctp associations (/proc/net/sctp/assocs). */
static int sctp_assocs_seq_show ( struct seq_file * seq , void * v )
{
struct sctp_hashbucket * head ;
struct sctp_ep_common * epb ;
struct sctp_association * assoc ;
struct sock * sk ;
2007-11-09 19:43:40 +03:00
struct hlist_node * node ;
2006-01-17 22:54:06 +03:00
int hash = * ( loff_t * ) v ;
2005-06-14 02:11:57 +04:00
2006-01-17 22:53:06 +03:00
if ( hash > = sctp_assoc_hashsize )
2005-06-14 02:11:57 +04:00
return - ENOMEM ;
2006-01-17 22:53:06 +03:00
head = & sctp_assoc_hashtable [ hash ] ;
2005-06-14 02:11:57 +04:00
sctp_local_bh_disable ( ) ;
read_lock ( & head - > lock ) ;
2007-11-09 19:43:40 +03:00
sctp_for_each_hentry ( epb , node , & head - > chain ) {
2005-06-14 02:11:57 +04:00
assoc = sctp_assoc ( epb ) ;
sk = epb - > sk ;
seq_printf ( seq ,
2008-02-29 22:40:56 +03:00
" %8p %8p %-3d %-3d %-2d %-4d "
2008-04-13 05:53:48 +04:00
" %4d %8d %8d %7d %5lu %-5d %5d " ,
2005-06-14 02:11:57 +04:00
assoc , sk , sctp_sk ( sk ) - > type , sk - > sk_state ,
2008-02-29 22:40:56 +03:00
assoc - > state , hash ,
assoc - > assoc_id ,
2005-06-14 02:11:57 +04:00
assoc - > sndbuf_used ,
2006-10-10 08:34:26 +04:00
atomic_read ( & assoc - > rmem_alloc ) ,
2005-06-14 02:11:57 +04:00
sock_i_uid ( sk ) , sock_i_ino ( sk ) ,
epb - > bind_addr . port ,
2008-04-13 05:53:48 +04:00
assoc - > peer . port ) ;
2005-06-14 02:11:57 +04:00
seq_printf ( seq , " " ) ;
sctp_seq_dump_local_addrs ( seq , epb ) ;
seq_printf ( seq , " <-> " ) ;
sctp_seq_dump_remote_addrs ( seq , assoc ) ;
2008-04-13 05:53:48 +04:00
seq_printf ( seq , " \t %8lu %5d %5d %4d %4d %4d %8d " ,
assoc - > hbinterval , assoc - > c . sinit_max_instreams ,
assoc - > c . sinit_num_ostreams , assoc - > max_retrans ,
assoc - > init_retries , assoc - > shutdown_retries ,
assoc - > rtx_data_chunks ) ;
2005-06-14 02:11:57 +04:00
seq_printf ( seq , " \n " ) ;
2005-04-17 02:20:36 +04:00
}
2005-06-14 02:11:57 +04:00
read_unlock ( & head - > lock ) ;
sctp_local_bh_enable ( ) ;
2005-04-17 02:20:36 +04:00
return 0 ;
}
2007-07-11 10:07:31 +04:00
static const struct seq_operations sctp_assoc_ops = {
2005-06-14 02:11:57 +04:00
. start = sctp_assocs_seq_start ,
. next = sctp_assocs_seq_next ,
. stop = sctp_assocs_seq_stop ,
. show = sctp_assocs_seq_show ,
} ;
2005-04-17 02:20:36 +04:00
/* Initialize the seq file operations for 'assocs' object. */
static int sctp_assocs_seq_open ( struct inode * inode , struct file * file )
{
2005-06-14 02:11:57 +04:00
return seq_open ( file , & sctp_assoc_ops ) ;
2005-04-17 02:20:36 +04:00
}
2007-02-12 11:55:36 +03:00
static const struct file_operations sctp_assocs_seq_fops = {
2005-04-17 02:20:36 +04:00
. open = sctp_assocs_seq_open ,
. read = seq_read ,
. llseek = seq_lseek ,
2005-06-14 02:11:57 +04:00
. release = seq_release ,
2005-04-17 02:20:36 +04:00
} ;
/* Set up the proc fs entry for 'assocs' object. */
int __init sctp_assocs_proc_init ( void )
{
struct proc_dir_entry * p ;
2008-02-29 22:24:45 +03:00
p = proc_create ( " assocs " , S_IRUGO , proc_net_sctp ,
& sctp_assocs_seq_fops ) ;
2005-04-17 02:20:36 +04:00
if ( ! p )
return - ENOMEM ;
return 0 ;
}
/* Cleanup the proc fs entry for 'assocs' object. */
void sctp_assocs_proc_exit ( void )
{
remove_proc_entry ( " assocs " , proc_net_sctp ) ;
}
2008-05-10 02:14:50 +04:00
static void * sctp_remaddr_seq_start ( struct seq_file * seq , loff_t * pos )
{
if ( * pos > = sctp_assoc_hashsize )
return NULL ;
if ( * pos < 0 )
* pos = 0 ;
if ( * pos = = 0 )
seq_printf ( seq , " ADDR ASSOC_ID HB_ACT RTO MAX_PATH_RTX "
" REM_ADDR_RTX START \n " ) ;
return ( void * ) pos ;
}
static void * sctp_remaddr_seq_next ( struct seq_file * seq , void * v , loff_t * pos )
{
if ( + + * pos > = sctp_assoc_hashsize )
return NULL ;
return pos ;
}
static void sctp_remaddr_seq_stop ( struct seq_file * seq , void * v )
{
return ;
}
static int sctp_remaddr_seq_show ( struct seq_file * seq , void * v )
{
struct sctp_hashbucket * head ;
struct sctp_ep_common * epb ;
struct sctp_association * assoc ;
struct hlist_node * node ;
struct sctp_transport * tsp ;
int hash = * ( loff_t * ) v ;
if ( hash > = sctp_assoc_hashsize )
return - ENOMEM ;
head = & sctp_assoc_hashtable [ hash ] ;
sctp_local_bh_disable ( ) ;
read_lock ( & head - > lock ) ;
sctp_for_each_hentry ( epb , node , & head - > chain ) {
assoc = sctp_assoc ( epb ) ;
list_for_each_entry ( tsp , & assoc - > peer . transport_addr_list ,
transports ) {
/*
* The remote address ( ADDR )
*/
tsp - > af_specific - > seq_dump_addr ( seq , & tsp - > ipaddr ) ;
seq_printf ( seq , " " ) ;
/*
* The association ID ( ASSOC_ID )
*/
seq_printf ( seq , " %d " , tsp - > asoc - > assoc_id ) ;
/*
* If the Heartbeat is active ( HB_ACT )
* Note : 1 = Active , 0 = Inactive
*/
seq_printf ( seq , " %d " , timer_pending ( & tsp - > hb_timer ) ) ;
/*
* Retransmit time out ( RTO )
*/
seq_printf ( seq , " %lu " , tsp - > rto ) ;
/*
* Maximum path retransmit count ( PATH_MAX_RTX )
*/
seq_printf ( seq , " %d " , tsp - > pathmaxrxt ) ;
/*
* remote address retransmit count ( REM_ADDR_RTX )
* Note : We don ' t have a way to tally this at the moment
* so lets just leave it as zero for the moment
*/
seq_printf ( seq , " 0 " ) ;
/*
* remote address start time ( START ) . This is also not
* currently implemented , but we can record it with a
* jiffies marker in a subsequent patch
*/
seq_printf ( seq , " 0 " ) ;
seq_printf ( seq , " \n " ) ;
}
}
read_unlock ( & head - > lock ) ;
sctp_local_bh_enable ( ) ;
return 0 ;
}
static const struct seq_operations sctp_remaddr_ops = {
. start = sctp_remaddr_seq_start ,
. next = sctp_remaddr_seq_next ,
. stop = sctp_remaddr_seq_stop ,
. show = sctp_remaddr_seq_show ,
} ;
/* Cleanup the proc fs entry for 'remaddr' object. */
void sctp_remaddr_proc_exit ( void )
{
remove_proc_entry ( " remaddr " , proc_net_sctp ) ;
}
static int sctp_remaddr_seq_open ( struct inode * inode , struct file * file )
{
return seq_open ( file , & sctp_remaddr_ops ) ;
}
static const struct file_operations sctp_remaddr_seq_fops = {
. open = sctp_remaddr_seq_open ,
. read = seq_read ,
. llseek = seq_lseek ,
. release = seq_release ,
} ;
int __init sctp_remaddr_proc_init ( void )
{
struct proc_dir_entry * p ;
2009-08-23 23:11:36 +04:00
p = proc_create ( " remaddr " , S_IRUGO , proc_net_sctp , & sctp_remaddr_seq_fops ) ;
2008-05-10 02:14:50 +04:00
if ( ! p )
return - ENOMEM ;
return 0 ;
}