| 2454 | |
| 2455 | #ifdef INET |
| 2456 | void |
| 2457 | tcp_ctlinput(int cmd, struct sockaddr *sa, void *vip) |
| 2458 | { |
| 2459 | struct ip *ip = vip; |
| 2460 | struct tcphdr *th; |
| 2461 | struct in_addr faddr; |
| 2462 | struct inpcb *inp; |
| 2463 | struct tcpcb *tp; |
| 2464 | struct inpcb *(*notify)(struct inpcb *, int) = tcp_notify; |
| 2465 | struct icmp *icp; |
| 2466 | struct in_conninfo inc; |
| 2467 | tcp_seq icmp_tcp_seq; |
| 2468 | int mtu; |
| 2469 | |
| 2470 | faddr = ((struct sockaddr_in *)sa)->sin_addr; |
| 2471 | if (sa->sa_family != AF_INET || faddr.s_addr == INADDR_ANY) |
| 2472 | return; |
| 2473 | |
| 2474 | if (cmd == PRC_MSGSIZE) |
| 2475 | notify = tcp_mtudisc_notify; |
| 2476 | else if (V_icmp_may_rst && (cmd == PRC_UNREACH_ADMIN_PROHIB || |
| 2477 | cmd == PRC_UNREACH_PORT || cmd == PRC_UNREACH_PROTOCOL || |
| 2478 | cmd == PRC_TIMXCEED_INTRANS) && ip) |
| 2479 | notify = tcp_drop_syn_sent; |
| 2480 | |
| 2481 | /* |
| 2482 | * Hostdead is ugly because it goes linearly through all PCBs. |
| 2483 | * XXX: We never get this from ICMP, otherwise it makes an |
| 2484 | * excellent DoS attack on machines with many connections. |
| 2485 | */ |
| 2486 | else if (cmd == PRC_HOSTDEAD) |
| 2487 | ip = NULL; |
| 2488 | else if ((unsigned)cmd >= PRC_NCMDS || inetctlerrmap[cmd] == 0) |
| 2489 | return; |
| 2490 | |
| 2491 | if (ip == NULL) { |
| 2492 | in_pcbnotifyall(&V_tcbinfo, faddr, inetctlerrmap[cmd], notify); |
| 2493 | return; |
| 2494 | } |
| 2495 | |
| 2496 | icp = (struct icmp *)((caddr_t)ip - offsetof(struct icmp, icmp_ip)); |
| 2497 | th = (struct tcphdr *)((caddr_t)ip + (ip->ip_hl << 2)); |
| 2498 | inp = in_pcblookup(&V_tcbinfo, faddr, th->th_dport, ip->ip_src, |
| 2499 | th->th_sport, INPLOOKUP_WLOCKPCB, NULL); |
| 2500 | if (inp != NULL && PRC_IS_REDIRECT(cmd)) { |
| 2501 | /* signal EHOSTDOWN, as it flushes the cached route */ |
| 2502 | inp = (*notify)(inp, EHOSTDOWN); |
| 2503 | goto out; |
| 2504 | } |
| 2505 | icmp_tcp_seq = th->th_seq; |
| 2506 | if (inp != NULL) { |
| 2507 | if (!(inp->inp_flags & INP_TIMEWAIT) && |
| 2508 | !(inp->inp_flags & INP_DROPPED) && |
| 2509 | !(inp->inp_socket == NULL)) { |
| 2510 | tp = intotcpcb(inp); |
| 2511 | if (SEQ_GEQ(ntohl(icmp_tcp_seq), tp->snd_una) && |
| 2512 | SEQ_LT(ntohl(icmp_tcp_seq), tp->snd_max)) { |
| 2513 | if (cmd == PRC_MSGSIZE) { |
nothing calls this directly
no test coverage detected