📄 ip_read.c
字号:
} pack->acc_linkC++; ip_packet2user(ip_fd, pack, exp_time, size); } if (share_fd) { pack->acc_linkC++; ip_packet2user(share_fd, pack, exp_time, size); } } if (first_fd) { if (first_fd->if_put_pkt && (first_fd->if_flags & IFF_READ_IP) && !(first_fd->if_ipopt.nwio_flags & NWIO_RWDATONLY)) { (*first_fd->if_put_pkt)(first_fd->if_srfd, pack, size); } else ip_packet2user(first_fd, pack, exp_time, size); } else { if (ip_pack_stat == NWIO_EN_LOC) { DBLOCK(0x01, printf("ip_port_arrive: dropping packet for proto %d\n", proto)); } else { DBLOCK(0x20, printf("dropping packet for proto %d\n", proto)); } bf_afree(pack); }}PUBLIC void ip_arrived(ip_port, pack)ip_port_t *ip_port;acc_t *pack;{ ip_hdr_t *ip_hdr; ipaddr_t dest; int ip_frag_len, ip_hdr_len, highbyte; size_t pack_size; acc_t *tmp_pack, *hdr_pack; ev_arg_t ev_arg; pack_size= bf_bufsize(pack); if (pack_size < IP_MIN_HDR_SIZE) { DBLOCK(1, printf("wrong acc_length\n")); bf_afree(pack); return; } pack= bf_align(pack, IP_MIN_HDR_SIZE, 4); pack= bf_packIffLess(pack, IP_MIN_HDR_SIZE);assert (pack->acc_length >= IP_MIN_HDR_SIZE); ip_hdr= (ip_hdr_t *)ptr2acc_data(pack); ip_hdr_len= (ip_hdr->ih_vers_ihl & IH_IHL_MASK) << 2; if (ip_hdr_len>IP_MIN_HDR_SIZE) { pack= bf_packIffLess(pack, ip_hdr_len); ip_hdr= (ip_hdr_t *)ptr2acc_data(pack); } ip_frag_len= ntohs(ip_hdr->ih_length); if (ip_frag_len != pack_size) { if (pack_size < ip_frag_len) { /* Sent ICMP? */ DBLOCK(1, printf("wrong acc_length\n")); bf_afree(pack); return; } assert(ip_frag_len<pack_size); tmp_pack= pack; pack= bf_cut(tmp_pack, 0, ip_frag_len); bf_afree(tmp_pack); pack_size= ip_frag_len; } if (!ip_frag_chk(pack)) { DBLOCK(1, printf("fragment not allright\n")); bf_afree(pack); return; } /* Decide about local delivery or routing. Local delivery can happen * when the destination is the local ip address, or one of the * broadcast addresses and the packet happens to be delivered * point-to-point. */ dest= ip_hdr->ih_dst; if (dest == ip_port->ip_ipaddr) { ip_port_arrive (ip_port, pack, ip_hdr); return; } if (broadcast_dst(ip_port, dest)) { ip_port_arrive (ip_port, pack, ip_hdr); return; } if (pack->acc_linkC != 1 || pack->acc_buffer->buf_linkC != 1) { /* Get a private copy of the IP header */ hdr_pack= bf_memreq(ip_hdr_len); memcpy(ptr2acc_data(hdr_pack), ip_hdr, ip_hdr_len); pack= bf_delhead(pack, ip_hdr_len); hdr_pack->acc_next= pack; pack= hdr_pack; hdr_pack= NULL; ip_hdr= (ip_hdr_t *)ptr2acc_data(pack); } assert(pack->acc_linkC == 1); assert(pack->acc_buffer->buf_linkC == 1); /* Try to decrement the ttl field with one. */ if (ip_hdr->ih_ttl < 2) { icmp_snd_time_exceeded(ip_port->ip_port, pack, ICMP_TTL_EXC); return; } ip_hdr->ih_ttl--; ip_hdr_chksum(ip_hdr, ip_hdr_len); /* Avoid routing to bad destinations. */ highbyte= ntohl(dest) >> 24; if (highbyte == 0 || highbyte == 127 || (highbyte == 169 && (((ntohl(dest) >> 16) & 0xff) == 254)) || highbyte >= 0xe0) { /* Bogus destination address */ bf_afree(pack); return; } /* Further processing from an event handler */ if (pack->acc_linkC != 1) { tmp_pack= bf_dupacc(pack); bf_afree(pack); pack= tmp_pack; tmp_pack= NULL; } pack->acc_ext_link= NULL; if (ip_port->ip_routeq_head) { ip_port->ip_routeq_tail->acc_ext_link= pack; ip_port->ip_routeq_tail= pack; return; } ip_port->ip_routeq_head= pack; ip_port->ip_routeq_tail= pack; ev_arg.ev_ptr= ip_port; ev_enqueue(&ip_port->ip_routeq_event, route_packets, ev_arg);}PUBLIC void ip_arrived_broadcast(ip_port, pack)ip_port_t *ip_port;acc_t *pack;{ ip_hdr_t *ip_hdr; int ip_frag_len, ip_hdr_len; size_t pack_size; acc_t *tmp_pack; pack_size= bf_bufsize(pack); if (pack_size < IP_MIN_HDR_SIZE) { DBLOCK(1, printf("wrong acc_length\n")); bf_afree(pack); return; } pack= bf_align(pack, IP_MIN_HDR_SIZE, 4); pack= bf_packIffLess(pack, IP_MIN_HDR_SIZE);assert (pack->acc_length >= IP_MIN_HDR_SIZE); ip_hdr= (ip_hdr_t *)ptr2acc_data(pack); DIFBLOCK(0x20, (ip_hdr->ih_dst & HTONL(0xf0000000)) == HTONL(0xe0000000), printf("got multicast packet\n")); ip_hdr_len= (ip_hdr->ih_vers_ihl & IH_IHL_MASK) << 2; if (ip_hdr_len>IP_MIN_HDR_SIZE) { pack= bf_align(pack, IP_MIN_HDR_SIZE, 4); pack= bf_packIffLess(pack, ip_hdr_len); ip_hdr= (ip_hdr_t *)ptr2acc_data(pack); } ip_frag_len= ntohs(ip_hdr->ih_length); if (ip_frag_len<pack_size) { tmp_pack= pack; pack= bf_cut(tmp_pack, 0, ip_frag_len); bf_afree(tmp_pack); } if (!ip_frag_chk(pack)) { DBLOCK(1, printf("fragment not allright\n")); bf_afree(pack); return; } if (!broadcast_dst(ip_port, ip_hdr->ih_dst)) {#if 0 printf( "ip[%d]: broadcast packet for ip-nonbroadcast addr, src=", ip_port->ip_port); writeIpAddr(ip_hdr->ih_src); printf(" dst="); writeIpAddr(ip_hdr->ih_dst); printf("\n");#endif bf_afree(pack); return; } ip_port_arrive (ip_port, pack, ip_hdr);}PRIVATE void route_packets(ev, ev_arg)event_t *ev;ev_arg_t ev_arg;{ ip_port_t *ip_port; ipaddr_t dest; acc_t *pack; iroute_t *iroute; ip_port_t *next_port; int r, type; ip_hdr_t *ip_hdr; size_t req_mtu; ip_port= ev_arg.ev_ptr; assert(&ip_port->ip_routeq_event == ev); while (pack= ip_port->ip_routeq_head, pack != NULL) { ip_port->ip_routeq_head= pack->acc_ext_link; ip_hdr= (ip_hdr_t *)ptr2acc_data(pack); dest= ip_hdr->ih_dst; iroute= iroute_frag(ip_port->ip_port, dest); if (iroute == NULL || iroute->irt_dist == IRTD_UNREACHABLE) { /* Also unreachable */ /* Finding out if we send a network unreachable is too * much trouble. */ if (iroute == NULL) { printf("ip[%d]: no route to ", ip_port-ip_port_table); writeIpAddr(dest); printf("\n"); } icmp_snd_unreachable(ip_port->ip_port, pack, ICMP_HOST_UNRCH); continue; } next_port= &ip_port_table[iroute->irt_port]; if (ip_hdr->ih_flags_fragoff & HTONS(IH_DONT_FRAG)) { req_mtu= bf_bufsize(pack); if (req_mtu > next_port->ip_mtu || (iroute->irt_mtu && req_mtu>iroute->irt_mtu)) { icmp_snd_mtu(ip_port->ip_port, pack, next_port->ip_mtu); continue; } } if (next_port != ip_port) { if (iroute->irt_gateway != 0) { /* Just send the packet to the next gateway */ pack->acc_linkC++; /* Extra ref for ICMP */ r= next_port->ip_dev_send(next_port, iroute->irt_gateway, pack, IP_LT_NORMAL); if (r == EDSTNOTRCH) { printf("ip[%d]: gw ", ip_port-ip_port_table); writeIpAddr(iroute->irt_gateway); printf(" on ip[%d] is down for dest ", next_port-ip_port_table); writeIpAddr(dest); printf("\n"); icmp_snd_unreachable(next_port- ip_port_table, pack, ICMP_HOST_UNRCH); pack= NULL; } else { assert(r == 0); bf_afree(pack); pack= NULL; } continue; } /* The packet is for the attached network. Special * addresses are the ip address of the interface and * net.0 if no IP_42BSD_BCAST. */ if (dest == next_port->ip_ipaddr) { ip_port_arrive (next_port, pack, ip_hdr); continue; } if (dest == iroute->irt_dest) { /* Never forward obsolete directed broadcasts */#if IP_42BSD_BCAST && 0 type= IP_LT_BROADCAST;#else /* Bogus destination address */ DBLOCK(1, printf( "ip[%d]: dropping old-fashioned directed broadcast ", ip_port-ip_port_table); writeIpAddr(dest); printf("\n");); icmp_snd_unreachable(next_port-ip_port_table, pack, ICMP_HOST_UNRCH); continue;#endif } else if (dest == (iroute->irt_dest | ~iroute->irt_subnetmask)) { if (!ip_forward_directed_bcast) { /* Do not forward directed broadcasts */ DBLOCK(1, printf( "ip[%d]: dropping directed broadcast ", ip_port-ip_port_table); writeIpAddr(dest); printf("\n");); icmp_snd_unreachable(next_port- ip_port_table, pack, ICMP_HOST_UNRCH); continue; } else type= IP_LT_BROADCAST; } else type= IP_LT_NORMAL; /* Just send the packet to it's destination */ pack->acc_linkC++; /* Extra ref for ICMP */ r= next_port->ip_dev_send(next_port, dest, pack, type); if (r == EDSTNOTRCH) { DBLOCK(1, printf("ip[%d]: next hop ", ip_port-ip_port_table); writeIpAddr(dest); printf(" on ip[%d] is down\n", next_port-ip_port_table);); icmp_snd_unreachable(next_port-ip_port_table, pack, ICMP_HOST_UNRCH); pack= NULL; } else { assert(r == 0 || (printf("r = %d\n", r), 0)); bf_afree(pack); pack= NULL; } continue; } /* Now we know that the packet should be routed over the same * network as it came from. If there is a next hop gateway, * we can send the packet to that gateway and send a redirect * ICMP to the sender if the sender is on the attached * network. If there is no gateway complain. */ if (iroute->irt_gateway == 0) { printf("ip_arrived: packet should not be here, src="); writeIpAddr(ip_hdr->ih_src); printf(" dst="); writeIpAddr(ip_hdr->ih_dst); printf("\n"); bf_afree(pack); continue; } if (((ip_hdr->ih_src ^ ip_port->ip_ipaddr) & ip_port->ip_subnetmask) == 0) { /* Finding out if we can send a network redirect * instead of a host redirect is too much trouble. */ pack->acc_linkC++; icmp_snd_redirect(ip_port->ip_port, pack, ICMP_REDIRECT_HOST, iroute->irt_gateway); } else { printf("ip_arrived: packet is wrongly routed, src="); writeIpAddr(ip_hdr->ih_src); printf(" dst="); writeIpAddr(ip_hdr->ih_dst); printf("\n"); printf("in port %d, output %d, dest net ", ip_port->ip_port, iroute->irt_port); writeIpAddr(iroute->irt_dest); printf("/"); writeIpAddr(iroute->irt_subnetmask); printf(" next hop "); writeIpAddr(iroute->irt_gateway); printf("\n"); bf_afree(pack); continue; } /* No code for unreachable ICMPs here. The sender should * process the ICMP redirect and figure it out. */ ip_port->ip_dev_send(ip_port, iroute->irt_gateway, pack, IP_LT_NORMAL); }}PRIVATE int broadcast_dst(ip_port, dest)ip_port_t *ip_port;ipaddr_t dest;{ ipaddr_t my_ipaddr, netmask, classmask; /* Treat class D (multicast) address as broadcasts. */ if ((dest & HTONL(0xF0000000)) == HTONL(0xE0000000)) { return 1; } /* Accept without complaint if netmask not yet configured. */ if (!(ip_port->ip_flags & IPF_NETMASKSET)) { return 1; } /* Two possibilities, 0 (iff IP_42BSD_BCAST) and -1 */ if (dest == HTONL((ipaddr_t)-1)) return 1;#if IP_42BSD_BCAST if (dest == HTONL((ipaddr_t)0)) return 1;#endif netmask= ip_port->ip_subnetmask; my_ipaddr= ip_port->ip_ipaddr; if (((my_ipaddr ^ dest) & netmask) != 0) { classmask= ip_port->ip_classfulmask; /* Not a subnet broadcast, maybe a classful broadcast */ if (((my_ipaddr ^ dest) & classmask) != 0) { return 0; } /* Two possibilities, net.0 (iff IP_42BSD_BCAST) and net.-1 */ if ((dest & ~classmask) == ~classmask) { return 1; }#if IP_42BSD_BCAST if ((dest & ~classmask) == 0) return 1;#endif return 0; } if (!(ip_port->ip_flags & IPF_SUBNET_BCAST)) return 0; /* No subnet broadcasts on this network */ /* Two possibilities, subnet.0 (iff IP_42BSD_BCAST) and subnet.-1 */ if ((dest & ~netmask) == ~netmask) return 1;#if IP_42BSD_BCAST if ((dest & ~netmask) == 0) return 1;#endif return 0;}void ip_process_loopb(ev, arg)event_t *ev;ev_arg_t arg;{ ip_port_t *ip_port; acc_t *pack; ip_port= arg.ev_ptr; assert(ev == &ip_port->ip_loopb_event); while(pack= ip_port->ip_loopb_head, pack != NULL) { ip_port->ip_loopb_head= pack->acc_ext_link; ip_arrived(ip_port, pack); }}/* * $PchId: ip_read.c,v 1.33 2005/06/28 14:18:50 philip Exp $ */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -