📄 sctp_output.c
字号:
/***************************************************************************** @(#) sctp_output.c,v 0.7.8.1 2001/12/11 13:26:34 brian Exp ----------------------------------------------------------------------------- Copyright (C) 2001 OpenSS7 Corporation <http://www.openss7.com> All Rights Reserved. This program 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 of the License, or (at your option) any later version. This program 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 this program; if not, write to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. ----------------------------------------------------------------------------- U.S. GOVERNMENT RESTRICTED RIGHTS. If you are licensing this Software on behalf of the U.S. Government ("Government"), the following provisions apply to you. If the Software is supplied by the Department of Defense ("DoD"), it is classified as "Commercial Computer Software" under paragraph 252.227-7014 of the DoD Supplement to the Federal Acquisition Regulations ("DFARS") (or any successor regulations) and the Government is acquiring only the license rights granted herein (the license rights customarily provided to non-Government users). If the Software is supplied to any unit or agency of the Government other than DoD, it is classified as "Restricted Computer Software" and the Government's rights in the Software are defined in paragraph 52.227-19 of the Federal Acquisition Regulations ("FAR") (or any success regulations) or, in the cases of NASA, in paragraph 18.52.227-86 of the NASA Supplement to the FAR (or any successor regulations). ----------------------------------------------------------------------------- Last Modified 2001/12/11 13:26:34 by brian *****************************************************************************/#ident "@(#) sctp_output.c,v 0.7.8.1 2001/12/11 13:26:34 brian Exp"static char const ident[] = "SS7AlphaRelease(0.7.8.1) 2001/12/11 13:26:34";#define __NO_VERSION__#include <linux/config.h>#include <linux/version.h>#include <linux/modversions.h>#include <linux/module.h>#include <sys/stream.h>#include <sys/stropts.h>#include <sys/cmn_err.h>#include <sys/dki.h>#include "sctp_debug.h"#include "sctp_bufq.h"#include "sctp.h"#include "sctp_defs.h"#include "sctp_hash.h"#include "sctp_cache.h"#include "sctp_route.h"#undef min /* LiS should not have defined these */#undef max /* LiS should not have defined these */#define sctp_daddr sctp_daddr__#define sctp_saddr sctp_saddr__#define sctp_strm sctp_strm__#ifdef ASSERT#undef ASSERT#endif#include <net/ip.h>#include <net/icmp.h>#include <net/route.h>#undef sctp_daddr#undef sctp_saddr#undef sctp_strm#ifdef ASSERT#undef ASSERT#endif#include "sctp_msg.h"#include "sctp_output.h"#include <linux/skbuff.h>/* * XMIT OOTB (Disconnect Send with no Listening STREAM). * ------------------------------------------------------------------------- * This sends disconnected without a STREAM. All that is needed is a * destination address and a message block. The only time that we use this * is for responding to OOTB packets with ABORT or SHUTDOWN COMPLETE. */void sctp_xmit_ootb(daddr, saddr, mp) uint32_t daddr; uint32_t saddr; mblk_t *mp;{ usual( mp ); if ( mp ) { struct rtable *rt = NULL; if ( !ip_route_output(&rt, daddr, 0, 0, 0) ) { struct sk_buff *skb; struct device *dev = rt->u.dst.dev; size_t hlen = (dev->hard_header_len + 15) & ~15; size_t plen = msgdsize(mp); size_t tlen = plen + sizeof(struct iphdr); usual( hlen ); usual( plen ); if ( (skb = alloc_skb(hlen + tlen, GFP_ATOMIC)) ) { mblk_t *bp; struct iphdr *iph; struct sctphdr *sh; unsigned char *data; skb_reserve(skb, hlen); iph = (struct iphdr *)__skb_put(skb, tlen); sh = (struct sctphdr *)(iph+1); data = (unsigned char *)(sh); skb->dst = &rt->u.dst; iph->version = 4; iph->ihl = 5; iph->tos = 0; iph->frag_off = 0; iph->ttl = 0; iph->daddr = rt->rt_dst; iph->saddr = saddr; iph->protocol = 132; iph->tot_len = htons(tlen); iph->id = htons(ip_id_count++); skb->nh.iph = iph; for ( bp = mp; bp; bp = bp->b_cont ) { int blen = bp->b_wptr - bp->b_rptr; if ( blen > 0 ) { bcopy(bp->b_rptr, data, blen); data += blen; } else rare(); } sh->check = 0; sh->check = htonl(adler32(1L, (unsigned char *)sh, plen)); if ( tlen > rt->u.dst.pmtu ) { rare(); ip_fragment(skb, skb->dst->output); } else { iph->frag_off |= __constant_htons(IP_DF); ip_send_check(iph); skb->priority = 0; skb->dst->output(skb); } } else rare(); } else rare(); /* sending OOTB reponses are one time events, if we can't send the * message we just drop it, the peer will probably come back again * later */ freemsg(mp); } return;}/* * * XMIT MSG (Disconnected Send) * ------------------------------------------------------------------------- * This sends disconnected sends. All that is needed is a destination * address and a message block. The only time that we use this is for * sending INIT ACKs (because we have not built a complete stream yet, * however we do at least have a Listening STREAM or possibly an established * STREAM that is partially qualitfied and can provide some TOS and other * information for the packet. */void sctp_xmit_msg(daddr, mp, sp) uint32_t daddr; mblk_t *mp; sctp_t *sp;{ usual( mp ); if ( mp ) { struct rtable *rt = NULL; if ( !ip_route_output(&rt, daddr, 0, RT_TOS(sp->ip_tos)|sp->ip_dontroute, 0) ) { struct sk_buff *skb; struct device *dev = rt->u.dst.dev; size_t hlen = (dev->hard_header_len + 15) & ~15; size_t plen = msgdsize(mp); size_t tlen = plen + sizeof(struct iphdr); size_t alen = 0; usual( hlen ); usual( plen ); if ( (skb = alloc_skb(hlen + tlen, GFP_ATOMIC)) ) { mblk_t *bp; struct iphdr *iph; struct sctphdr *sh; unsigned char *data; skb_reserve(skb, hlen); iph = (struct iphdr *)__skb_put(skb, tlen); sh = (struct sctphdr *)(iph+1); data = (unsigned char *)(sh); skb->dst = &rt->u.dst; iph->version = 4; iph->ihl = 5; iph->tos = sp->ip_tos; iph->frag_off = 0; iph->ttl = sp->ip_ttl; iph->daddr = rt->rt_dst; iph->saddr = rt->rt_src; iph->protocol = sp->ip_proto; iph->tot_len = htons(tlen); iph->id = htons(ip_id_count++); skb->nh.iph = iph; for ( bp = mp; bp; bp = bp->b_cont ) { int blen = bp->b_wptr - bp->b_rptr; if ( blen > 0 ) { bcopy(bp->b_rptr, data, blen); data += blen; alen += blen; } else rare(); } sh->check = 0; sh->check = htonl(adler32(1L, (unsigned char *)sh, plen)); if ( tlen > rt->u.dst.pmtu ) { rare(); ip_fragment(skb, skb->dst->output); } else { iph->frag_off |= __constant_htons(IP_DF); ip_send_check(iph); skb->priority = sp->ip_priority; skb->dst->output(skb); } } else rare(); } else rare(); /* sending INIT ACKs are one time events, if we can't get the * response off, we just drop the INIT ACK: the peer should send us * another INIT in a short while... */ freemsg(mp); } return;}/* * SEND MSG (Connected Send) * ------------------------------------------------------------------------- * This sends connected sends. It requires a STREAM a desination address * structure and a message block. This function does not free the message * block. The caller is responsible for the message block. */static int break_packets = 0;static int seed = 152;static unsigned char random(void){ return (unsigned char) (seed = seed * 60691 + 1);}void sctp_send_msg(sp, sd, mp) sctp_t *sp; sctp_daddr_t *sd; mblk_t *mp;{ int tried_update; ensure( sp, return ); if ( mp ) { if ( sd ) { for ( tried_update = 0; !tried_update; sctp_update_routes(sp,1), tried_update++ ) { if ( sd->dst_cache && !sd->dst_cache->obsolete ) { struct sk_buff *skb; struct device *dev; size_t hlen, plen, tlen;#ifdef ERROR_GENERATOR if ( (sp->options & SCTP_OPTION_DBREAK) && sd->daddr == 0x010000ff && ++break_packets> BREAK_GENERATOR_LEVEL ) { if ( break_packets > BREAK_GENERATOR_LIMIT ) break_packets = 0; return; } if ( (sp->options & SCTP_OPTION_BREAK) && (sd == sp->daddr || sd == sp->daddr->next) && ++sd->packets > BREAK_GENERATOR_LEVEL ) { return; } if ( (sp->options & SCTP_OPTION_DROPPING) && ++sd->packets > ERROR_GENERATOR_LEVEL ) { if ( sd->packets > ERROR_GENERATOR_LIMIT ) sd->packets = 0; return; } if ( (sp->options & SCTP_OPTION_RANDOM) && ++sd->packets > 2*ERROR_GENERATOR_LEVEL ) { if ( !(random() & 0x03) ) return; }#endif dev = sd->dst_cache->dev; plen = SCTP_TCB(mp)->dlen; hlen = (dev->hard_header_len + 15) & ~15; tlen = sizeof(struct iphdr) + plen; unusual( plen == 0 || plen > 5000 ); if ( (skb = alloc_skb(hlen + tlen, GFP_ATOMIC)) ) { mblk_t *bp; struct iphdr *iph; struct sctphdr *sh; unsigned char *head, *data; size_t alen = 0; skb_reserve(skb, hlen); iph = (struct iphdr *)__skb_put(skb, tlen); sh = (struct sctphdr *)(iph+1); data = (unsigned char *)(sh); head = data; skb->dst = dst_clone(sd->dst_cache); iph->version = 4; iph->ihl = 5; iph->tos = sp->ip_tos; iph->frag_off = 0; iph->ttl = sp->ip_ttl; iph->daddr = sd->daddr; iph->saddr = sd->saddr; iph->protocol = sp->ip_proto; iph->tot_len = htons(tlen); iph->id = htons(ip_id_count++); skb->nh.iph = iph; for ( bp = mp; bp; bp = bp->b_next ) { mblk_t *db; size_t clen = 0; sctp_tcb_t *cb = SCTP_TCB(bp); cb->daddr = sd; cb->when = jiffies; cb->flags |= SCTPCB_FLAG_SENT; cb->trans++; for ( db = bp; db; db = db->b_cont ) { int blen = db->b_wptr - db->b_rptr; normal( db->b_datap->db_type == M_DATA ); if ( db->b_datap->db_type == M_DATA ) { normal( blen > 0 ); if ( blen > 0 ) { ensure( head + plen >= data + blen, kfree_skb(skb); return ); bcopy(db->b_rptr, data, blen); data += blen; clen += blen; } } } { /* pad each chunk if not padded already */ size_t pad = PADC(clen) - clen; ensure( head + plen >= data + pad, kfree_skb(skb); return ); bzero(data, pad); data += pad; alen += clen+pad; } } if ( alen != plen ) { usual( alen == plen ); ptrace(("alen = %u, plen = %u discarding\n", alen, plen)); kfree_skb(skb); return; } sh->check = 0; sh->check = htonl(adler32(1L, (unsigned char *)sh, plen)); if ( tlen > sd->mtu ) { rare(); ip_fragment(skb, skb->dst->output); } else { iph->frag_off |= __constant_htons(IP_DF); ip_send_check(iph); skb->priority = sp->ip_priority; skb->dst->output(skb); } /* * Whenever we transmit something, we expect a reply to our v_tag, so * we put ourselves in the 1st level vtag caches expecting a quick * reply. */ if ( !((1<<sp->s_state) & (SCTPF_CLOSED|SCTPF_LISTEN)) ) sctp_cache[sp->hashent] = sp; break; } else rare(); } else usual( sd->dst_cache && !sd->dst_cache->obsolete ); } } else { usual( sd ); sctp_update_routes(sp,1); } } else usual( mp );}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -