/* * Add an ip header to a skbuff and send it out. * */ int ip_build_and_send_pkt(struct sk_buff *skb, struct sock *sk, __be32 saddr, __be32 daddr, struct ip_options_rcu *opt) { struct inet_sock *inet = inet_sk(sk); struct rtable *rt = skb_rtable(skb); struct iphdr *iph; /* Build the IP header. */ skb_push(skb, sizeof(struct iphdr) + (opt ? opt->opt.optlen : 0)); skb_reset_network_header(skb); iph = ip_hdr(skb); iph->version = 4; iph->ihl = 5; iph->tos = inet->tos; if (ip_dont_fragment(sk, &rt->dst)) iph->frag_off = htons(IP_DF); else iph->frag_off = 0; iph->ttl = ip_select_ttl(inet, &rt->dst); iph->daddr = (opt && opt->opt.srr ? opt->opt.faddr : daddr); iph->saddr = saddr; iph->protocol = sk->sk_protocol; ip_select_ident(skb, sk); if (opt && opt->opt.optlen) { iph->ihl += opt->opt.optlen>>2; ip_options_build(skb, &opt->opt, daddr, rt, 0); }
/* * Add an ip header to a skbuff and send it out. * */ int ip_build_and_send_pkt(struct sk_buff *skb, struct sock *sk, u32 saddr, u32 daddr, struct ip_options *opt) { struct inet_sock *inet = inet_sk(sk); struct rtable *rt = (struct rtable *)skb->dst; struct iphdr *iph; /* Build the IP header. */ if (opt) iph=(struct iphdr *)skb_push(skb,sizeof(struct iphdr) + opt->optlen); else iph=(struct iphdr *)skb_push(skb,sizeof(struct iphdr)); iph->version = 4; iph->ihl = 5; iph->tos = inet->tos; if (ip_dont_fragment(sk, &rt->u.dst)) iph->frag_off = htons(IP_DF); else iph->frag_off = 0; iph->ttl = ip_select_ttl(inet, &rt->u.dst); iph->daddr = rt->rt_dst; iph->saddr = rt->rt_src; iph->protocol = sk->sk_protocol; iph->tot_len = htons(skb->len); ip_select_ident(iph, &rt->u.dst, sk); skb->nh.iph = iph; if (opt && opt->optlen) { iph->ihl += opt->optlen>>2; ip_options_build(skb, opt, daddr, rt, 0); }
int ip_build_xmit(struct sock *sk, void getfrag (const void *, __u32, char *, unsigned int, unsigned int), const void *frag, unsigned short int length, __u32 daddr, __u32 user_saddr, struct options * opt, int flags, int type, int noblock) { struct rtable *rt; unsigned int fraglen, maxfraglen, fragheaderlen; int offset, mf; __u32 saddr; unsigned short id; struct iphdr *iph; __u32 raddr; struct device *dev = NULL; struct hh_cache * hh=NULL; int nfrags=0; __u32 true_daddr = daddr; if (opt && opt->srr && !sk->ip_hdrincl) daddr = opt->faddr; ip_statistics.IpOutRequests++; #ifdef CONFIG_IP_MULTICAST if(MULTICAST(daddr) && *sk->ip_mc_name) { dev=dev_get(sk->ip_mc_name); if(!dev) return -ENODEV; rt=NULL; if (sk->saddr && (!LOOPBACK(sk->saddr) || LOOPBACK(daddr))) saddr = sk->saddr; else saddr = dev->pa_addr; } else { #endif rt = ip_check_route(&sk->ip_route_cache, daddr, sk->localroute || (flags&MSG_DONTROUTE) || (opt && opt->is_strictroute), sk->bound_device); if (rt == NULL) { ip_statistics.IpOutNoRoutes++; return(-ENETUNREACH); } saddr = rt->rt_src; hh = rt->rt_hh; if (sk->saddr && (!LOOPBACK(sk->saddr) || LOOPBACK(daddr))) saddr = sk->saddr; dev=rt->rt_dev; #ifdef CONFIG_IP_MULTICAST } if (rt && !dev) dev = rt->rt_dev; #endif if (user_saddr) saddr = user_saddr; raddr = rt ? rt->rt_gateway : daddr; /* * Now compute the buffer space we require */ /* * Try the simple case first. This leaves broadcast, multicast, fragmented frames, and by * choice RAW frames within 20 bytes of maximum size(rare) to the long path */ if (!sk->ip_hdrincl) { length += sizeof(struct iphdr); if (opt) { /* make sure not to exceed maximum packet size */ if (0xffff - length < opt->optlen) return -EMSGSIZE; length += opt->optlen; } } if(length <= dev->mtu && !MULTICAST(daddr) && daddr!=0xFFFFFFFF && daddr!=dev->pa_brdaddr) { int error; struct sk_buff *skb=sock_alloc_send_skb(sk, length+15+dev->hard_header_len,0, noblock, &error); if(skb==NULL) { ip_statistics.IpOutDiscards++; return error; } skb->dev=dev; skb->protocol = htons(ETH_P_IP); skb->free=1; skb->when=jiffies; skb->sk=sk; skb->arp=0; skb->saddr=saddr; skb->raddr = raddr; skb_reserve(skb,(dev->hard_header_len+15)&~15); if (hh) { skb->arp=1; memcpy(skb_push(skb,dev->hard_header_len),hh->hh_data,dev->hard_header_len); if (!hh->hh_uptodate) { skb->arp = 0; #if RT_CACHE_DEBUG >= 2 printk("ip_build_xmit: hh miss %08x via %08x\n", rt->rt_dst, rt->rt_gateway); #endif } } else if(dev->hard_header) { if(dev->hard_header(skb,dev,ETH_P_IP,NULL,NULL,0)>0) skb->arp=1; } else skb->arp=1; skb->ip_hdr=iph=(struct iphdr *)skb_put(skb,length); dev_lock_list(); if(!sk->ip_hdrincl) { iph->version=4; iph->ihl=5; iph->tos=sk->ip_tos; iph->tot_len = htons(length); iph->id=htons(ip_id_count++); iph->frag_off = 0; iph->ttl=sk->ip_ttl; iph->protocol=type; iph->saddr=saddr; iph->daddr=daddr; if (opt) { iph->ihl += opt->optlen>>2; ip_options_build(skb, opt, true_daddr, dev->pa_addr, 0); } iph->check=0; iph->check = ip_fast_csum((unsigned char *)iph, iph->ihl); getfrag(frag,saddr,((char *)iph)+iph->ihl*4,0, length-iph->ihl*4); }
/* * 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; }