📄 input.c
字号:
struct sctp_endpoint *ep; struct sctp_association *asoc; struct sctp_transport *transport; struct inet_sock *inet; char *saveip, *savesctp; int err; if (skb->len < ((iph->ihl << 2) + 8)) { ICMP_INC_STATS_BH(ICMP_MIB_INERRORS); return; } /* Fix up skb to look at the embedded net header. */ saveip = skb->nh.raw; savesctp = skb->h.raw; skb->nh.iph = iph; skb->h.raw = (char *)sh; sk = sctp_err_lookup(AF_INET, skb, sh, &ep, &asoc, &transport); /* Put back, the original pointers. */ skb->nh.raw = saveip; skb->h.raw = savesctp; if (!sk) { ICMP_INC_STATS_BH(ICMP_MIB_INERRORS); return; } /* Warning: The sock lock is held. Remember to call * sctp_err_finish! */ switch (type) { case ICMP_PARAMETERPROB: err = EPROTO; break; case ICMP_DEST_UNREACH: if (code > NR_ICMP_UNREACH) goto out_unlock; /* PMTU discovery (RFC1191) */ if (ICMP_FRAG_NEEDED == code) { sctp_icmp_frag_needed(sk, asoc, transport, info); goto out_unlock; } else { if (ICMP_PROT_UNREACH == code) { sctp_icmp_proto_unreachable(sk, ep, asoc, transport); goto out_unlock; } } err = icmp_err_convert[code].errno; break; case ICMP_TIME_EXCEEDED: /* Ignore any time exceeded errors due to fragment reassembly * timeouts. */ if (ICMP_EXC_FRAGTIME == code) goto out_unlock; err = EHOSTUNREACH; break; default: goto out_unlock; } inet = inet_sk(sk); if (!sock_owned_by_user(sk) && inet->recverr) { sk->sk_err = err; sk->sk_error_report(sk); } else { /* Only an error on timeout */ sk->sk_err_soft = err; }out_unlock: sctp_err_finish(sk, ep, asoc);}/* * RFC 2960, 8.4 - Handle "Out of the blue" Packets. * * This function scans all the chunks in the OOTB packet to determine if * the packet should be discarded right away. If a response might be needed * for this packet, or, if further processing is possible, the packet will * be queued to a proper inqueue for the next phase of handling. * * Output: * Return 0 - If further processing is needed. * Return 1 - If the packet can be discarded right away. */int sctp_rcv_ootb(struct sk_buff *skb){ sctp_chunkhdr_t *ch; __u8 *ch_end; sctp_errhdr_t *err; ch = (sctp_chunkhdr_t *) skb->data; ch_end = ((__u8 *) ch) + WORD_ROUND(ntohs(ch->length)); /* Scan through all the chunks in the packet. */ while (ch_end > (__u8 *)ch && ch_end < skb->tail) { /* RFC 8.4, 2) If the OOTB packet contains an ABORT chunk, the * receiver MUST silently discard the OOTB packet and take no * further action. */ if (SCTP_CID_ABORT == ch->type) goto discard; /* RFC 8.4, 6) If the packet contains a SHUTDOWN COMPLETE * chunk, the receiver should silently discard the packet * and take no further action. */ if (SCTP_CID_SHUTDOWN_COMPLETE == ch->type) goto discard; /* RFC 8.4, 7) If the packet contains a "Stale cookie" ERROR * or a COOKIE ACK the SCTP Packet should be silently * discarded. */ if (SCTP_CID_COOKIE_ACK == ch->type) goto discard; if (SCTP_CID_ERROR == ch->type) { sctp_walk_errors(err, ch) { if (SCTP_ERROR_STALE_COOKIE == err->cause) goto discard; } } ch = (sctp_chunkhdr_t *) ch_end; ch_end = ((__u8 *) ch) + WORD_ROUND(ntohs(ch->length)); } return 0;discard: return 1;}/* Insert endpoint into the hash table. */static void __sctp_hash_endpoint(struct sctp_endpoint *ep){ struct sctp_ep_common **epp; struct sctp_ep_common *epb; struct sctp_hashbucket *head; epb = &ep->base; epb->hashent = sctp_ep_hashfn(epb->bind_addr.port); head = &sctp_ep_hashtable[epb->hashent]; sctp_write_lock(&head->lock); epp = &head->chain; epb->next = *epp; if (epb->next) (*epp)->pprev = &epb->next; *epp = epb; epb->pprev = epp; sctp_write_unlock(&head->lock);}/* Add an endpoint to the hash. Local BH-safe. */void sctp_hash_endpoint(struct sctp_endpoint *ep){ sctp_local_bh_disable(); __sctp_hash_endpoint(ep); sctp_local_bh_enable();}/* Remove endpoint from the hash table. */static void __sctp_unhash_endpoint(struct sctp_endpoint *ep){ struct sctp_hashbucket *head; struct sctp_ep_common *epb; epb = &ep->base; epb->hashent = sctp_ep_hashfn(epb->bind_addr.port); head = &sctp_ep_hashtable[epb->hashent]; sctp_write_lock(&head->lock); if (epb->pprev) { if (epb->next) epb->next->pprev = epb->pprev; *epb->pprev = epb->next; epb->pprev = NULL; } sctp_write_unlock(&head->lock);}/* Remove endpoint from the hash. Local BH-safe. */void sctp_unhash_endpoint(struct sctp_endpoint *ep){ sctp_local_bh_disable(); __sctp_unhash_endpoint(ep); sctp_local_bh_enable();}/* Look up an endpoint. */static struct sctp_endpoint *__sctp_rcv_lookup_endpoint(const union sctp_addr *laddr){ struct sctp_hashbucket *head; struct sctp_ep_common *epb; struct sctp_endpoint *ep; int hash; hash = sctp_ep_hashfn(laddr->v4.sin_port); head = &sctp_ep_hashtable[hash]; read_lock(&head->lock); for (epb = head->chain; epb; epb = epb->next) { ep = sctp_ep(epb); if (sctp_endpoint_is_match(ep, laddr)) goto hit; } ep = sctp_sk((sctp_get_ctl_sock()))->ep; epb = &ep->base;hit: sctp_endpoint_hold(ep); sock_hold(epb->sk); read_unlock(&head->lock); return ep;}/* Insert association into the hash table. */static void __sctp_hash_established(struct sctp_association *asoc){ struct sctp_ep_common **epp; struct sctp_ep_common *epb; struct sctp_hashbucket *head; epb = &asoc->base; /* Calculate which chain this entry will belong to. */ epb->hashent = sctp_assoc_hashfn(epb->bind_addr.port, asoc->peer.port); head = &sctp_assoc_hashtable[epb->hashent]; sctp_write_lock(&head->lock); epp = &head->chain; epb->next = *epp; if (epb->next) (*epp)->pprev = &epb->next; *epp = epb; epb->pprev = epp; sctp_write_unlock(&head->lock);}/* Add an association to the hash. Local BH-safe. */void sctp_hash_established(struct sctp_association *asoc){ sctp_local_bh_disable(); __sctp_hash_established(asoc); sctp_local_bh_enable();}/* Remove association from the hash table. */static void __sctp_unhash_established(struct sctp_association *asoc){ struct sctp_hashbucket *head; struct sctp_ep_common *epb; epb = &asoc->base; epb->hashent = sctp_assoc_hashfn(epb->bind_addr.port, asoc->peer.port); head = &sctp_assoc_hashtable[epb->hashent]; sctp_write_lock(&head->lock); if (epb->pprev) { if (epb->next) epb->next->pprev = epb->pprev; *epb->pprev = epb->next; epb->pprev = NULL; } sctp_write_unlock(&head->lock);}/* Remove association from the hash table. Local BH-safe. */void sctp_unhash_established(struct sctp_association *asoc){ sctp_local_bh_disable(); __sctp_unhash_established(asoc); sctp_local_bh_enable();}/* Look up an association. */static struct sctp_association *__sctp_lookup_association( const union sctp_addr *local, const union sctp_addr *peer, struct sctp_transport **pt){ struct sctp_hashbucket *head; struct sctp_ep_common *epb; struct sctp_association *asoc; struct sctp_transport *transport; int hash; /* Optimize here for direct hit, only listening connections can * have wildcards anyways. */ hash = sctp_assoc_hashfn(local->v4.sin_port, peer->v4.sin_port); head = &sctp_assoc_hashtable[hash]; read_lock(&head->lock); for (epb = head->chain; epb; epb = epb->next) { asoc = sctp_assoc(epb); transport = sctp_assoc_is_match(asoc, local, peer); if (transport) goto hit; } read_unlock(&head->lock); return NULL;hit: *pt = transport; sctp_association_hold(asoc); sock_hold(epb->sk); read_unlock(&head->lock); return asoc;}/* Look up an association. BH-safe. */SCTP_STATICstruct sctp_association *sctp_lookup_association(const union sctp_addr *laddr, const union sctp_addr *paddr, struct sctp_transport **transportp){ struct sctp_association *asoc; sctp_local_bh_disable(); asoc = __sctp_lookup_association(laddr, paddr, transportp); sctp_local_bh_enable(); return asoc;}/* Is there an association matching the given local and peer addresses? */int sctp_has_association(const union sctp_addr *laddr, const union sctp_addr *paddr){ struct sctp_association *asoc; struct sctp_transport *transport; if ((asoc = sctp_lookup_association(laddr, paddr, &transport))) { sock_put(asoc->base.sk); sctp_association_put(asoc); return 1; } return 0;}/* * SCTP Implementors Guide, 2.18 Handling of address * parameters within the INIT or INIT-ACK. * * D) When searching for a matching TCB upon reception of an INIT * or INIT-ACK chunk the receiver SHOULD use not only the * source address of the packet (containing the INIT or * INIT-ACK) but the receiver SHOULD also use all valid * address parameters contained within the chunk. * * 2.18.3 Solution description * * This new text clearly specifies to an implementor the need * to look within the INIT or INIT-ACK. Any implementation that * does not do this, may not be able to establish associations * in certain circumstances. * */static struct sctp_association *__sctp_rcv_init_lookup(struct sk_buff *skb, const union sctp_addr *laddr, struct sctp_transport **transportp){ struct sctp_association *asoc; union sctp_addr addr; union sctp_addr *paddr = &addr; struct sctphdr *sh = (struct sctphdr *) skb->h.raw; sctp_chunkhdr_t *ch; union sctp_params params; sctp_init_chunk_t *init; struct sctp_transport *transport; struct sctp_af *af; ch = (sctp_chunkhdr_t *) skb->data; /* If this is INIT/INIT-ACK look inside the chunk too. */ switch (ch->type) { case SCTP_CID_INIT: case SCTP_CID_INIT_ACK: break; default: return NULL; } /* The code below will attempt to walk the chunk and extract * parameter information. Before we do that, we need to verify * that the chunk length doesn't cause overflow. Otherwise, we'll * walk off the end. */ if (WORD_ROUND(ntohs(ch->length)) > skb->len) return NULL; /* * This code will NOT touch anything inside the chunk--it is * strictly READ-ONLY. * * RFC 2960 3 SCTP packet Format * * Multiple chunks can be bundled into one SCTP packet up to * the MTU size, except for the INIT, INIT ACK, and SHUTDOWN * COMPLETE chunks. These chunks MUST NOT be bundled with any * other chunk in a packet. See Section 6.10 for more details * on chunk bundling. */ /* Find the start of the TLVs and the end of the chunk. This is * the region we search for address parameters. */ init = (sctp_init_chunk_t *)skb->data; /* Walk the parameters looking for embedded addresses. */ sctp_walk_params(params, init, init_hdr.params) { /* Note: Ignoring hostname addresses. */ af = sctp_get_af_specific(param_type2af(params.p->type)); if (!af) continue; af->from_addr_param(paddr, params.addr, ntohs(sh->source), 0); asoc = __sctp_lookup_association(laddr, paddr, &transport); if (asoc) return asoc; } return NULL;}/* Lookup an association for an inbound skb. */static struct sctp_association *__sctp_rcv_lookup(struct sk_buff *skb, const union sctp_addr *paddr, const union sctp_addr *laddr, struct sctp_transport **transportp){ struct sctp_association *asoc; asoc = __sctp_lookup_association(laddr, paddr, transportp); /* Further lookup for INIT/INIT-ACK packets. * SCTP Implementors Guide, 2.18 Handling of address * parameters within the INIT or INIT-ACK. */ if (!asoc) asoc = __sctp_rcv_init_lookup(skb, laddr, transportp); return asoc;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -