Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-or-later
0002 /* SCTP kernel implementation
0003  * Copyright (c) 2003 International Business Machines, Corp.
0004  *
0005  * This file is part of the SCTP kernel implementation
0006  *
0007  * Please send any bug reports or fixes you make to the
0008  * email address(es):
0009  *    lksctp developers <linux-sctp@vger.kernel.org>
0010  *
0011  * Written or modified by:
0012  *    Sridhar Samudrala <sri@us.ibm.com>
0013  */
0014 
0015 #include <linux/types.h>
0016 #include <linux/seq_file.h>
0017 #include <linux/init.h>
0018 #include <linux/export.h>
0019 #include <net/sctp/sctp.h>
0020 #include <net/ip.h> /* for snmp_fold_field */
0021 
0022 static const struct snmp_mib sctp_snmp_list[] = {
0023     SNMP_MIB_ITEM("SctpCurrEstab", SCTP_MIB_CURRESTAB),
0024     SNMP_MIB_ITEM("SctpActiveEstabs", SCTP_MIB_ACTIVEESTABS),
0025     SNMP_MIB_ITEM("SctpPassiveEstabs", SCTP_MIB_PASSIVEESTABS),
0026     SNMP_MIB_ITEM("SctpAborteds", SCTP_MIB_ABORTEDS),
0027     SNMP_MIB_ITEM("SctpShutdowns", SCTP_MIB_SHUTDOWNS),
0028     SNMP_MIB_ITEM("SctpOutOfBlues", SCTP_MIB_OUTOFBLUES),
0029     SNMP_MIB_ITEM("SctpChecksumErrors", SCTP_MIB_CHECKSUMERRORS),
0030     SNMP_MIB_ITEM("SctpOutCtrlChunks", SCTP_MIB_OUTCTRLCHUNKS),
0031     SNMP_MIB_ITEM("SctpOutOrderChunks", SCTP_MIB_OUTORDERCHUNKS),
0032     SNMP_MIB_ITEM("SctpOutUnorderChunks", SCTP_MIB_OUTUNORDERCHUNKS),
0033     SNMP_MIB_ITEM("SctpInCtrlChunks", SCTP_MIB_INCTRLCHUNKS),
0034     SNMP_MIB_ITEM("SctpInOrderChunks", SCTP_MIB_INORDERCHUNKS),
0035     SNMP_MIB_ITEM("SctpInUnorderChunks", SCTP_MIB_INUNORDERCHUNKS),
0036     SNMP_MIB_ITEM("SctpFragUsrMsgs", SCTP_MIB_FRAGUSRMSGS),
0037     SNMP_MIB_ITEM("SctpReasmUsrMsgs", SCTP_MIB_REASMUSRMSGS),
0038     SNMP_MIB_ITEM("SctpOutSCTPPacks", SCTP_MIB_OUTSCTPPACKS),
0039     SNMP_MIB_ITEM("SctpInSCTPPacks", SCTP_MIB_INSCTPPACKS),
0040     SNMP_MIB_ITEM("SctpT1InitExpireds", SCTP_MIB_T1_INIT_EXPIREDS),
0041     SNMP_MIB_ITEM("SctpT1CookieExpireds", SCTP_MIB_T1_COOKIE_EXPIREDS),
0042     SNMP_MIB_ITEM("SctpT2ShutdownExpireds", SCTP_MIB_T2_SHUTDOWN_EXPIREDS),
0043     SNMP_MIB_ITEM("SctpT3RtxExpireds", SCTP_MIB_T3_RTX_EXPIREDS),
0044     SNMP_MIB_ITEM("SctpT4RtoExpireds", SCTP_MIB_T4_RTO_EXPIREDS),
0045     SNMP_MIB_ITEM("SctpT5ShutdownGuardExpireds", SCTP_MIB_T5_SHUTDOWN_GUARD_EXPIREDS),
0046     SNMP_MIB_ITEM("SctpDelaySackExpireds", SCTP_MIB_DELAY_SACK_EXPIREDS),
0047     SNMP_MIB_ITEM("SctpAutocloseExpireds", SCTP_MIB_AUTOCLOSE_EXPIREDS),
0048     SNMP_MIB_ITEM("SctpT3Retransmits", SCTP_MIB_T3_RETRANSMITS),
0049     SNMP_MIB_ITEM("SctpPmtudRetransmits", SCTP_MIB_PMTUD_RETRANSMITS),
0050     SNMP_MIB_ITEM("SctpFastRetransmits", SCTP_MIB_FAST_RETRANSMITS),
0051     SNMP_MIB_ITEM("SctpInPktSoftirq", SCTP_MIB_IN_PKT_SOFTIRQ),
0052     SNMP_MIB_ITEM("SctpInPktBacklog", SCTP_MIB_IN_PKT_BACKLOG),
0053     SNMP_MIB_ITEM("SctpInPktDiscards", SCTP_MIB_IN_PKT_DISCARDS),
0054     SNMP_MIB_ITEM("SctpInDataChunkDiscards", SCTP_MIB_IN_DATA_CHUNK_DISCARDS),
0055     SNMP_MIB_SENTINEL
0056 };
0057 
0058 /* Display sctp snmp mib statistics(/proc/net/sctp/snmp). */
0059 static int sctp_snmp_seq_show(struct seq_file *seq, void *v)
0060 {
0061     unsigned long buff[SCTP_MIB_MAX];
0062     struct net *net = seq->private;
0063     int i;
0064 
0065     memset(buff, 0, sizeof(unsigned long) * SCTP_MIB_MAX);
0066 
0067     snmp_get_cpu_field_batch(buff, sctp_snmp_list,
0068                  net->sctp.sctp_statistics);
0069     for (i = 0; sctp_snmp_list[i].name; i++)
0070         seq_printf(seq, "%-32s\t%ld\n", sctp_snmp_list[i].name,
0071                         buff[i]);
0072 
0073     return 0;
0074 }
0075 
0076 /* Dump local addresses of an association/endpoint. */
0077 static void sctp_seq_dump_local_addrs(struct seq_file *seq, struct sctp_ep_common *epb)
0078 {
0079     struct sctp_association *asoc;
0080     struct sctp_sockaddr_entry *laddr;
0081     struct sctp_transport *peer;
0082     union sctp_addr *addr, *primary = NULL;
0083     struct sctp_af *af;
0084 
0085     if (epb->type == SCTP_EP_TYPE_ASSOCIATION) {
0086         asoc = sctp_assoc(epb);
0087 
0088         peer = asoc->peer.primary_path;
0089         if (unlikely(peer == NULL)) {
0090             WARN(1, "Association %p with NULL primary path!\n", asoc);
0091             return;
0092         }
0093 
0094         primary = &peer->saddr;
0095     }
0096 
0097     rcu_read_lock();
0098     list_for_each_entry_rcu(laddr, &epb->bind_addr.address_list, list) {
0099         if (!laddr->valid)
0100             continue;
0101 
0102         addr = &laddr->a;
0103         af = sctp_get_af_specific(addr->sa.sa_family);
0104         if (primary && af->cmp_addr(addr, primary)) {
0105             seq_printf(seq, "*");
0106         }
0107         af->seq_dump_addr(seq, addr);
0108     }
0109     rcu_read_unlock();
0110 }
0111 
0112 /* Dump remote addresses of an association. */
0113 static void sctp_seq_dump_remote_addrs(struct seq_file *seq, struct sctp_association *assoc)
0114 {
0115     struct sctp_transport *transport;
0116     union sctp_addr *addr, *primary;
0117     struct sctp_af *af;
0118 
0119     primary = &assoc->peer.primary_addr;
0120     list_for_each_entry_rcu(transport, &assoc->peer.transport_addr_list,
0121             transports) {
0122         addr = &transport->ipaddr;
0123 
0124         af = sctp_get_af_specific(addr->sa.sa_family);
0125         if (af->cmp_addr(addr, primary)) {
0126             seq_printf(seq, "*");
0127         }
0128         af->seq_dump_addr(seq, addr);
0129     }
0130 }
0131 
0132 static void *sctp_eps_seq_start(struct seq_file *seq, loff_t *pos)
0133 {
0134     if (*pos >= sctp_ep_hashsize)
0135         return NULL;
0136 
0137     if (*pos < 0)
0138         *pos = 0;
0139 
0140     if (*pos == 0)
0141         seq_printf(seq, " ENDPT     SOCK   STY SST HBKT LPORT   UID INODE LADDRS\n");
0142 
0143     return (void *)pos;
0144 }
0145 
0146 static void sctp_eps_seq_stop(struct seq_file *seq, void *v)
0147 {
0148 }
0149 
0150 
0151 static void *sctp_eps_seq_next(struct seq_file *seq, void *v, loff_t *pos)
0152 {
0153     if (++*pos >= sctp_ep_hashsize)
0154         return NULL;
0155 
0156     return pos;
0157 }
0158 
0159 
0160 /* Display sctp endpoints (/proc/net/sctp/eps). */
0161 static int sctp_eps_seq_show(struct seq_file *seq, void *v)
0162 {
0163     struct sctp_hashbucket *head;
0164     struct sctp_endpoint *ep;
0165     struct sock *sk;
0166     int    hash = *(loff_t *)v;
0167 
0168     if (hash >= sctp_ep_hashsize)
0169         return -ENOMEM;
0170 
0171     head = &sctp_ep_hashtable[hash];
0172     read_lock_bh(&head->lock);
0173     sctp_for_each_hentry(ep, &head->chain) {
0174         sk = ep->base.sk;
0175         if (!net_eq(sock_net(sk), seq_file_net(seq)))
0176             continue;
0177         seq_printf(seq, "%8pK %8pK %-3d %-3d %-4d %-5d %5u %5lu ", ep, sk,
0178                sctp_sk(sk)->type, sk->sk_state, hash,
0179                ep->base.bind_addr.port,
0180                from_kuid_munged(seq_user_ns(seq), sock_i_uid(sk)),
0181                sock_i_ino(sk));
0182 
0183         sctp_seq_dump_local_addrs(seq, &ep->base);
0184         seq_printf(seq, "\n");
0185     }
0186     read_unlock_bh(&head->lock);
0187 
0188     return 0;
0189 }
0190 
0191 static const struct seq_operations sctp_eps_ops = {
0192     .start = sctp_eps_seq_start,
0193     .next  = sctp_eps_seq_next,
0194     .stop  = sctp_eps_seq_stop,
0195     .show  = sctp_eps_seq_show,
0196 };
0197 
0198 struct sctp_ht_iter {
0199     struct seq_net_private p;
0200     struct rhashtable_iter hti;
0201 };
0202 
0203 static void *sctp_transport_seq_start(struct seq_file *seq, loff_t *pos)
0204 {
0205     struct sctp_ht_iter *iter = seq->private;
0206 
0207     sctp_transport_walk_start(&iter->hti);
0208 
0209     return sctp_transport_get_idx(seq_file_net(seq), &iter->hti, *pos);
0210 }
0211 
0212 static void sctp_transport_seq_stop(struct seq_file *seq, void *v)
0213 {
0214     struct sctp_ht_iter *iter = seq->private;
0215 
0216     if (v && v != SEQ_START_TOKEN) {
0217         struct sctp_transport *transport = v;
0218 
0219         sctp_transport_put(transport);
0220     }
0221 
0222     sctp_transport_walk_stop(&iter->hti);
0223 }
0224 
0225 static void *sctp_transport_seq_next(struct seq_file *seq, void *v, loff_t *pos)
0226 {
0227     struct sctp_ht_iter *iter = seq->private;
0228 
0229     if (v && v != SEQ_START_TOKEN) {
0230         struct sctp_transport *transport = v;
0231 
0232         sctp_transport_put(transport);
0233     }
0234 
0235     ++*pos;
0236 
0237     return sctp_transport_get_next(seq_file_net(seq), &iter->hti);
0238 }
0239 
0240 /* Display sctp associations (/proc/net/sctp/assocs). */
0241 static int sctp_assocs_seq_show(struct seq_file *seq, void *v)
0242 {
0243     struct sctp_transport *transport;
0244     struct sctp_association *assoc;
0245     struct sctp_ep_common *epb;
0246     struct sock *sk;
0247 
0248     if (v == SEQ_START_TOKEN) {
0249         seq_printf(seq, " ASSOC     SOCK   STY SST ST HBKT "
0250                 "ASSOC-ID TX_QUEUE RX_QUEUE UID INODE LPORT "
0251                 "RPORT LADDRS <-> RADDRS "
0252                 "HBINT INS OUTS MAXRT T1X T2X RTXC "
0253                 "wmema wmemq sndbuf rcvbuf\n");
0254         return 0;
0255     }
0256 
0257     transport = (struct sctp_transport *)v;
0258     assoc = transport->asoc;
0259     epb = &assoc->base;
0260     sk = epb->sk;
0261 
0262     seq_printf(seq,
0263            "%8pK %8pK %-3d %-3d %-2d %-4d "
0264            "%4d %8d %8d %7u %5lu %-5d %5d ",
0265            assoc, sk, sctp_sk(sk)->type, sk->sk_state,
0266            assoc->state, 0,
0267            assoc->assoc_id,
0268            assoc->sndbuf_used,
0269            atomic_read(&assoc->rmem_alloc),
0270            from_kuid_munged(seq_user_ns(seq), sock_i_uid(sk)),
0271            sock_i_ino(sk),
0272            epb->bind_addr.port,
0273            assoc->peer.port);
0274     seq_printf(seq, " ");
0275     sctp_seq_dump_local_addrs(seq, epb);
0276     seq_printf(seq, "<-> ");
0277     sctp_seq_dump_remote_addrs(seq, assoc);
0278     seq_printf(seq, "\t%8lu %5d %5d %4d %4d %4d %8d "
0279            "%8d %8d %8d %8d",
0280         assoc->hbinterval, assoc->stream.incnt,
0281         assoc->stream.outcnt, assoc->max_retrans,
0282         assoc->init_retries, assoc->shutdown_retries,
0283         assoc->rtx_data_chunks,
0284         refcount_read(&sk->sk_wmem_alloc),
0285         sk->sk_wmem_queued,
0286         sk->sk_sndbuf,
0287         sk->sk_rcvbuf);
0288     seq_printf(seq, "\n");
0289 
0290     return 0;
0291 }
0292 
0293 static const struct seq_operations sctp_assoc_ops = {
0294     .start = sctp_transport_seq_start,
0295     .next  = sctp_transport_seq_next,
0296     .stop  = sctp_transport_seq_stop,
0297     .show  = sctp_assocs_seq_show,
0298 };
0299 
0300 static int sctp_remaddr_seq_show(struct seq_file *seq, void *v)
0301 {
0302     struct sctp_association *assoc;
0303     struct sctp_transport *transport, *tsp;
0304 
0305     if (v == SEQ_START_TOKEN) {
0306         seq_printf(seq, "ADDR ASSOC_ID HB_ACT RTO MAX_PATH_RTX "
0307                 "REM_ADDR_RTX START STATE\n");
0308         return 0;
0309     }
0310 
0311     transport = (struct sctp_transport *)v;
0312     assoc = transport->asoc;
0313 
0314     list_for_each_entry_rcu(tsp, &assoc->peer.transport_addr_list,
0315                 transports) {
0316         /*
0317          * The remote address (ADDR)
0318          */
0319         tsp->af_specific->seq_dump_addr(seq, &tsp->ipaddr);
0320         seq_printf(seq, " ");
0321         /*
0322          * The association ID (ASSOC_ID)
0323          */
0324         seq_printf(seq, "%d ", tsp->asoc->assoc_id);
0325 
0326         /*
0327          * If the Heartbeat is active (HB_ACT)
0328          * Note: 1 = Active, 0 = Inactive
0329          */
0330         seq_printf(seq, "%d ", timer_pending(&tsp->hb_timer));
0331 
0332         /*
0333          * Retransmit time out (RTO)
0334          */
0335         seq_printf(seq, "%lu ", tsp->rto);
0336 
0337         /*
0338          * Maximum path retransmit count (PATH_MAX_RTX)
0339          */
0340         seq_printf(seq, "%d ", tsp->pathmaxrxt);
0341 
0342         /*
0343          * remote address retransmit count (REM_ADDR_RTX)
0344          * Note: We don't have a way to tally this at the moment
0345          * so lets just leave it as zero for the moment
0346          */
0347         seq_puts(seq, "0 ");
0348 
0349         /*
0350          * remote address start time (START).  This is also not
0351          * currently implemented, but we can record it with a
0352          * jiffies marker in a subsequent patch
0353          */
0354         seq_puts(seq, "0 ");
0355 
0356         /*
0357          * The current state of this destination. I.e.
0358          * SCTP_ACTIVE, SCTP_INACTIVE, ...
0359          */
0360         seq_printf(seq, "%d", tsp->state);
0361 
0362         seq_printf(seq, "\n");
0363     }
0364 
0365     return 0;
0366 }
0367 
0368 static const struct seq_operations sctp_remaddr_ops = {
0369     .start = sctp_transport_seq_start,
0370     .next  = sctp_transport_seq_next,
0371     .stop  = sctp_transport_seq_stop,
0372     .show  = sctp_remaddr_seq_show,
0373 };
0374 
0375 /* Set up the proc fs entry for the SCTP protocol. */
0376 int __net_init sctp_proc_init(struct net *net)
0377 {
0378     net->sctp.proc_net_sctp = proc_net_mkdir(net, "sctp", net->proc_net);
0379     if (!net->sctp.proc_net_sctp)
0380         return -ENOMEM;
0381     if (!proc_create_net_single("snmp", 0444, net->sctp.proc_net_sctp,
0382              sctp_snmp_seq_show, NULL))
0383         goto cleanup;
0384     if (!proc_create_net("eps", 0444, net->sctp.proc_net_sctp,
0385             &sctp_eps_ops, sizeof(struct seq_net_private)))
0386         goto cleanup;
0387     if (!proc_create_net("assocs", 0444, net->sctp.proc_net_sctp,
0388             &sctp_assoc_ops, sizeof(struct sctp_ht_iter)))
0389         goto cleanup;
0390     if (!proc_create_net("remaddr", 0444, net->sctp.proc_net_sctp,
0391             &sctp_remaddr_ops, sizeof(struct sctp_ht_iter)))
0392         goto cleanup;
0393     return 0;
0394 
0395 cleanup:
0396     remove_proc_subtree("sctp", net->proc_net);
0397     net->sctp.proc_net_sctp = NULL;
0398     return -ENOMEM;
0399 }