/*
 * 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;
 unsigned short ulen;
 int addr_type = IS_MYADDR;
 
 if(!dev || dev->pa_addr!=daddr)//??????????????????????????????
  addr_type=ip_chk_addr(daddr);//?ú?????????devinet.c?У???????ip????????????????????
 
 /*
  * Get the header.
  */
   uh = (struct udphdr *) skb->h.uh;//???UDP?????????
  
   ip_statistics.IpInDelivers++;

 /*
  * Validate the packet and the UDP length.
  */
 
 ulen = ntohs(uh->len);
 //????len???ip???????(IP?????????????????)= UDP??????+UDP??????????????+????????
 //ulen???????UDP??????????????????????????????????len>=ulen
 if (ulen > len || len < sizeof(*uh) || ulen < sizeof(*uh))
 {
  printk("UDP: short packet: %d/%d "?? ulen?? len);
  udp_statistics.UdpInErrors++;
  kfree_skb(skb?? FREE_WRITE);
  return(0);
 }

 if (uh->check && udp_check(uh?? len?? saddr?? daddr)) //????UDP?????У??
 {
  /* <mea@utu.fi> wants to know?? who sent it?? to
     go and stomp on the garbage sender... */
  printk("UDP: bad checksum. From %08lX:%d to %08lX:%d ulen %d "??
         ntohl(saddr)??ntohs(uh->source)??
         ntohl(daddr)??ntohs(uh->dest)??
         ulen);
  udp_statistics.UdpInErrors++;
  kfree_skb(skb?? FREE_WRITE);
  return(0);
 }


 len=ulen;//??len????????UDP?????????

#ifdef CONFIG_IP_MULTICAST//?????????д???
 if (addr_type!=IS_MYADDR)
 {
  /*
   * Multicasts and broadcasts go to each listener.
   */
  struct sock *sknext=NULL;//next???
 
  /*get_sock_mcast ????????????????????
  *???溯??????????α??:sock???????????????????????????????
  */
 
  sk=get_sock_mcast(udp_prot.sock_array[ntohs(uh->dest)&(SOCK_ARRAY_SIZE-1)]?? uh->dest??
    saddr?? uh->source?? daddr);
  if(sk)
  { 
   do
   {
    struct sk_buff *skb1;

    sknext=get_sock_mcast(sk->next?? uh->dest?? saddr?? uh->source?? daddr);//????????????????????
    if(sknext)
     skb1=skb_clone(skb??GFP_ATOMIC);
    else
     skb1=skb;
    if(skb1)
     udp_deliver(sk?? uh?? skb1?? dev??saddr??daddr??len);//???????????????????÷??????????
    sk=sknext;
   }
   while(sknext!=NULL);
  }
  else
   kfree_skb(skb?? FREE_READ);
  return 0;
 }
#endif
   sk = get_sock(&udp_prot?? uh->dest?? saddr?? uh->source?? daddr);
 if (sk == NULL) //????????????????????????г??????
   {
    udp_statistics.UdpNoPorts++;
  if (addr_type == IS_MYADDR)
  {
   icmp_send(skb?? ICMP_DEST_UNREACH?? ICMP_PORT_UNREACH?? 0?? dev);//???ICMP????????????????????
  }
  /*
   * Hmm.  We got an UDP broadcast to a port to which we
   * don't wanna listen.  Ignore it.
   */
  skb->sk = NULL;
  kfree_skb(skb?? FREE_WRITE);
  return(0);
   }

 return udp_deliver(sk??uh??skb??dev?? saddr?? daddr?? len);//???ú????????????
}