int ip_send_packet(struct sr_packet * packet) { struct ip * ip_hdr = IP_HDR(packet); uint32_t next_hop; char thru_interface[SR_NAMELEN]; if(forwarding_table_lookup_next_hop(ROUTER(packet->sr)->fwd_table, ip_hdr->ip_dst.s_addr, &next_hop, thru_interface, 0)) { if(next_hop == 0) { next_hop = ip_hdr->ip_dst.s_addr; } ip_send(packet,next_hop,thru_interface); return 1; } return 0; }
// ------------------------------------------------ // Function: icmp_parse() // ------------------------------------------------ // Input: Message buffer // Output: - // ------------------------------------------------ // Description: Parse a ICMP message // ------------------------------------------------ void icmp_parse(PPBUF pbuf) { // --------------------- // checksum verification // --------------------- icmp_checksum(pbuf->data, pbuf->size); if(chk_H != 0xff) return; if(chk_L != 0xff) return; // ------------------------------- // checks recognized message types // ------------------------------- switch(ICMP(pbuf->data)->type) { case PING_REQUEST: // --------- // answer it // --------- retain_buffer(pbuf); ip_answer(pbuf); ICMP(pbuf->data)->type = PING_REPLY; // --------------- // update checksum // --------------- ICMP(pbuf->data)->checksum = 0; icmp_checksum(pbuf->data, pbuf->size); ICMP(pbuf->data)->checksum = HTONS(~WORDOF(chk_H, chk_L)); // ---------------------------- // sends answer to IP interface // ---------------------------- ip_send(pbuf); release_buffer(pbuf); break; case PING_REPLY: // -------------------------------------- // answer received, signal waiting thread // -------------------------------------- os_signal(SIG_ICMP); break; } }
int udp_send(struct netdev *nd, struct sin *from, struct sin *to, struct buflist *data) { struct buflist bl, *blp; struct udphdr udp; int size = 0; bl.data = &udp; bl.size = sizeof(udp); bl.next = data; for (blp = &bl; blp; blp = blp->next) size += blp->size; udp.udp_source = from->sin_port; udp.udp_dest = to->sin_port; udp.udp_length = htons(size); udp.udp_check = 0; udp.udp_check = udp_check(&udp, from, to, &bl, size); return ip_send(nd, 0x11, from->sin_addr, to->sin_addr, &bl); }
static void raw_send(const struct send_pkt *s, unsigned int len) { static char ip_buf[2048]; static ip_t *ip_p = NULL; int n; unsigned int i; if (!ip_p) { ip_p = ip_open(); if (!ip_p) err(1, "ip_open"); } for (i = 0 ; i < len; ++i) { memset(ip_buf, 0, sizeof(ip_buf)); n = build_buf(&s[i], ip_buf, sizeof(ip_buf)); ip_checksum(ip_buf, n); ip_send(ip_p, ip_buf, n); } return; }
static void ip_loopback(struct device *old_dev, struct sk_buff *skb) { struct device *dev=&loopback_dev; int len=ntohs(skb->ip_hdr->tot_len); struct sk_buff *newskb=dev_alloc_skb(len+dev->hard_header_len+15); if(newskb==NULL) return; newskb->link3=NULL; newskb->sk=NULL; newskb->dev=dev; newskb->saddr=skb->saddr; newskb->daddr=skb->daddr; newskb->raddr=skb->raddr; newskb->free=1; newskb->lock=0; newskb->users=0; newskb->pkt_type=skb->pkt_type; /* * Put a MAC header on the packet */ ip_send(NULL,newskb, skb->ip_hdr->daddr, len, dev, skb->ip_hdr->saddr); /* * Add the rest of the data space. */ newskb->ip_hdr=(struct iphdr *)skb_put(newskb, len); memcpy(newskb->proto_priv, skb->proto_priv, sizeof(skb->proto_priv)); /* * Copy the data */ memcpy(newskb->ip_hdr,skb->ip_hdr,len); /* Recurse. The device check against IFF_LOOPBACK will stop infinite recursion */ /*printk("Loopback output queued [%lX to %lX].\n", newskb->ip_hdr->saddr,newskb->ip_hdr->daddr);*/ ip_queue_xmit(NULL, dev, newskb, 2); }
static int ipq_daq_inject ( void* handle, const DAQ_PktHdr_t* hdr, const uint8_t* buf, uint32_t len, int reverse) { IpqImpl* impl = (IpqImpl*)handle; ssize_t sent = 0; if ( impl->link ) sent = eth_send(impl->link, buf, len); else if ( impl->net ) sent = ip_send(impl->net, buf, len); if ( (uint32_t)sent != len ) { DPE(impl->error, "%s: failed to send", __FUNCTION__); return DAQ_ERROR; } impl->stats.packets_injected++; return DAQ_SUCCESS; }
/* * Send a RST to destip, from port srcport to port dstport, acking seqnum. */ static int tcp_send_rst(unsigned long destip, unsigned short dstport, unsigned short srcport, unsigned long seqnum) { unsigned char pkt[20]; struct tcphdr *hdr = (struct tcphdr *)pkt; hdr->srcport = srcport; hdr->dstport = dstport; hdr->seqnum = 0; /* not used in this, right? */ hdr->acknum = htonl(ntohl(seqnum)+1); hdr->hdrlen = 5; /* 20 / 4 = 5 */ hdr->reserved1 = hdr->reserved2 = 0; hdr->cntrlbits = TCPBIT_RST | TCPBIT_ACK; hdr->window = 0; hdr->csum = 0; hdr->urgptr = 0; hdr->csum = tcp_checksum(pkt, hdr->hdrlen*4, htonl(INTERMOBI_OURIP), destip); ip_send(destip, IPPROTO_TCP, pkt, 20); return 0; }
/* if packet->interface = NULL then the packet has been generated by the router */ void ip_forward(struct sr_packet * packet) { struct ip * ip_hdr = IP_HDR(packet); uint32_t next_hop; char thru_interface[SR_NAMELEN]; /* if the destination is to one of our ports, then just forward it there */ if(interface_list_get_interface_by_ip(INTERFACE_LIST(packet->sr), ip_hdr->ip_dst.s_addr)) { ip_handle_incoming_packet(packet); } else { if(forwarding_table_lookup_next_hop(ROUTER(packet->sr)->fwd_table, ip_hdr->ip_dst.s_addr, &next_hop, thru_interface, interface_list_inbound(packet->sr, packet->interface)) && interface_list_forward_packet(packet->sr, packet->interface, thru_interface)) { if(next_hop == 0) { next_hop = ip_hdr->ip_dst.s_addr; } ip_hdr->ip_ttl --; ip_hdr->ip_sum = checksum_ipheader(ip_hdr); ip_send(packet,next_hop,thru_interface); } else { if(forwarding_table_lookup_next_hop(ROUTER(packet->sr)->fwd_table, ip_hdr->ip_src.s_addr, 0,0, interface_list_inbound(packet->sr, packet->interface))) { icmp_send_host_unreachable(packet); } } } }
/*------------------------------------------------------------------------ * udp_sendto - Send a UDP packet to a specified destination *------------------------------------------------------------------------ */ status udp_sendto ( uid32 slot, /* UDP table slot to use */ uint32 remip, /* Remote IP address to use */ uint16 remport, /* Remote protocol port to use */ char *buff, /* Buffer of UDP data */ int32 len /* Length of data in buffer */ ) { intmask mask; /* Saved interrupt mask */ struct netpacket *pkt; /* Pointer to a packet buffer */ int32 pktlen; /* Total packet length */ static uint16 ident = 1; /* Datagram IDENT field */ struct udpentry *udptr; /* Pointer to a UDP table entry */ char *udataptr; /* Pointer to UDP data */ /* Ensure only one process can access the UDP table at a time */ mask = disable(); /* Verify that the slot is valid */ if ( (slot < 0) || (slot >= UDP_SLOTS) ) { restore(mask); return SYSERR; } /* Get pointer to table entry */ udptr = &udptab[slot]; /* Verify that the slot has been registered and is valid */ if (udptr->udstate == UDP_FREE) { restore(mask); return SYSERR; } /* Allocate a network buffer to hold the packet */ pkt = (struct netpacket *)getbuf(netbufpool); if ((int32)pkt == SYSERR) { restore(mask); return SYSERR; } /* Compute packet length as UDP data size + fixed header size */ pktlen = ((char *)&pkt->net_udpdata - (char *)pkt) + len; /* Create UDP packet in pkt */ memcpy((char *)pkt->net_ethsrc,NetData.ethucast,ETH_ADDR_LEN); pkt->net_ethtype = 0x0800; /* Type is IP */ pkt->net_ipvh = 0x45; /* IP version and hdr length */ pkt->net_iptos = 0x00; /* Type of service */ pkt->net_iplen= pktlen - ETH_HDR_LEN;/* total IP datagram length*/ pkt->net_ipid = ident++; /* Datagram gets next IDENT */ pkt->net_ipfrag = 0x0000; /* IP flags & fragment offset */ pkt->net_ipttl = 0xff; /* IP time-to-live */ pkt->net_ipproto = IP_UDP; /* Datagram carries UDP */ pkt->net_ipcksum = 0x0000; /* Initial checksum */ pkt->net_ipsrc = NetData.ipucast;/* IP source address */ pkt->net_ipdst = remip; /* IP destination address */ pkt->net_udpsport = udptr->udlocport;/* local UDP protocol port */ pkt->net_udpdport = remport; /* Remote UDP protocol port */ pkt->net_udplen = (uint16)(UDP_HDR_LEN+len); /* UDP length */ pkt->net_udpcksum = 0x0000; /* Ignore UDP checksum */ udataptr = (char *) pkt->net_udpdata; for (; len>0; len--) { *udataptr++ = *buff++; } /* Call ipsend to send the datagram */ ip_send(pkt); restore(mask); return OK; }
/* * Handle ICMP messages in the outside-to-inside direction (incoming) * and sometimes in outgoing direction from ip_vs_forward_icmp. * Find any that might be relevant, check against existing connections, * forward to the right destination host if relevant. * Currently handles error types - unreachable, quench, ttl exceeded. */ static int ip_vs_in_icmp(struct sk_buff **skb_p) { struct sk_buff *skb = *skb_p; struct iphdr *iph; struct icmphdr *icmph; struct iphdr *ciph; /* The ip header contained within the ICMP */ __u16 *pptr; /* port numbers from TCP/UDP contained header */ unsigned short len; unsigned short clen, csize; struct ip_vs_conn *cp; struct rtable *rt; /* Route to the other host */ int mtu; if (skb_is_nonlinear(skb)) { if (skb_linearize(skb, GFP_ATOMIC) != 0) return NF_DROP; } iph = skb->nh.iph; ip_send_check(iph); icmph = (struct icmphdr *)((char *)iph + (iph->ihl << 2)); len = ntohs(iph->tot_len) - (iph->ihl<<2); if (len < sizeof(struct icmphdr)) return NF_DROP; IP_VS_DBG(12, "icmp in (%d,%d) %u.%u.%u.%u -> %u.%u.%u.%u\n", icmph->type, ntohs(icmp_id(icmph)), NIPQUAD(iph->saddr), NIPQUAD(iph->daddr)); if ((icmph->type != ICMP_DEST_UNREACH) && (icmph->type != ICMP_SOURCE_QUENCH) && (icmph->type != ICMP_TIME_EXCEEDED)) return NF_ACCEPT; /* * If we get here we have an ICMP error of one of the above 3 types * Now find the contained IP header */ clen = len - sizeof(struct icmphdr); if (clen < sizeof(struct iphdr)) return NF_DROP; ciph = (struct iphdr *) (icmph + 1); csize = ciph->ihl << 2; if (clen < csize) return NF_DROP; /* We are only interested ICMPs generated from TCP or UDP packets */ if (ciph->protocol != IPPROTO_UDP && ciph->protocol != IPPROTO_TCP) return NF_ACCEPT; /* Skip non-first embedded TCP/UDP fragments */ if (ciph->frag_off & __constant_htons(IP_OFFSET)) return NF_ACCEPT; /* We need at least TCP/UDP ports here */ if (clen < csize + sizeof(struct udphdr)) return NF_DROP; /* Ensure the checksum is correct */ if (ip_compute_csum((unsigned char *) icmph, len)) { /* Failed checksum! */ IP_VS_ERR_RL("incoming ICMP: failed checksum from " "%d.%d.%d.%d!\n", NIPQUAD(iph->saddr)); return NF_DROP; } pptr = (__u16 *)&(((char *)ciph)[csize]); IP_VS_DBG(11, "Handling incoming ICMP for " "%u.%u.%u.%u:%d -> %u.%u.%u.%u:%d\n", NIPQUAD(ciph->saddr), ntohs(pptr[0]), NIPQUAD(ciph->daddr), ntohs(pptr[1])); /* This is pretty much what ip_vs_conn_in_get() does, except parameters are in the reverse order */ cp = ip_vs_conn_in_get(ciph->protocol, ciph->daddr, pptr[1], ciph->saddr, pptr[0]); if (cp == NULL) return NF_ACCEPT; ip_vs_in_stats(cp, skb); /* The ICMP packet for VS/TUN, VS/DR and LOCALNODE will be forwarded directly here, because there is no need to translate address/port back */ if (IP_VS_FWD_METHOD(cp) != IP_VS_CONN_F_MASQ) { int ret; if (cp->packet_xmit) ret = cp->packet_xmit(skb, cp); else ret = NF_ACCEPT; atomic_inc(&cp->in_pkts); ip_vs_conn_put(cp); return ret; } /* * mangle and send the packet here */ if (!(rt = __ip_vs_get_out_rt(cp, RT_TOS(iph->tos)))) goto tx_error_icmp; /* MTU checking */ mtu = rt->u.dst.pmtu; if ((skb->len > mtu) && (iph->frag_off&__constant_htons(IP_DF))) { ip_rt_put(rt); icmp_send(skb, ICMP_DEST_UNREACH,ICMP_FRAG_NEEDED, htonl(mtu)); IP_VS_DBG_RL("ip_vs_in_icmp(): frag needed\n"); goto tx_error; } /* drop old route */ dst_release(skb->dst); skb->dst = &rt->u.dst; /* copy-on-write the packet before mangling it */ if (ip_vs_skb_cow(skb, rt->u.dst.dev->hard_header_len, &iph, (unsigned char**)&icmph)) { ip_vs_conn_put(cp); return NF_DROP; } ciph = (struct iphdr *) (icmph + 1); pptr = (__u16 *)&(((char *)ciph)[csize]); /* The ICMP packet for VS/NAT must be written to correct addresses before being forwarded to the right server */ /* First change the dest IP address, and recalc checksum */ iph->daddr = cp->daddr; ip_send_check(iph); /* Now change the *source* address in the contained IP */ ciph->saddr = cp->daddr; ip_send_check(ciph); /* the TCP/UDP source port - cannot redo check */ pptr[0] = cp->dport; /* And finally the ICMP checksum */ icmph->checksum = 0; icmph->checksum = ip_compute_csum((unsigned char *) icmph, len); skb->ip_summed = CHECKSUM_UNNECESSARY; IP_VS_DBG(11, "Forwarding incoming ICMP to " "%u.%u.%u.%u:%d -> %u.%u.%u.%u:%d\n", NIPQUAD(ciph->saddr), ntohs(pptr[0]), NIPQUAD(ciph->daddr), ntohs(pptr[1])); #ifdef CONFIG_NETFILTER_DEBUG skb->nf_debug = 1 << NF_IP_LOCAL_OUT; #endif /* CONFIG_NETFILTER_DEBUG */ ip_send(skb); ip_vs_conn_put(cp); return NF_STOLEN; tx_error_icmp: dst_link_failure(skb); tx_error: dev_kfree_skb(skb); ip_vs_conn_put(cp); return NF_STOLEN; }
//------------------------------------------------------------------------ // This handles incoming ARP messages // See "TCP/IP Illustrated, Volume 1" Sect 4.4 // Todo: Resolve problem of trying to add to a full cache //------------------------------------------------------------------------ void arp_rcve(UCHAR xdata * inbuf) { UCHAR idata i, cached, oldest; UINT idata minimum; ARP_HEADER xdata * arp; arp = (ARP_HEADER xdata *)(inbuf + 14); cached = FALSE; // Print message if (debug) { if (arp->message_type == ARP_REQUEST) serial_send("ARP: Request rcvd\r"); else serial_send("ARP: Response rcvd\r"); } // Validate incoming frame if ((arp->hardware_type != DIX_ETHERNET) || (arp->protocol_type != IP_PACKET)) return; // Search ARP cache for senders IP address // If found, update entry and restart timer for (i=0; i < CACHESIZE; i++) { if (arp_cache[i].ipaddr == arp->source_ipaddr) { memcpy(&arp_cache[i].hwaddr[0], &arp->source_hwaddr[0], 6); arp_cache[i].timer = CACHETIME; cached = TRUE; if (debug) serial_send("ARP: Cache entry updated\r"); break; } } if (arp->dest_ipaddr != my_ipaddr) return; // At this point we know the the frame is addressed to me // If not already in cache then add entry and start timer if (cached == FALSE) { // Find first blank space and add entry // Blank entries are indicated by ip addr = 0 for (i=0; i < CACHESIZE; i++) { if (arp_cache[i].ipaddr == 0) { arp_cache[i].ipaddr = arp->source_ipaddr; memcpy(&arp_cache[i].hwaddr[0], &arp->source_hwaddr[0], 6); arp_cache[i].timer = CACHETIME; if (debug) serial_send("ARP: New cache entry added\r"); break; } } // If no blank entries in arp cache then sort cache // to find oldest entry and replace it if (i == CACHESIZE) { // Oldest entry is the one with lowest timer value minimum = 0xFFFF; for (i=0; i < CACHESIZE; i++) { if (arp_cache[i].timer < minimum) { minimum = arp_cache[i].timer; oldest = i; } } // "oldest" is now index of oldest entry, so replace it arp_cache[oldest].ipaddr = arp->source_ipaddr; memcpy(&arp_cache[oldest].hwaddr[0], &arp->source_hwaddr[0], 6); arp_cache[oldest].timer = CACHETIME; if (debug) serial_send("ARP: Cache full, so replaced oldest\r"); } } // If we are waiting for an arp response and the arp response // that just came in is addressed to me and is from the host // we are waiting for, then send the message-in-waiting if (arp->message_type == ARP_RESPONSE) { if ((waiting_for_arp) && (wait.ipaddr == arp->source_ipaddr)) { waiting_for_arp = FALSE; ip_send(wait.buf, wait.ipaddr, wait.proto_id, wait.len); } } else if (arp->message_type == ARP_REQUEST) { // Send ARP response if (debug) serial_send("ARP: Sending response\r"); arp_send(arp->source_hwaddr, arp->source_ipaddr, ARP_RESPONSE); } }
/* * This is a bit complicated because we attempt to stuff everything * we've already sent that hasn't been acked into this packet, along * with the new data. * * XXX check the endpoint window and MSS to make sure we don't overflow it. * */ static int tcp_send_data(struct tcp_socket *sk, const unsigned char *data, int datalen) { unsigned char *pkt; struct tcphdr *hdr; struct tcpvec *cur; unsigned short flags = 0; unsigned long seqnum; /* First, enqueue the new data and increment the next seqnum */ if (data && datalen) tcp_txenqueue(sk, 0, sk->snd_nxt, bufdup(data, datalen), datalen); for (cur = sk->txqueue, datalen = 0, seqnum = sk->snd_nxt; cur && (datalen < sk->rcv_max); cur = cur->next) { if (cur->txcount >= TCP_MAX_RETRIES) { tcp_changestate(sk, STATE_TIME_WAIT); tcp_send_fin(sk); return -1; } flags |= cur->flags; if (cur->seqnum < seqnum) seqnum = cur->seqnum; /* get the lowest seqnum queued */ datalen += cur->len; } dprintf("tcp_send_data: procesing %d queued bytes\n", datalen); if (!(pkt = RimMalloc(20+datalen))) return -1; hdr = (struct tcphdr *)pkt; hdr->srcport = htons(sk->localport); hdr->dstport = htons(sk->remoteport); if (sk->snd_nxt < sk->snd_una) sk->snd_una = sk->snd_nxt; hdr->seqnum = htonl(seqnum); hdr->acknum = htonl(sk->rcv_nxt); hdr->hdrlen = 5; /* 20 / 4 = 5 */ hdr->reserved1 = hdr->reserved2 = 0; hdr->cntrlbits = TCPBIT_ACK | flags | (!flags ? TCPBIT_PSH : 0); hdr->window = htons(TCP_DEFAULT_WINDOW); hdr->csum = 0; hdr->urgptr = 0; for (cur = sk->txqueue, flags = 20; cur; cur = cur->next) { memcpy(pkt+flags, cur->buf+cur->start, cur->len); flags += cur->len; cur->lasttx = RimGetTicks(); cur->txcount++; } hdr->csum = tcp_checksum(pkt, (hdr->hdrlen*4)+datalen, htonl(INTERMOBI_OURIP), htonl(sk->remoteaddr)); ip_send(htonl(sk->remoteaddr), IPPROTO_TCP, pkt, 20+datalen); RimFree(pkt); return 0; }
/* * This routine builds the appropriate hardware/IP headers for * the routine. It assumes that if *dev != NULL then the * protocol knows what it's doing, otherwise it uses the * routing/ARP tables to select a device struct. */ int ip_build_header(struct sk_buff *skb, __u32 saddr, __u32 daddr, struct device **dev, int type, struct options *opt, int len, int tos, int ttl, struct rtable ** rp) { struct rtable *rt; __u32 raddr; int tmp; struct iphdr *iph; __u32 final_daddr = daddr; if (opt && opt->srr) daddr = opt->faddr; /* * See if we need to look up the device. */ #ifdef CONFIG_IP_MULTICAST if(MULTICAST(daddr) && *dev==NULL && skb->sk && *skb->sk->ip_mc_name) *dev=dev_get(skb->sk->ip_mc_name); #endif if (rp) { rt = ip_check_route(rp, daddr, skb->localroute, *dev); /* * If rp != NULL rt_put following below should not * release route, so that... */ if (rt) atomic_inc(&rt->rt_refcnt); } else rt = ip_rt_route(daddr, skb->localroute, *dev); if (*dev == NULL) { if (rt == NULL) { ip_statistics.IpOutNoRoutes++; return(-ENETUNREACH); } *dev = rt->rt_dev; } if ((LOOPBACK(saddr) && !LOOPBACK(daddr)) || !saddr) saddr = rt ? rt->rt_src : (*dev)->pa_addr; raddr = rt ? rt->rt_gateway : daddr; if (opt && opt->is_strictroute && rt && (rt->rt_flags & RTF_GATEWAY)) { ip_rt_put(rt); ip_statistics.IpOutNoRoutes++; return -ENETUNREACH; } /* * Now build the MAC header. */ if (type==IPPROTO_TCP) tmp = ip_send_room(rt, skb, raddr, len, *dev, saddr); else tmp = ip_send(rt, skb, raddr, len, *dev, saddr); ip_rt_put(rt); /* * Book keeping */ skb->dev = *dev; skb->saddr = saddr; /* * Now build the IP header. */ /* * If we are using IPPROTO_RAW, then we don't need an IP header, since * one is being supplied to us by the user */ if(type == IPPROTO_RAW) return (tmp); /* * Build the IP addresses */ if (opt) iph=(struct iphdr *)skb_put(skb,sizeof(struct iphdr) + opt->optlen); else iph=(struct iphdr *)skb_put(skb,sizeof(struct iphdr)); iph->version = 4; iph->ihl = 5; iph->tos = tos; iph->frag_off = 0; iph->ttl = ttl; iph->daddr = daddr; iph->saddr = saddr; iph->protocol = type; skb->ip_hdr = iph; if (!opt || !opt->optlen) return sizeof(struct iphdr) + tmp; iph->ihl += opt->optlen>>2; ip_options_build(skb, opt, final_daddr, (*dev)->pa_addr, 0); return iph->ihl*4 + tmp; }
static inline int ipsec_mast_xmit2(struct sk_buff *skb) { return ip_send(skb); }
/* * This routine builds the appropriate hardware/IP headers for * the routine. It assumes that if *dev != NULL then the * protocol knows what it's doing, otherwise it uses the * routing/ARP tables to select a device struct. */ int ip_build_header(struct sk_buff *skb, unsigned long saddr, unsigned long daddr, struct device **dev, int type, struct options *opt, int len, int tos, int ttl) { static struct options optmem; struct iphdr *iph; struct rtable *rt; unsigned char *buff; unsigned long raddr; int tmp; unsigned long src; /* * If there is no 'from' address as yet, then make it our loopback */ if (saddr == 0) saddr = ip_my_addr(); buff = skb->data; /* * See if we need to look up the device. */ if (*dev == NULL) { if(skb->localroute) rt = ip_rt_local(daddr, &optmem, &src); else rt = ip_rt_route(daddr, &optmem, &src); if (rt == NULL) { ip_statistics.IpOutNoRoutes++; return(-ENETUNREACH); } *dev = rt->rt_dev; /* * If the frame is from us and going off machine it MUST MUST MUST * have the output device ip address and never the loopback */ if (LOOPBACK(saddr) && !LOOPBACK(daddr)) saddr = src;/*rt->rt_dev->pa_addr;*/ raddr = rt->rt_gateway; opt = &optmem; } else { /* * We still need the address of the first hop. */ if(skb->localroute) rt = ip_rt_local(daddr, &optmem, &src); else rt = ip_rt_route(daddr, &optmem, &src); /* * If the frame is from us and going off machine it MUST MUST MUST * have the output device ip address and never the loopback */ if (LOOPBACK(saddr) && !LOOPBACK(daddr)) saddr = src;/*rt->rt_dev->pa_addr;*/ raddr = (rt == NULL) ? 0 : rt->rt_gateway; } /* * No gateway so aim at the real destination */ if (raddr == 0) raddr = daddr; /* * Now build the MAC header. */ tmp = ip_send(skb, raddr, len, *dev, saddr); buff += tmp; len -= tmp; /* * Book keeping */ skb->dev = *dev; skb->saddr = saddr; if (skb->sk) skb->sk->saddr = saddr; /* * Now build the IP header. */ /* * If we are using IPPROTO_RAW, then we don't need an IP header, since * one is being supplied to us by the user */ if(type == IPPROTO_RAW) return (tmp); iph = (struct iphdr *)buff; iph->version = 4; iph->tos = tos; iph->frag_off = 0; iph->ttl = ttl; iph->daddr = daddr; iph->saddr = saddr; iph->protocol = type; iph->ihl = 5; /* Setup the IP options. */ #ifdef Not_Yet_Avail build_options(iph, opt); #endif return(20 + tmp); /* IP header plus MAC header size */ }
/* Need this wrapper because NF_HOOK takes the function address */ static inline int do_ip_send(struct sk_buff *skb) { return ip_send(skb); }
static int ipip_tunnel_xmit(struct sk_buff *skb, struct device *dev) { struct ip_tunnel *tunnel = (struct ip_tunnel*)dev->priv; struct net_device_stats *stats = &tunnel->stat; struct iphdr *tiph = &tunnel->parms.iph; u8 tos = tunnel->parms.iph.tos; u16 df = tiph->frag_off; struct rtable *rt; /* Route to the other host */ struct device *tdev; /* Device to other host */ struct iphdr *old_iph = skb->nh.iph; struct iphdr *iph; /* Our new IP header */ int max_headroom; /* The extra header space needed */ u32 dst = tiph->daddr; int mtu; if (tunnel->recursion++) { tunnel->stat.collisions++; goto tx_error; } if (skb->protocol != __constant_htons(ETH_P_IP)) goto tx_error; if (tos&1) tos = old_iph->tos; if (!dst) { /* NBMA tunnel */ if ((rt = (struct rtable*)skb->dst) == NULL) { tunnel->stat.tx_fifo_errors++; goto tx_error; } if ((dst = rt->rt_gateway) == 0) goto tx_error_icmp; } if (ip_route_output(&rt, dst, tiph->saddr, RT_TOS(tos), tunnel->parms.link)) { tunnel->stat.tx_carrier_errors++; goto tx_error_icmp; } tdev = rt->u.dst.dev; if (tdev == dev) { ip_rt_put(rt); tunnel->stat.collisions++; goto tx_error; } mtu = rt->u.dst.pmtu - sizeof(struct iphdr); if (mtu < 68) { tunnel->stat.collisions++; ip_rt_put(rt); goto tx_error; } if (skb->dst && mtu < skb->dst->pmtu) skb->dst->pmtu = mtu; df |= (old_iph->frag_off&__constant_htons(IP_DF)); if ((old_iph->frag_off&__constant_htons(IP_DF)) && mtu < ntohs(old_iph->tot_len)) { icmp_send(skb, ICMP_DEST_UNREACH, ICMP_FRAG_NEEDED, htonl(mtu)); ip_rt_put(rt); goto tx_error; } if (tunnel->err_count > 0) { if (jiffies - tunnel->err_time < IPTUNNEL_ERR_TIMEO) { tunnel->err_count--; dst_link_failure(skb); } else tunnel->err_count = 0; } skb->h.raw = skb->nh.raw; /* * Okay, now see if we can stuff it in the buffer as-is. */ max_headroom = (((tdev->hard_header_len+15)&~15)+sizeof(struct iphdr)); if (skb_headroom(skb) < max_headroom || skb_cloned(skb) || skb_shared(skb)) { struct sk_buff *new_skb = skb_realloc_headroom(skb, max_headroom); if (!new_skb) { ip_rt_put(rt); stats->tx_dropped++; dev_kfree_skb(skb); tunnel->recursion--; return 0; } if (skb->sk) skb_set_owner_w(new_skb, skb->sk); dev_kfree_skb(skb); skb = new_skb; } skb->nh.raw = skb_push(skb, sizeof(struct iphdr)); memset(&(IPCB(skb)->opt), 0, sizeof(IPCB(skb)->opt)); dst_release(skb->dst); skb->dst = &rt->u.dst; /* * Push down and install the IPIP header. */ iph = skb->nh.iph; iph->version = 4; iph->ihl = sizeof(struct iphdr)>>2; iph->frag_off = df; iph->protocol = IPPROTO_IPIP; iph->tos = tos; iph->daddr = rt->rt_dst; iph->saddr = rt->rt_src; if ((iph->ttl = tiph->ttl) == 0) iph->ttl = old_iph->ttl; iph->tot_len = htons(skb->len); iph->id = htons(ip_id_count++); ip_send_check(iph); stats->tx_bytes += skb->len; stats->tx_packets++; ip_send(skb); tunnel->recursion--; return 0; tx_error_icmp: dst_link_failure(skb); tx_error: stats->tx_errors++; dev_kfree_skb(skb); tunnel->recursion--; return 0; }
/* Return an ICMP response to the sender of a datagram. * Unlike most routines, the callER frees the mbuf. */ int icmp_output( struct ip *ip, /* Header of offending datagram */ struct mbuf *data, /* Data portion of datagram - FREED BY CALLER */ uint8 type, /* Codes to send */ uint8 code, union icmp_args *args ){ struct mbuf *bp; struct icmp icmp; /* ICMP protocol header */ uint dlen; /* Length of data portion of offending pkt */ uint length; /* Total length of reply */ if(ip == NULL) return -1; if(ip->protocol == ICMP_PTCL){ /* Peek at type field of ICMP header to see if it's safe to * return an ICMP message */ switch(data->data[0]){ case ICMP_ECHO_REPLY: case ICMP_ECHO: case ICMP_TIMESTAMP: case ICMP_TIME_REPLY: case ICMP_INFO_RQST: case ICMP_INFO_REPLY: break; /* These are all safe */ default: /* Never send an ICMP error message about another * ICMP error message! */ return -1; } } /* Compute amount of original datagram to return. * We return the original IP header, and up to 8 bytes past that. */ dlen = min(8,len_p(data)); length = dlen + ICMPLEN + IPLEN + ip->optlen; /* Take excerpt from data portion */ if(data != NULL && dup_p(&bp,data,0,dlen) == 0) return -1; /* The caller will free data */ /* Recreate and tack on offending IP header */ htonip(ip,&bp,IP_CS_NEW); icmp.type = type; icmp.code = code; icmp.args.unused = 0; switch(icmp.type){ case ICMP_PARAM_PROB: icmpOutParmProbs++; icmp.args.pointer = args->pointer; break; case ICMP_REDIRECT: icmpOutRedirects++; icmp.args.address = args->address; break; case ICMP_ECHO: icmpOutEchos++; break; case ICMP_ECHO_REPLY: icmpOutEchoReps++; break; case ICMP_INFO_RQST: break; case ICMP_INFO_REPLY: break; case ICMP_TIMESTAMP: icmpOutTimestamps++; break; case ICMP_TIME_REPLY: icmpOutTimestampReps++; icmp.args.echo.id = args->echo.id; icmp.args.echo.seq = args->echo.seq; break; case ICMP_ADDR_MASK: icmpOutAddrMasks++; break; case ICMP_ADDR_MASK_REPLY: icmpOutAddrMaskReps++; break; case ICMP_DEST_UNREACH: if(icmp.code == ICMP_FRAG_NEEDED) icmp.args.mtu = args->mtu; icmpOutDestUnreachs++; break; case ICMP_TIME_EXCEED: icmpOutTimeExcds++; break; case ICMP_QUENCH: icmpOutSrcQuenchs++; break; } icmpOutMsgs++; /* Now stick on the ICMP header */ htonicmp(&icmp,&bp); return ip_send(INADDR_ANY,ip->source,ICMP_PTCL,ip->tos,0,&bp,length,0,0); }