⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 udp.c

📁 Linux 1.0 内核C源代码 Linux最早版本代码 由Linus Torvalds亲自书写的
💻 C
📖 第 1 页 / 共 2 页
字号:
		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 + -