📄 udp.c
字号:
return err;
memcpy_fromfs(&sin, usin, sizeof(sin));
if (sin.sin_family && sin.sin_family != AF_INET)
return(-EINVAL);
if (sin.sin_port == 0)
return(-EINVAL);
} else {
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;
}
if(!sk->broadcast && chk_addr(sin.sin_addr.s_addr)==IS_BROADCAST)
return -EACCES; /* Must turn broadcast on first */
sk->inuse = 1;
/* Send the packet. */
tmp = udp_send(sk, &sin, from, len);
/* The datagram has been sent off. Release the socket. */
release_sock(sk);
return(tmp);
}
static int
udp_write(struct sock *sk, unsigned char *buff, int len, int noblock,
unsigned flags)
{
return(udp_sendto(sk, buff, len, noblock, flags, NULL, 0));
}
int
udp_ioctl(struct sock *sk, int cmd, unsigned long arg)
{
int err;
switch(cmd) {
case DDIOCSDBG:
{
int val;
if (!suser()) return(-EPERM);
err=verify_area(VERIFY_READ, (void *)arg, sizeof(int));
if(err)
return err;
val = get_fs_long((int *)arg);
switch(val) {
case 0:
inet_debug = 0;
break;
case 1:
inet_debug = DBG_UDP;
break;
default:
return(-EINVAL);
}
}
break;
case TIOCOUTQ:
{
unsigned long amount;
if (sk->state == TCP_LISTEN) return(-EINVAL);
amount = sk->prot->wspace(sk)/*/2*/;
err=verify_area(VERIFY_WRITE,(void *)arg,
sizeof(unsigned long));
if(err)
return(err);
put_fs_long(amount,(unsigned long *)arg);
return(0);
}
case TIOCINQ:
{
struct sk_buff *skb;
unsigned long amount;
if (sk->state == TCP_LISTEN) return(-EINVAL);
amount = 0;
skb = sk->rqueue;
if (skb != NULL) {
/*
* We will only return the amount
* of this packet since that is all
* that will be read.
*/
amount = skb->len;
}
err=verify_area(VERIFY_WRITE,(void *)arg,
sizeof(unsigned long));
if(err)
return(err);
put_fs_long(amount,(unsigned long *)arg);
return(0);
}
default:
return(-EINVAL);
}
return(0);
}
/*
* This should be easy, if there is something there we\
* return it, otherwise we block.
*/
int
udp_recvfrom(struct sock *sk, unsigned char *to, int len,
int noblock, unsigned flags, struct sockaddr_in *sin,
int *addr_len)
{
int copied = 0;
struct sk_buff *skb;
int er;
/*
* This will pick up errors that occured while the program
* was doing something else.
*/
if (sk->err) {
int err;
err = -sk->err;
sk->err = 0;
return(err);
}
if (len == 0)
return(0);
if (len < 0)
return(-EINVAL);
if (addr_len) {
er=verify_area(VERIFY_WRITE, addr_len, sizeof(*addr_len));
if(er)
return(er);
put_fs_long(sizeof(*sin), addr_len);
}
if(sin)
{
er=verify_area(VERIFY_WRITE, sin, sizeof(*sin));
if(er)
return(er);
}
er=verify_area(VERIFY_WRITE,to,len);
if(er)
return er;
skb=skb_recv_datagram(sk,flags,noblock,&er);
if(skb==NULL)
return er;
copied = min(len, skb->len);
/* FIXME : should use udp header size info value */
skb_copy_datagram(skb,sizeof(struct udphdr),to,copied);
/* Copy the address. */
if (sin) {
struct sockaddr_in addr;
addr.sin_family = AF_INET;
addr.sin_port = skb->h.uh->source;
addr.sin_addr.s_addr = skb->daddr;
memcpy_tofs(sin, &addr, sizeof(*sin));
}
skb_free_datagram(skb);
release_sock(sk);
return(copied);
}
int
udp_read(struct sock *sk, unsigned char *buff, int len, int noblock,
unsigned flags)
{
return(udp_recvfrom(sk, buff, len, noblock, flags, NULL, NULL));
}
int
udp_connect(struct sock *sk, struct sockaddr_in *usin, int addr_len)
{
struct sockaddr_in sin;
int er;
if (addr_len < sizeof(sin))
return(-EINVAL);
er=verify_area(VERIFY_READ, usin, sizeof(sin));
if(er)
return er;
memcpy_fromfs(&sin, usin, sizeof(sin));
if (sin.sin_family && sin.sin_family != AF_INET)
return(-EAFNOSUPPORT);
if(!sk->broadcast && chk_addr(sin.sin_addr.s_addr)==IS_BROADCAST)
return -EACCES; /* Must turn broadcast on first */
sk->daddr = sin.sin_addr.s_addr;
sk->dummy_th.dest = sin.sin_port;
sk->state = TCP_ESTABLISHED;
return(0);
}
static void
udp_close(struct sock *sk, int timeout)
{
sk->inuse = 1;
sk->state = TCP_CLOSE;
if (sk->dead) destroy_sock(sk);
else release_sock(sk);
}
/* All we need to do is get the socket, and then do a checksum. */
int
udp_rcv(struct sk_buff *skb, struct device *dev, struct options *opt,
unsigned long daddr, unsigned short len,
unsigned long saddr, int redo, struct inet_protocol *protocol)
{
struct sock *sk;
struct udphdr *uh;
uh = (struct udphdr *) skb->h.uh;
sk = get_sock(&udp_prot, uh->dest, saddr, uh->source, daddr);
if (sk == NULL)
{
if (chk_addr(daddr) == IS_MYADDR)
{
icmp_send(skb, ICMP_DEST_UNREACH, ICMP_PORT_UNREACH, dev);
}
/*
* Hmm. We got an UDP broadcast to a port to which we
* don't wanna listen. The only thing we can do now is
* to ignore the packet... -FvK
*/
skb->sk = NULL;
kfree_skb(skb, FREE_WRITE);
return(0);
}
if (uh->check && udp_check(uh, len, saddr, daddr)) {
DPRINTF((DBG_UDP, "UDP: bad checksum\n"));
skb->sk = NULL;
kfree_skb(skb, FREE_WRITE);
return(0);
}
skb->sk = sk;
skb->dev = dev;
skb->len = len;
/* These are supposed to be switched. */
skb->daddr = saddr;
skb->saddr = daddr;
/* Charge it to the socket. */
if (sk->rmem_alloc + skb->mem_len >= sk->rcvbuf)
{
skb->sk = NULL;
kfree_skb(skb, FREE_WRITE);
release_sock(sk);
return(0);
}
sk->rmem_alloc += skb->mem_len;
/* At this point we should print the thing out. */
DPRINTF((DBG_UDP, "<< \n"));
print_udp(uh);
/* Now add it to the data chain and wake things up. */
skb_queue_tail(&sk->rqueue,skb);
skb->len = len - sizeof(*uh);
if (!sk->dead)
sk->data_ready(sk,skb->len);
release_sock(sk);
return(0);
}
struct proto udp_prot = {
sock_wmalloc,
sock_rmalloc,
sock_wfree,
sock_rfree,
sock_rspace,
sock_wspace,
udp_close,
udp_read,
udp_write,
udp_sendto,
udp_recvfrom,
ip_build_header,
udp_connect,
NULL,
ip_queue_xmit,
ip_retransmit,
NULL,
NULL,
udp_rcv,
datagram_select,
udp_ioctl,
NULL,
NULL,
ip_setsockopt,
ip_getsockopt,
128,
0,
{NULL,},
"UDP"
};
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -