static int inet_getname(struct socket *sock, struct sockaddr *uaddr, int *uaddr_len, int peer) { struct sockaddr_in *sin=(struct sockaddr_in *)uaddr; struct sock *sk; sin->sin_family = AF_INET; sk = (struct sock *) sock->data; if (peer) { if (!tcp_connected(sk->state)) return(-ENOTCONN); sin->sin_port = sk->dummy_th.dest; sin->sin_addr.s_addr = sk->daddr; } else { sin->sin_port = sk->dummy_th.source; /* 如果使用了通配地址,就用主设备地址作为源地址 */ if (sk->saddr == 0) sin->sin_addr.s_addr = ip_my_addr(); else sin->sin_addr.s_addr = sk->saddr; } *uaddr_len = sizeof(*sin); return(0); }
int udp_connect(struct sock *sk, struct sockaddr_in *usin, int addr_len) { struct rtable *rt; if (addr_len < sizeof(*usin)) return(-EINVAL); if (usin->sin_family && usin->sin_family != AF_INET) return(-EAFNOSUPPORT); if (usin->sin_addr.s_addr==INADDR_ANY) usin->sin_addr.s_addr=ip_my_addr(); if(!sk->broadcast && ip_chk_addr(usin->sin_addr.s_addr)==IS_BROADCAST) return -EACCES; /* Must turn broadcast on first */ rt=ip_rt_route((__u32)usin->sin_addr.s_addr, sk->localroute, sk->bound_device); if (rt==NULL) return -ENETUNREACH; if(!sk->saddr) sk->saddr = rt->rt_src; /* Update source address */ if(!sk->rcv_saddr) sk->rcv_saddr = rt->rt_src; sk->daddr = usin->sin_addr.s_addr; sk->dummy_th.dest = usin->sin_port; sk->state = TCP_ESTABLISHED; if (sk->ip_route_cache) ip_rt_put(sk->ip_route_cache); sk->ip_route_cache = rt; return(0); }
static int raw_sendto(struct sock *sk, const unsigned char *from, int len, int noblock, unsigned flags, struct sockaddr_in *usin, int addr_len) { int err; struct sockaddr_in sin; /* * Check the flags. Only MSG_DONTROUTE is permitted. */ if (flags & MSG_OOB) /* Mirror BSD error message compatibility */ return -EOPNOTSUPP; if (flags & ~MSG_DONTROUTE) return(-EINVAL); /* * Get and verify the address. */ if (usin) { if (addr_len < sizeof(sin)) return(-EINVAL); memcpy(&sin, usin, sizeof(sin)); if (sin.sin_family && sin.sin_family != AF_INET) return(-EINVAL); } else { if (sk->state != TCP_ESTABLISHED) return(-EINVAL); sin.sin_family = AF_INET; sin.sin_port = sk->num; sin.sin_addr.s_addr = sk->daddr; } if (sin.sin_port == 0) sin.sin_port = sk->num; if (sin.sin_addr.s_addr == INADDR_ANY) sin.sin_addr.s_addr = ip_my_addr(); /* * BSD raw sockets forget to check SO_BROADCAST .... */ if (!sk->bsdism && sk->broadcast == 0 && ip_chk_addr(sin.sin_addr.s_addr)==IS_BROADCAST) return -EACCES; if(sk->ip_hdrincl) { if(len>65535) return -EMSGSIZE; err=ip_build_xmit(sk, raw_getrawfrag, from, len, sin.sin_addr.s_addr, 0, sk->opt, flags, sin.sin_port, noblock); } else { if(len>65535-sizeof(struct iphdr)) return -EMSGSIZE; err=ip_build_xmit(sk, raw_getfrag, from, len, sin.sin_addr.s_addr, 0, sk->opt, flags, sin.sin_port, noblock); } return err<0?err:len; }
static int udp_sendto(struct sock *sk, const unsigned char *from, int len, int noblock, unsigned flags, struct sockaddr_in *usin, int addr_len) { struct sockaddr_in sin; int tmp; __u32 saddr=0; /* * Check the flags. We support no flags for UDP sending */ #ifdef CONFIG_IP_TRANSPARENT_PROXY if (flags&~(MSG_DONTROUTE|MSG_PROXY)) #else if (flags&~MSG_DONTROUTE) #endif return(-EINVAL); /* * Get and verify the address. */ if (usin) { if (addr_len < sizeof(sin)) return(-EINVAL); if (usin->sin_family && usin->sin_family != AF_INET) return(-EINVAL); if (usin->sin_port == 0) return(-EINVAL); } else { #ifdef CONFIG_IP_TRANSPARENT_PROXY /* We need to provide a sockaddr_in when using MSG_PROXY. */ if (flags&MSG_PROXY) return(-EINVAL); #endif if (sk->state != TCP_ESTABLISHED) return(-EINVAL); sin.sin_family = AF_INET; sin.sin_port = sk->dummy_th.dest; sin.sin_addr.s_addr = sk->daddr; usin = &sin; } /* * BSD socket semantics. You must set SO_BROADCAST to permit * broadcasting of data. */ /* RFC1122: OK. Allows the application to select the specific */ /* source address for an outgoing packet (MUST) as per 4.1.3.5. */ /* Optional addition: a mechanism for telling the application what */ /* address was used. (4.1.3.5, MAY) -- MS */ /* RFC1122: MUST ensure that all outgoing packets have one */ /* of this host's addresses as a source addr.(4.1.3.6) - bind in */ /* af_inet.c checks these. It does need work to allow BSD style */ /* bind to multicast as is done by xntpd */ if(usin->sin_addr.s_addr==INADDR_ANY) usin->sin_addr.s_addr=ip_my_addr(); if(!sk->broadcast && ip_chk_addr(usin->sin_addr.s_addr)==IS_BROADCAST) return -EACCES; /* Must turn broadcast on first */ lock_sock(sk); /* Send the packet. */ tmp = udp_send(sk, usin, from, len, flags, saddr, noblock); /* The datagram has been sent off. Release the socket. */ release_sock(sk); return(tmp); }
/* * 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 */ }