????????????????????????ú???ip_queue_xmit()???????????????????????????????????????ú?????

?????ú???????????????ù??????£?

/*
 * Queues a packet to be sent?? and starts the transmitter
 * if necessary.  if free = 1 then we free the block after
 * transmit?? otherwise we don't. If free==2 we not only
 * free the block but also don't assign a new ip seq number.
 * This routine also needs to put in the total length??
 * and compute the checksum
 */

void ip_queue_xmit(struct sock *sk?? //???????????????????sock??
       struct device *dev??//?????????????????豸
            struct sk_buff *skb??//??????sk_buff????????????????y???
            int free)//??????TCPЭ??????????????????????UDP??Э???????free=1
{
 struct iphdr *iph;//IP???????????
 unsigned char *ptr;

 /* Sanity check */
 if (dev == NULL)
 {
  printk("IP: ip_queue_xmit dev = NULL ");
  return;
 }

 IS_SKB(skb);

 /*
  * Do some book-keeping in the packet for later
  */


 skb->dev = dev;//?????????sk_buff????????
 skb->when = jiffies;//????TCPЭ????????

 /*
  * Find the IP header and set the length. This is bad
  * but once we get the skb data handling code in the
  * hardware will push its header sensibly and we will
  * set skb->ip_hdr to avoid this mess and the fixed
  * header length problem
  */

 ptr = skb->data;//??????sk_buff?е????????
 ptr += dev->hard_header_len;//hard_header_len??????????????net_init.c?????eth_setup()????????????dev->hard_header_len = ETH_HLEN; ?????????????14
 iph = (struct iphdr *)ptr;//prt??????IP??????????
 skb->ip_hdr = iph;
 iph->tot_len = ntohs(skb->len-dev->hard_header_len);//????IP????????????

#ifdef CONFIG_IP_FIREWALL
 if(ip_fw_chk(iph?? dev?? ip_fw_blk_chain?? ip_fw_blk_policy?? 0) != 1)
  /* just don't send this packet */
  return;
#endif

 /*
  * No reassigning numbers to fragments...
  */

 if(free!=2)
  iph->id      = htons(ip_id_count++);
 else
  free=1;

 /* All buffers without an owner socket get freed */
 if (sk == NULL)
  free = 1;

 skb->free = free;//????skb??free???free=1???????????????free=2???????????棬??????????μ????к?

 /*
  * Do we need to fragment. Again this is inefficient.
  * We need to somehow lock the original buffer and use
  * bits of it.
  */
 //??????е???????????С?????MTU
 if(skb->len > dev->mtu + dev->hard_header_len)//??????????????????????????????????????????????
 {
  ip_fragment(sk??skb??dev??0);//???????????????????ip _queue_xmit()????????????
  IS_SKB(skb);
  kfree_skb(skb??FREE_WRITE);
  return;
 }

 /*
  * Add an IP checksum
  */

 ip_send_check(iph);//IP???????????

 /*
  * Print the frame when debugging
  */

 /*
  * More debugging. You cannot queue a packet already on a list
  * Spot this and moan loudly.
  */
 if (skb->next != NULL)//?????????????????????????????
 {
  printk("ip_queue_xmit: next != NULL ");
  skb_unlink(skb);//???????????????????????????????????
 }

 /*
  * If a sender wishes the packet to remain unfreed
  * we add it to his send queue. This arguably belongs
  * in the TCP level since nobody else uses it. BUT
  * remember IPng might change all the rules.
  */

 if (!free)//free=0
 {
  unsigned long flags;
  /* The socket now has more outstanding blocks */

  sk->packets_out++;

  /* Protect the list for a moment */
  save_flags(flags);
  cli();

  if (skb->link3 != NULL)//link3???????????????????
  {
   printk("ip.c: link3 != NULL ");
   skb->link3 = NULL;
  }
  //sk??send_tail??send_head??????????????????β????
  if (sk->send_head == NULL)
  {
   sk->send_tail = skb;
   sk->send_head = skb;
  }
  else
  {
   sk->send_tail->link3 = skb;//link3??????????????????
   sk->send_tail = skb;
  }
  /* skb->link3 is NULL */

  /* Interrupt restore */
  restore_flags(flags);
 }
 else
  /* Remember who owns the buffer */
  skb->sk = sk;

 /*
  * If the indicated interface is up and running?? send the packet.
  */
 
 ip_statistics.IpOutRequests++;
#ifdef CONFIG_IP_ACCT
 ip_acct_cnt(iph??dev?? ip_acct_chain);
#endif
 
#ifdef CONFIG_IP_MULTICAST //??????IP????????????

 /*
  * Multicasts are looped back for other local users
  */
 
 .......................................
#endif
 if((dev->flags&IFF_BROADCAST) && iph->daddr==dev->pa_brdaddr && !(dev->flags&IFF_LOOPBACK))//????????????
  ip_loopback(dev??skb);
 
 if (dev->flags & IFF_UP)//?豸??????
 {
  /*
   * If we have an owner use its priority setting??
   * otherwise use NORMAL
   */
  //?????豸??????????????: dev_queue_xmit()????
  if (sk != NULL)
  {
   dev_queue_xmit(skb?? dev?? sk->priority);
  }
  else
  {
   dev_queue_xmit(skb?? dev?? SOPRI_NORMAL);
  }
 }
 else//?豸????????
 {
  ip_statistics.IpOutDiscards++;
  if (free)
   kfree_skb(skb?? FREE_WRITE);
 }
}