Ejemplo n.º 1
0
void uip_igmpsend(FAR struct uip_driver_s *dev, FAR struct igmp_group_s *group,
                  FAR uip_ipaddr_t *destipaddr)
{
  nllvdbg("msgid: %02x destipaddr: %08x\n", group->msgid, (int)*destipaddr);

  /* The total length to send is the size of the IP and IGMP headers and 4
   * bytes for the ROUTER ALERT (and, eventually, the ethernet header)
   */

  dev->d_len           = UIP_IPIGMPH_LEN;

  /* The total size of the data is the size of the IGMP header */

  dev->d_sndlen        = UIP_IGMPH_LEN;

  /* Add the router alert option */

  IGMPBUF->ra[0]       = HTONS(IPOPT_RA >> 16);
  IGMPBUF->ra[1]       = HTONS(IPOPT_RA & 0xffff);

  /* Initialize the IPv4 header */

  IGMPBUF->vhl         = 0x46;  /* 4->IP; 6->24 bytes */
  IGMPBUF->tos         = 0;
  IGMPBUF->len[0]      = (dev->d_len >> 8);
  IGMPBUF->len[1]      = (dev->d_len & 0xff);
  ++g_ipid;
  IGMPBUF->ipid[0]     = g_ipid >> 8;
  IGMPBUF->ipid[1]     = g_ipid & 0xff;
  IGMPBUF->ipoffset[0] = UIP_TCPFLAG_DONTFRAG >> 8;
  IGMPBUF->ipoffset[1] = UIP_TCPFLAG_DONTFRAG & 0xff;
  IGMPBUF->ttl         = IGMP_TTL;
  IGMPBUF->proto       = UIP_PROTO_IGMP;

  uiphdr_ipaddr_copy(IGMPBUF->srcipaddr, &dev->d_ipaddr);
  uiphdr_ipaddr_copy(IGMPBUF->destipaddr, destipaddr);

  /* Calculate IP checksum. */

  IGMPBUF->ipchksum    = 0;
  IGMPBUF->ipchksum    = ~uip_igmpchksum((FAR uint8_t *)IGMPBUF, UIP_IPH_LEN + RASIZE);

  /* Set up the IGMP message */

  IGMPBUF->type        = group->msgid;
  IGMPBUF->maxresp     = 0;
  uiphdr_ipaddr_copy(IGMPBUF->grpaddr, &group->grpaddr);

  /* Calculate the IGMP checksum. */

  IGMPBUF->chksum      = 0;
  IGMPBUF->chksum      = ~uip_igmpchksum(&IGMPBUF->type, UIP_IPIGMPH_LEN);

  IGMP_STATINCR(uip_stat.igmp.poll_send);
  IGMP_STATINCR(uip_stat.ip.sent);

  nllvdbg("Outgoing IGMP packet length: %d (%d)\n",
          dev->d_len, (IGMPBUF->len[0] << 8) | IGMPBUF->len[1]);
  igmp_dumppkt(RA, UIP_IPIGMPH_LEN + RASIZE);
}
Ejemplo n.º 2
0
static void uip_igmptimeout(int argc, uint32_t arg, ...)
{
  FAR struct igmp_group_s *group;

  /* If the state is DELAYING_MEMBER then we send a report for this group */

  nllvdbg("Timeout!\n");
  group = (FAR struct igmp_group_s *)arg;
  DEBUGASSERT(argc == 1 && group);

  /* If the group exists and is no an IDLE MEMBER, then it must be a DELAYING
   * member.  Race conditions are avoided because (1) the timer is not started
   * until after the first IGMPv2_MEMBERSHIP_REPORT during the join, and (2)
   * the timer is canceled before sending the IGMP_LEAVE_GROUP during a leave.
   */

  if (!IS_IDLEMEMBER(group->flags))
    {
      /* Schedule (and forget) the Membership Report.  NOTE:
       * Since we are executing from a timer interrupt, we cannot wait
       * for the message to be sent.
       */

      IGMP_STATINCR(uip_stat.igmp.report_sched);
      uip_igmpschedmsg(group, IGMPv2_MEMBERSHIP_REPORT);

      /* Also note:  The Membership Report is sent at most two times becasue
       * the timer is not reset here.  Hmm.. does this mean that the group
       * is stranded if both reports were lost?  This is consistent with the
       * RFC that states: "To cover the possibility of the initial Membership
       * Report being lost or damaged, it is recommended that it be repeated
       * once or twice after shortdelays [Unsolicited Report Interval]..."
       */
    }
}
Ejemplo n.º 3
0
static inline void igmp_sched_send(FAR struct net_driver_s *dev,
                                   FAR struct igmp_group_s *group)
{
  net_ipaddr_t *dest;

  /* Check what kind of message we need to send.  There are only two
   * possibilities:
   */

  if (group->msgid == IGMPv2_MEMBERSHIP_REPORT)
    {
      dest = &group->grpaddr;
      nllvdbg("Send IGMPv2_MEMBERSHIP_REPORT, dest=%08x flags=%02x\n",
               *dest, group->flags);
      IGMP_STATINCR(g_netstats.igmp.report_sched);
      SET_LASTREPORT(group->flags); /* Remember we were the last to report */
    }
  else
    {
      DEBUGASSERT(group->msgid == IGMP_LEAVE_GROUP);
      dest = &g_allrouters;
      nllvdbg("Send IGMP_LEAVE_GROUP, dest=%08x flags=%02x\n",
               *dest, group->flags);
      IGMP_STATINCR(g_netstats.igmp.leave_sched);
    }

  /* Send the message */

  igmp_send(dev, group, dest);

  /* Indicate that the message has been sent */

  CLR_SCHEDMSG(group->flags);
  group->msgid = 0;

  /* If there is a thread waiting fore the message to be sent, wake it up */

  if (IS_WAITMSG(group->flags))
    {
      nllvdbg("Awakening waiter\n");
      sem_post(&group->sem);
    }
}
Ejemplo n.º 4
0
int igmp_joingroup(struct uip_driver_s *dev, FAR const struct in_addr *grpaddr)
{
  struct igmp_group_s *group;

  DEBUGASSERT(dev && grpaddr);

  /* Check if a this address is already in the group */
 
  group = uip_grpfind(dev, &grpaddr->s_addr);
  if (!group)
    {
       /* No... allocate a new entry */
 
       nvdbg("Join to new group: %08x\n", grpaddr->s_addr);
       group = uip_grpalloc(dev, &grpaddr->s_addr);
       IGMP_STATINCR(uip_stat.igmp.joins);

       /* Send the Membership Report */
 
       IGMP_STATINCR(uip_stat.igmp.report_sched);
       uip_igmpwaitmsg(group, IGMPv2_MEMBERSHIP_REPORT);

       /* And start the timer at 10*100 msec */

       uip_igmpstarttimer(group, 10);

       /* Add the group (MAC) address to the ether drivers MAC filter list */

       uip_addmcastmac(dev, (FAR uip_ipaddr_t *)&grpaddr->s_addr);
       return OK;
    }

  /* Return EEXIST if the address is already a member of the group */

  return -EEXIST;
}