www.usr.com/support/gpl/USR9113_release1.0.tar.gz
[bcm963xx.git] / userapps / opensource / udhcp / options.c
index 284744a..7766e54 100755 (executable)
@@ -227,3 +227,304 @@ void attach_option(struct option_set **opt_list, struct dhcp_option *option, cha
                *curr = new;            
        }
 }
+
+
+//brcm begin
+void viInfoFree(pVI_OPTION_INFO pInfo)
+{
+  if (pInfo) {
+    free(pInfo->oui);
+    free(pInfo->serialNumber);
+    free(pInfo->productClass);
+    free(pInfo);
+  }
+}
+
+void addViToList(pVI_OPTION_INFO pNew) {
+  pVI_OPTION_INFO pPtr= NULL;
+
+  /* if VI exists already, don't add, just update the info */
+  if (viList->count > 0) {
+    pPtr = viList->pHead;
+    while (pPtr) {
+      if (pPtr->ipAddr == pNew->ipAddr) {
+       /* found it, just copy the info over */
+       memcpy(pPtr,pNew,sizeof(VI_OPTION_INFO));
+       viInfoFree(pNew);
+       return;
+      }
+      pPtr = pPtr->next;
+    } /* while */
+  } /* list has something */
+
+  if (viList->pHead == NULL) {
+    viList->pHead = pNew;
+    viList->pTail = pNew;
+  }
+  else {
+    viList->pTail->next = pNew;
+    viList->pTail = pNew;
+  }
+  viList->count++;
+}
+
+void viListFree(void)
+{
+  pVI_OPTION_INFO pInfo;
+
+  while (viList->pHead) {
+    pInfo = viList->pHead;
+    viList->pHead = viList->pHead->next;
+    free(pInfo->oui);
+    free(pInfo->serialNumber);
+    free(pInfo->productClass);
+    free(pInfo);
+  }
+  viList->count = 0;
+}
+
+
+/* this function generates VI info based on TR111 part I.
+   If -1 is return, there is no VI info found.  Otherwise, 0 is returned.
+   Type specifies gateway vendor info or device vendor info.   
+   VIinfo is where the option string is stored */
+int createVIoption(int type, char *VIinfo)
+{
+  FILE* fs;
+  char optionData[VENDOR_IDENTIFYING_INFO_LEN], *dataPtr;
+  int len, totalLen = 0;
+  char line[VENDOR_IDENTIFYING_INFO_LEN];
+  char oui[6];
+  char serialNum[64];
+  char productClass[64];
+
+  fs = fopen("/var/fyi/sys/info", "r");
+  if (fs == NULL) {
+    return (-1);
+  }
+  fgets(line, VENDOR_IDENTIFYING_INFO_LEN, fs);
+  sscanf(line, "OUI %s\n", oui);
+  fgets(line, VENDOR_IDENTIFYING_INFO_LEN, fs);
+  sscanf(line, "SerialNumber %s\n", serialNum);
+  fgets(line, VENDOR_IDENTIFYING_INFO_LEN, fs);
+  sscanf(line, "ProductClass %s\n", productClass);
+  fclose(fs);
+
+  optionData[VENDOR_OPTION_CODE_OFFSET] = (char)VENDOR_IDENTIFYING_OPTION_CODE;
+  *(unsigned int*)(optionData+VENDOR_OPTION_ENTERPRISE_OFFSET) = (unsigned int)VENDOR_BRCM_ENTERPRISE_NUMBER;
+  dataPtr = optionData + VENDOR_OPTION_DATA_OFFSET;
+  totalLen = VENDOR_ENTERPRISE_LEN;
+  /* read system information and add it to option data */
+  /* OUI */
+  if (type == VENDOR_IDENTIFYING_FOR_DEVICE)
+    *dataPtr++ = (char)VENDOR_DEVICE_OUI_SUBCODE;
+  else 
+    *dataPtr++ = (char)VENDOR_GATEWAY_OUI_SUBCODE;
+  len = strlen(oui);
+  *dataPtr++ = len;
+  strncpy(dataPtr,oui,len);
+  dataPtr += len;
+  totalLen += (len + VENDOR_SUBCODE_AND_LEN_BYTES);
+  
+  /* Serial Number */
+  if (type == VENDOR_IDENTIFYING_FOR_DEVICE)
+    *dataPtr++ = (char)VENDOR_DEVICE_SERIAL_NUMBER_SUBCODE;
+  else
+    *dataPtr++ = (char)VENDOR_GATEWAY_SERIAL_NUMBER_SUBCODE;
+  len = strlen(serialNum);
+  *dataPtr++ = len;
+  strncpy(dataPtr,(const char*)serialNum,len);
+  dataPtr += len;
+  totalLen += (len + VENDOR_SUBCODE_AND_LEN_BYTES);
+
+  /* Product Class */
+  if (type == VENDOR_IDENTIFYING_FOR_DEVICE)
+    *dataPtr++ = VENDOR_DEVICE_PRODUCT_CLASS_SUBCODE;
+  else 
+    *dataPtr++ = VENDOR_GATEWAY_PRODUCT_CLASS_SUBCODE;
+  len = strlen(productClass);
+  *dataPtr++ = len;
+  strncpy(dataPtr,(const char*)productClass,len);
+  dataPtr += len;
+  totalLen += (len + VENDOR_SUBCODE_AND_LEN_BYTES);
+
+  optionData[VENDOR_OPTION_LEN_OFFSET] = totalLen;
+
+  /* also copy the option code and option len which is not counted in total len */
+  memcpy((void*)VIinfo,(void*)optionData,(totalLen+VENDOR_OPTION_DATA_OFFSET));
+
+  return 0;
+}
+/* udp_send and readIp from voice */
+static int readIp(const char* ip)
+{
+   int n = 0;
+   int res = 0;
+   
+   while (n < 4 && *ip)
+   {
+      if (isdigit(*ip)) 
+      {
+         res = (res << 8) | atoi(ip);
+         n++;
+         while (isdigit(*ip)) 
+         {
+            ip++;
+         }
+      } 
+      else 
+      {
+         ip++;
+               }
+   }
+   return res;
+}
+
+static int notifyApp(short port, void *data, int len)
+{
+   int sockfd;
+   struct sockaddr_in serv_addr;
+   struct sockaddr_in cli_addr;
+   
+   /* fill in server address */
+   memset(&serv_addr, 0, sizeof(serv_addr));
+   serv_addr.sin_family      = AF_INET;
+   serv_addr.sin_addr.s_addr = readIp("127.0.0.1");
+   serv_addr.sin_port        = htons(port);
+
+   /* open udp socket */
+   if ((sockfd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) 
+   {
+      printf("WT-104: Could not open socket for send\n");
+      return -1; /* could not open socket */
+   }
+
+   /* bind any local address for us */ 
+   memset(&cli_addr, 0, sizeof(cli_addr));
+   cli_addr.sin_family      = AF_INET;
+   cli_addr.sin_addr.s_addr = htonl(INADDR_ANY);
+   cli_addr.sin_port        = htons(0);
+
+   if (bind(sockfd, (struct sockaddr *) &cli_addr, sizeof(cli_addr)) < 0) 
+   {
+      printf("dhcpd: Could not bind client socket\n");
+      return -2; /* could not bind client socket */
+   }
+   /* send the data */
+   if (sendto(sockfd, data, len, 0, (struct sockaddr *) &serv_addr, sizeof(serv_addr)) != len) 
+   {
+      printf( "dhcpd: Could not sendto\n");
+      return -3; /* could not sendto */
+   }
+   close(sockfd);
+   return 0;
+}
+
+/* this function parses received VI info, and save it.
+   If -1 is return, there is no VI info found; invalid option.  Otherwise, 0 is returned.
+   *option is the received option string to parse; it points to optionData.
+   ipAddr is the device's offered address or device's ip address */
+int saveVIoption(char *option, u_int32_t ipAddr)
+{
+  char *optionPtr;
+
+  int maxSubcode = 3;
+  int subcodeParsed = 0;
+  int subcode, sublen;
+  pVI_OPTION_INFO pInfo = NULL;
+  int ret = 0;
+  int msg = 0;
+
+  if (option == NULL) {
+    DEBUG(LOG_ERR, "saveVIoption(): option is NULL.");
+    return -1;
+  }
+
+  optionPtr = option;
+  pInfo = malloc(sizeof(VI_OPTION_INFO));
+  memset(pInfo,0,sizeof(VI_OPTION_INFO));
+  pInfo->enterprise = *(unsigned int*)(optionPtr);
+  pInfo->ipAddr = ipAddr;
+  optionPtr += VENDOR_ENTERPRISE_LEN;
+
+  while (subcodeParsed < maxSubcode) {
+     /* subcode, len, data */
+     subcode = *optionPtr++;
+     sublen = *optionPtr++;
+     subcodeParsed++;
+     switch (subcode)
+     {
+     case VENDOR_DEVICE_OUI_SUBCODE:
+     case VENDOR_GATEWAY_OUI_SUBCODE:
+        if (sublen <= VENDOR_GATEWAY_OUI_MAX_LEN) {
+           if ((pInfo->oui = malloc(sublen+1)) != NULL) {
+              memcpy(pInfo->oui,optionPtr,sublen);
+              pInfo->oui[sublen] = '\0';
+           }
+           else        
+              goto viError;
+        }
+        else {
+           DEBUG(LOG_ERR, "saveVIoption(): subcode OUI, OUI len %d is too long.",sublen);
+           goto viError;
+        }
+        break;
+     case VENDOR_DEVICE_SERIAL_NUMBER_SUBCODE:
+     case VENDOR_GATEWAY_SERIAL_NUMBER_SUBCODE:
+        if (sublen <= VENDOR_GATEWAY_SERIAL_NUMBER_MAX_LEN) {
+           if ((pInfo->serialNumber = malloc(sublen+1)) != NULL) {
+              memcpy(pInfo->serialNumber,optionPtr,sublen);
+              pInfo->serialNumber[sublen] = '\0';
+           }
+           else
+              goto viError;
+        }
+        else {
+           DEBUG(LOG_ERR, "saveVIoption(): subcode SerialNumber, Serial Number len %d is too long.",sublen);
+           goto viError;
+        }
+        break;
+     case VENDOR_DEVICE_PRODUCT_CLASS_SUBCODE:
+     case VENDOR_GATEWAY_PRODUCT_CLASS_SUBCODE:
+        if (sublen <= VENDOR_GATEWAY_PRODUCT_CLASS_MAX_LEN) {
+           if ((pInfo->productClass = malloc(sublen+1)) != NULL) {
+              memcpy(pInfo->productClass,optionPtr,sublen);
+              pInfo->productClass[sublen] = '\0';
+           }
+           else
+              goto viError;
+        }
+        else {
+           DEBUG(LOG_ERR, "saveVIoption(): subcode ProductClass, Class len %d is too long.",sublen);
+           goto viError;
+        }
+        break;
+     default:
+        DEBUG(LOG_ERR, "saveVIoption(): subcode %d, not supported.",subcode);
+        goto viError;
+     }
+     optionPtr += sublen;
+     /* add info to the manageable device link list */
+  } /* while subcodeParsed < maxSubcode */
+  addViToList(pInfo);
+  notifyApp(30006,(void*)&msg,sizeof(msg));
+
+  return ret;
+
+ viError:
+  ret = -1;
+  if (pInfo) {
+    if (pInfo->oui)
+      free(pInfo->oui);
+    if (pInfo->serialNumber)
+      free(pInfo->serialNumber);
+    if (pInfo->productClass)
+      free(pInfo->productClass);
+    free(pInfo);
+  }
+  return ret;
+}
+
+
+//brcm end