/* * igmp_handler - handles the incoming IGMP packets * * void igmp_handler (in_Header *ip) * Where: * ip is the IP packet in question * * Returns: None * */ void igmp_handler (const in_Header *ip, BOOL broadcast) { BYTE i; DWORD host; BOOL found = 0; WORD len = in_GetHdrLen (ip); IGMP_packet *igmp = (IGMP_packet*) ((BYTE*)ip + len); DEBUG_RX (NULL, ip); if (len < sizeof(*igmp)) { STAT (igmpstats.igps_rcv_tooshort++); return; } if (checksum(igmp,sizeof(*igmp)) != 0xFFFF) { STAT (igmpstats.igps_rcv_badsum++); return; } host = intel (igmp->address); /* Determine whether this is a report or a query */ switch (igmp->type) { case IGMP_QUERY: STAT (igmpstats.igps_rcv_queries++); for (i = 0; i < IPMULTI_SIZE; i++) if (_ipmulti[i].active && _ipmulti[i].ina != ALL_SYSTEMS && _ipmulti[i].replytime == 0) { _ipmulti[i].replytime = set_timeout (Random(500,1000)); found = 1; } if (!found && !broadcast) STAT (igmpstats.igps_rcv_badqueries++); break; case IGMP_REPORT: STAT (igmpstats.igps_rcv_reports++); for (i = 0; i < IPMULTI_SIZE; i++) if (_ipmulti[i].active && _ipmulti[i].ina == host && host != ALL_SYSTEMS) { _ipmulti[i].replytime = 0; found = 1; STAT (igmpstats.igps_rcv_ourreports++); break; } if (!found && !broadcast) STAT (igmpstats.igps_rcv_badreports++); break; } }
/** * Handle incoming PPPoE packets. */ int pppoe_handler (const pppoe_Packet *pkt) { const BYTE *buf; const void *src; const void *dst; WORD proto, len; BOOL bcast, delivered = FALSE; if (pkt->type != 1 || pkt->ver != 1) return (0); src = MAC_SRC (pkt); dst = MAC_DST (pkt); proto = MAC_TYP (pkt); bcast = !memcmp (dst, _eth_brdcast, _eth_mac_len); if (proto == PPPOE_SESS_TYPE && state == StateSession) { if (pkt->code == PPPOE_CODE_SESS && pkt->session == session && !bcast && !memcmp(dst, _eth_addr, _eth_mac_len) && /* to us? */ !memcmp(src, ac_macAddr, _eth_mac_len)) { len = intel16 (pkt->length); buf = &pkt->data[0]; ppp_input (buf, len); /* assume ppp_input() traces it */ delivered = TRUE; } } else if (!bcast && proto == PPPOE_DISC_TYPE && state == StateDiscovery) { if (pkt->code == PPPOE_CODE_PADO) /* Offer (can this be bcast?) */ { got_PADO = TRUE; memcpy (ac_macAddr, src, _eth_mac_len); } else if (pkt->code == PPPOE_CODE_PADT && /* Terminate */ pkt->session == session) { if (cfg.trace) outsnl (_LANG("PPPoE: session terminated")); got_PADT = TRUE; session = 0; } else if (pkt->code == PPPOE_CODE_PADS) /* Session-confirmation */ { got_PADS = TRUE; session = pkt->session; } else if (pkt->code == PPPOE_CODE_PADM) /* Message (what to do?) */ { got_PADM = TRUE; } } if (!delivered) DEBUG_RX (NULL, pkt); return (1); }
/* * Fix the LLC header to look like ordinary Ethernet II * !! not yet. */ static void fix_llc_head (void **mac) { SIO_TRACE (("fix_llc_head")); #if 1 DEBUG_RX (NULL, *mac); _eth_free (*mac); *mac = NULL; #else /** \todo handle IEEE 802.3 encapsulation also. */ #endif }
/** * Handle incoming RARP packets. */ BOOL _rarp_handler (const rarp_Header *rh, BOOL brdcast) { SIO_TRACE (("_rarp_handler")); DEBUG_RX (NULL, rh); if (!brdcast && rh->opcode == RARP_REPLY && rh->protType == IP4_TYPE && !memcmp(rh->dstEthAddr,_eth_addr,sizeof(mac_address))) { my_ip_addr = intel (rh->dstIPAddr); return (TRUE); } return (FALSE); }
/* * _dorarp - Checks global variable _rarptimeout * returns 1 on success and sets ip address */ int _dorarp (void) { DWORD rarptimeout = set_timeout (1000 * _rarptimeout); WORD magictimeout = Random (7000, 14000); outs (_LANG("Configuring through RARP...")); while (1) { DWORD sendtimeout; if (!_rarp_request()) break; sendtimeout = set_timeout (magictimeout); magictimeout += Random (1000, 7000); while (!chk_timeout(sendtimeout)) { const struct rarp_Header *rarp; WORD eth_type; BOOL bcast; if (chk_timeout(rarptimeout)) return (0); WATT_YIELD(); rarp = (rarp_Header*) _eth_arrived (ð_type, &bcast); if (!rarp) continue; DEBUG_RX (NULL, rarp); if (eth_type == RARP_TYPE && !bcast && rarp->opcode == RARP_REPLY && rarp->protType == IP4_TYPE && !memcmp(rarp->dstEthAddr,_eth_addr,sizeof(mac_address))) { my_ip_addr = intel (rarp->dstIPAddr); _eth_free (rarp); return (1); } _eth_free (rarp); } } return (0); }
/* * Handler for incoming ICMP packets */ void icmp_handler (const in_Header *ip, BOOL broadcast) { union icmp_pkt *icmp; in_Header *orig_ip; int len, type, code; BOOL for_me, i_orig; /* is it for me, did I originate it */ const char *msg; DEBUG_RX (NULL, ip); if (block_icmp) /* application is handling ICMP; not needed */ return; len = in_GetHdrLen (ip); icmp = (union icmp_pkt*) ((BYTE*)ip + len); len = intel16 (ip->length) - len; for_me = (DWORD) (intel(ip->destination) - my_ip_addr) <= multihomes; if (!for_me || broadcast) /* drop broadcast pings.. */ return; if (len < sizeof(icmp->info)) { STAT (icmpstats.icps_tooshort++); return; } if (checksum(icmp,len) != 0xFFFF) { STAT (icmpstats.icps_checksum++); icmp_print (1, _LANG("bad checksum"), ip->source); return; } type = icmp->unused.type; code = icmp->unused.code; orig_ip = &icmp->ip.ip; i_orig = is_local_addr (intel(orig_ip->source)); if (type == ICMP_MASKREPLY) { if (!_domask_req) return; i_orig = TRUE; } /* !! this needs work */ if (!i_orig && (type != ICMP_ECHOREPLY && type != ICMP_ECHO && type != ICMP_IREQREPLY && type != ICMP_TSTAMP)) { icmp_bogus (ip, type, NULL); return; } switch (type) { case ICMP_ECHOREPLY: /* check if we were waiting for it */ STAT (icmpstats.icps_inhist[ICMP_ECHOREPLY]++); ping_hcache = intel (ip->source); ping_tcache = set_timeout (1000) - *(DWORD*)&icmp->echo.identifier; if (ping_tcache > 0x7FFFFFFFL) ping_tcache += 0x1800B0L; ping_number = *(DWORD*)(((BYTE*)&icmp->echo.identifier) + 4); return; case ICMP_UNREACH: STAT (icmpstats.icps_inhist[ICMP_UNREACH]++); if (code < DIM(icmp_unreach_str)) { icmp_print (1, msg = icmp_unreach_str[code], ip->source); #if !defined(USE_UDP_ONLY) if (orig_ip->proto == TCP_PROTO) _tcp_cancel (orig_ip, type, msg, 0); else #endif if (orig_ip->proto == UDP_PROTO) _udp_cancel (orig_ip, type, msg, 0); } else STAT (icmpstats.icps_badcode++); return; case ICMP_SOURCEQUENCH: STAT (icmpstats.icps_inhist[ICMP_SOURCEQUENCH]++); #if !defined(USE_UDP_ONLY) if (orig_ip->proto == TCP_PROTO) { icmp_print (1, _LANG("Source Quench"), ip->source); _tcp_cancel (orig_ip, type, NULL, 0); } #endif return; case ICMP_REDIRECT: STAT (icmpstats.icps_inhist[ICMP_REDIRECT]++); if (code < 4) { DWORD new_gw = intel (icmp->ip.ipaddr); /* Check if new gateway is on our subnet */ if ((new_gw ^ my_ip_addr) & sin_mask) { char buf[100], adr[20]; strcpy (buf, ", GW = "); strcat (buf, _inet_ntoa(adr,new_gw)); icmp_bogus (ip, type, buf); return; } icmp_print (1, msg = icmp_redirect_str[code], ip->source); switch (orig_ip->proto) { #if !defined(USE_UDP_ONLY) case TCP_PROTO: if (do_redirect.tcp) /* do it to some socket */ _tcp_cancel (orig_ip, type, msg, new_gw); break; #endif case UDP_PROTO: if (do_redirect.udp) _udp_cancel (orig_ip, type, msg, new_gw); break; case ICMP_PROTO: if (do_redirect.icmp) { _ip_recursion = 1; _arp_register (new_gw, intel(orig_ip->destination), 0); _ip_recursion = 0; } break; case IGMP_PROTO: if (do_redirect.igmp) { _ip_recursion = 1; _arp_register (new_gw, intel(orig_ip->destination), 0); _ip_recursion = 0; } break; } } else STAT (icmpstats.icps_badcode++); return; case ICMP_ECHO: STAT (icmpstats.icps_inhist[ICMP_ECHO]++); icmp_print (2, _LANG("PING requested of us"), ip->source); { /* Extract eth-address and create Echo reply packet. */ struct _pkt *pkt; union icmp_pkt *newicmp; if (!icmp_chk_src(ip,ICMP_ECHO)) return; pkt = (struct _pkt*) _eth_formatpacket (MAC_SRC(ip), IP_TYPE); newicmp = &pkt->icmp; /* Don't let a huge reassembled ICMP-packet kill us. */ len = min (len, mtu - sizeof(*ip)); memcpy (newicmp, icmp, len); newicmp->echo.type = ICMP_ECHOREPLY; newicmp->echo.code = code; /* Use supplied ip values in case we ever multi-home. * Note that ip values are still in network order. */ icmp_send (pkt, ip->destination, ip->source, len); icmp_print (2, _LANG("PING reply sent"), 0); } return; case ICMP_TIMXCEED: if (code >= DIM(icmp_exceed_str)) { STAT (icmpstats.icps_badcode++); return; } STAT (icmpstats.icps_inhist[ICMP_TIMXCEED]++); if (code != 1) switch (orig_ip->proto) { #if !defined(USE_UDP_ONLY) case TCP_PROTO: icmp_print (1, icmp_exceed_str[code], ip->source); _tcp_cancel (orig_ip, ICMP_TIMXCEED, NULL, 0); break; #endif case UDP_PROTO: icmp_print (1, icmp_exceed_str[code], ip->source); _udp_cancel (orig_ip, ICMP_TIMXCEED, NULL, 0); break; } return; case ICMP_PARAMPROB: STAT (icmpstats.icps_inhist[ICMP_PARAMPROB]++); switch (orig_ip->proto) { #if !defined(USE_UDP_ONLY) case TCP_PROTO: icmp_print (0, _LANG(icmp_type_str[type]), ip->source); _tcp_cancel (orig_ip, type, NULL, 0); break; #endif case UDP_PROTO: icmp_print (0, _LANG(icmp_type_str[type]), ip->source); _udp_cancel (orig_ip, type, NULL, 0); break; } return; case ICMP_ROUTERADVERT: /* todo !! */ STAT (icmpstats.icps_inhist[ICMP_ROUTERADVERT]++); icmp_print (1, _LANG(icmp_type_str[type]), ip->source); return; case ICMP_ROUTERSOLICIT: /* todo !! */ STAT (icmpstats.icps_inhist[ICMP_ROUTERSOLICIT]++); icmp_print (1, _LANG(icmp_type_str[type]), ip->source); return; case ICMP_TSTAMP: STAT (icmpstats.icps_inhist[ICMP_TSTAMP]++); icmp_print (1, _LANG(icmp_type_str[type]), ip->source); /* todo!!, send reply? */ return; case ICMP_TSTAMPREPLY: STAT (icmpstats.icps_inhist[ICMP_TSTAMPREPLY]++); icmp_print (1, _LANG(icmp_type_str[type]), ip->source); /* todo!!, should store */ return; case ICMP_IREQ: STAT (icmpstats.icps_inhist[ICMP_IREQ]++); icmp_print (1, _LANG(icmp_type_str[type]), ip->source); /* todo!!, send reply */ return; case ICMP_IREQREPLY: STAT (icmpstats.icps_inhist[ICMP_IREQREPLY]++); icmp_print (1, _LANG(icmp_type_str[type]), ip->source); /* todo!!, send reply upwards */ return; case ICMP_MASKREQ: STAT (icmpstats.icps_inhist[ICMP_MASKREQ]++); break; case ICMP_MASKREPLY: STAT (icmpstats.icps_inhist[ICMP_MASKREPLY]++); icmp_print (0, _LANG(icmp_type_str[type]), ip->source); if ((icmp->mask.identifier == addr_mask_id) && (icmp->mask.sequence == addr_mask_seq-1) && sin_mask != intel(icmp->mask.mask)) outsnl ("Conflicting net-mask from \"ICMP Addr Mask Reply\"\7"); addr_mask_id = 0; return; } }
/** * Poll the packet queue. Return first packet in queue. * Optionally do receiver profiling. * * \retval pointer to start of MAC-header. * \retval NULL no packets are queued. * * \note Not used when e.g. libpcap has set the `_eth_recv_hook' to * do it's own packet-polling. * \note 'type' is always set. */ static union link_Packet *poll_recv_queue (WORD *type) { #if defined(USE_FAST_PKT) || defined(WIN32) struct pkt_rx_element *buf; #endif struct pkt_ringbuf *q = &_pkt_inf->pkt_queue; union link_Packet *pkt; struct in_Header *ip; SIO_TRACE (("poll_recv_queue")); ASSERT_PKT_INF (NULL); #if defined(USE_DEBUG) #if defined(USE_FAST_PKT) if (!pktq_far_check(q)) #else if (!pktq_check(q)) #endif { fprintf (stderr, "%s: pkt-queue destroyed!\n", __FILE__); exit (-1); } #endif #if defined(WIN32) buf = pkt_poll_recv(); if (!buf) return (NULL); PROFILE_RECV ((uint64*)&buf->tstamp_put, (uint64*)&buf->tstamp_get); _eth_last.rx.size = buf->rx_length; _eth_last.rx.tstamp.lo = 0UL; /* no need yet */ _eth_last.rx.tstamp.hi = 0UL; pkt = (link_Packet*) &buf->rx_buf[0]; #elif defined(USE_FAST_PKT) buf = pkt_poll_recv(); if (!buf) return (NULL); PROFILE_RECV ((uint64*)buf->tstamp_put, (uint64*)buf->tstamp_get); pkt = (link_Packet*) buf->rx_buf; _eth_last.rx.size = buf->rx_length_1; /* length on 1st upcall */ _eth_last.rx.tstamp.lo = buf->tstamp_put[0]; /* TSC set in asmpkt */ _eth_last.rx.tstamp.hi = buf->tstamp_put[1]; #else if (!pktq_queued(q)) return (NULL); pkt = (link_Packet*) pktq_out_buf (q); _eth_last.rx.size = ETH_MAX; /* !! wrong, but doesn't matter for pcap */ _eth_last.rx.tstamp.lo = 0UL; /* pcdbug.c writes rx-time == dbg-time */ _eth_last.rx.tstamp.hi = 0UL; #endif if (_pktserial) { ip = &pkt->ip.head; /* SLIP/PPP/AX25 */ *type = (ip->ver == 4) ? IP4_TYPE : IP6_TYPE; return (pkt); } if (_pktdevclass == PDCLASS_TOKEN || _pktdevclass == PDCLASS_TOKEN_RIF) { tok_Header *tr = &pkt->tok.head; fix_tok_head (&tr); *type = tr->type; return (union link_Packet*) tr; } if (_pktdevclass == PDCLASS_ARCNET) { arcnet_Packet *arc = &pkt->arc; if (!fix_arc_head(&arc->head, type)) { DEBUG_RX (NULL, &arc->data); pkt_free_pkt (pkt); pkt = NULL; } return (pkt); } if (_pktdevclass == PDCLASS_FDDI) { fddi_Packet *fddi = &pkt->fddi; *type = fddi->head.type; return (pkt); } /* must be PDCLASS_ETHER */ *type = pkt->eth.head.type; ARGSUSED (q); return (pkt); }
/** * Handler for incoming ICMP packets. */ void icmp_handler (const in_Header *ip, BOOL broadcast) { union ICMP_PKT *icmp; const in_Header *orig_ip; int type, code; unsigned len; DWORD delta_time; BOOL for_me, i_orig; /* is it for me, did I originate it */ const char *msg; DEBUG_RX (NULL, ip); if (block_icmp) /* application is handling ICMP; not needed */ return; len = in_GetHdrLen (ip); icmp = (union ICMP_PKT*) ((BYTE*)ip + len); len = intel16 (ip->length) - len; for_me = _ip4_is_multihome_addr (intel(ip->destination)); if (!for_me || broadcast) /* drop broadcast pings.. */ return; if (len < sizeof(icmp->info)) { STAT (icmpstats.icps_tooshort++); return; } if (CHECKSUM(icmp,len) != 0xFFFF) { STAT (icmpstats.icps_checksum++); icmp_print (1, _LANG("bad checksum"), ip->source); return; } type = icmp->unused.type; code = icmp->unused.code; orig_ip = &icmp->ip.ip; i_orig = _ip4_is_local_addr (intel(orig_ip->source)); if (type == ICMP_MASKREPLY) { if (!_do_mask_req) return; i_orig = TRUE; } /* !! this needs work */ if (!i_orig && (type != ICMP_ECHOREPLY && type != ICMP_ECHO && type != ICMP_IREQREPLY && type != ICMP_TSTAMP)) { icmp_bogus (ip, type, NULL); return; } switch (type) { case ICMP_ECHOREPLY: /* check if we were waiting for it */ delta_time = set_timeout(0) - icmp->echo.identifier; add_ping (intel(ip->source), delta_time, icmp->echo.index); return; case ICMP_UNREACH: if (code < DIM(icmp_unreach_str)) { UINT len_needed = 8 + in_GetHdrLen (orig_ip); WORD next_mtu = 0; msg = _LANG (icmp_unreach_str[code]); icmp_print (1, msg, ip->source); if (orig_ip->proto == TCP_PROTO || orig_ip->proto == UDP_PROTO) len_needed += 4; /* Need the src/dest port numbers */ if (len >= len_needed) { if (code == ICMP_UNREACH_NEEDFRAG) next_mtu = intel16 (icmp->needfrag.next_mtu); #if !defined(USE_UDP_ONLY) if (orig_ip->proto == TCP_PROTO) _tcp_cancel (orig_ip, ICMP_UNREACH, code, msg, &next_mtu); else #endif if (orig_ip->proto == UDP_PROTO) _udp_cancel (orig_ip, ICMP_UNREACH, code, msg, &next_mtu); /** \todo Handle cancelling raw sockets */ #if defined(USE_BSD_API) && 0 else _raw_cancel (orig_ip, ICMP_UNREACH, code, msg); #endif } else STAT (icmpstats.icps_tooshort++); } else STAT (icmpstats.icps_badcode++); return; case ICMP_SOURCEQUENCH: #if !defined(USE_UDP_ONLY) if (orig_ip->proto == TCP_PROTO) { msg = _LANG (icmp_type_str[type]); icmp_print (1, msg, ip->source); _tcp_cancel (orig_ip, ICMP_SOURCEQUENCH, code, msg, NULL); } #endif return; case ICMP_REDIRECT: if (code < DIM(icmp_redirect_str)) icmp_redirect (icmp, ip, orig_ip, code); else STAT (icmpstats.icps_badcode++); return; case ICMP_ECHO: icmp_print (2, _LANG("PING requested of us"), ip->source); icmp_echo_reply (ip, icmp, len); return; case ICMP_TIMXCEED: if (code >= DIM(icmp_exceed_str)) { STAT (icmpstats.icps_badcode++); return; } if (code == 0) /* "TTL exceeded in transit" */ switch (orig_ip->proto) { #if !defined(USE_UDP_ONLY) case TCP_PROTO: msg = _LANG (icmp_exceed_str[0]); icmp_print (1, msg, ip->source); _tcp_cancel (orig_ip, ICMP_TIMXCEED, code, msg, NULL); break; #endif case UDP_PROTO: msg = _LANG (icmp_exceed_str[0]); icmp_print (1, msg, ip->source); _udp_cancel (orig_ip, ICMP_TIMXCEED, code, msg, NULL); break; } return; case ICMP_PARAMPROB: msg = _LANG (icmp_type_str[ICMP_PARAMPROB]); switch (orig_ip->proto) { #if !defined(USE_UDP_ONLY) case TCP_PROTO: icmp_print (0, msg, ip->source); _tcp_cancel (orig_ip, ICMP_PARAMPROB, code, msg, NULL); break; #endif case UDP_PROTO: icmp_print (0, msg, ip->source); _udp_cancel (orig_ip, ICMP_PARAMPROB, code, msg, NULL); break; } return; case ICMP_ROUTERADVERT: /* todo !! */ msg = _LANG (icmp_type_str[ICMP_ROUTERADVERT]); icmp_print (1, msg, ip->source); return; case ICMP_ROUTERSOLICIT: /* todo !! */ msg = _LANG (icmp_type_str[ICMP_ROUTERSOLICIT]); icmp_print (1, msg, ip->source); return; case ICMP_TSTAMP: msg = _LANG (icmp_type_str[ICMP_TSTAMP]); icmp_print (1, msg, ip->source); /**< \todo send reply? */ return; case ICMP_TSTAMPREPLY: msg = _LANG (icmp_type_str[ICMP_TSTAMPREPLY]); icmp_print (1, msg, ip->source); /**< \todo should store */ return; case ICMP_IREQ: msg = _LANG (icmp_type_str[ICMP_IREQ]); icmp_print (1, msg, ip->source); /**< \todo send reply */ return; case ICMP_IREQREPLY: msg = _LANG (icmp_type_str[ICMP_IREQREPLY]); icmp_print (1, msg, ip->source); /**< \todo send reply upwards */ return; case ICMP_MASKREQ: /* might be sent by us, never answer */ break; case ICMP_MASKREPLY: msg = _LANG (icmp_type_str[ICMP_MASKREPLY]); icmp_print (0, msg, ip->source); if ((icmp->mask.identifier == addr_mask_id) && (icmp->mask.sequence == addr_mask_seq-1) && sin_mask != intel(icmp->mask.mask)) outsnl ("Conflicting net-mask from \"ICMP Addr Mask Reply\"\7"); addr_mask_id = 0; return; } }