📄 dhcpccommonlib.c
字号:
pMbuf = bcopy_to_mbufs (pData, size, 0, pIf, NONE); if (pMbuf == NULL) return (ERROR); if (broadcastFlag) pMbuf->mBlkHdr.mFlags |= M_BCAST; level = splnet (); result = pIf->if_output (pIf, pMbuf, (struct sockaddr *)pDest, NULL); splx (level); if (result) return (ERROR); return (OK); }/********************************************************************************* dhcpcRead - handle all incoming DHCP messages** This routine monitors all active BPF devices for new DHCP messages and* signals the lease monitor task when a valid message arrives. It is the* entry point for the data retrieval task created during the library* initialization and should only be called internally.** RETURNS: N/A** ERRNO: N/A** NOMANUAL*/void dhcpcRead (void) { STATUS result; EVENT_DATA newEvent; int key; char * pMsgData = NULL; BOOL dataFlag; fd_set readFds; int fileNum = 0; int maxFileNum; int slot = 0; /* Current buffer for holding messages. */ int maxSlot = 10; /* Matches size of event ring. */ int loop; int bufSize = 0; struct bpf_hdr * pMsgHdr; int msglen; int curlen; int totlen; /* Amount of data in BPF buffer. */ struct timeval timeout; timeout.tv_sec = timeout.tv_usec = 0; FOREVER { /* * Wait until a message arrives or a new DHCP session is available. * The dhcpcInit() routine forces the read task to rebuild the list * of active devices by sending an empty message to the selected DHCP * client port so that the select routine exits. */ FD_ZERO (&readFds); maxFileNum = 0; if (!_dhcpcBootFlag) { /* * Runtime DHCP sessions monitor a UDP socket bound to the * DHCP port to read and discard messages which were already * processed through the Berkeley Packet Filters. This socket * also allows the read loop to restart when a new DHCP session * begins. The boot time DHCP session is unable to use any * sockets since no fully configured devices exist. */ FD_SET (dhcpcDataSock, &readFds); maxFileNum = dhcpcDataSock; } /* Create list of active BPF devices for monitoring. */ for (loop = 0; loop < dhcpcMaxLeases; loop++) { if (dhcpcLeaseList [loop] != NULL && dhcpcLeaseList [loop]->initFlag) { fileNum = dhcpcLeaseList [loop]->ifData.bpfDev; FD_SET (fileNum, &readFds); if (fileNum > maxFileNum) maxFileNum = fileNum; } } /* * No BPF devices will be active until a lease session starts * which uses an interface without an assigned IP address. */ maxFileNum++; /* Adjust maximum for select() routine. */ /* * Check for an incoming DHCP message. None may be available * if a new session started. */ result = select (maxFileNum, &readFds, NULL, NULL, NULL); if (result <= 0) continue; /* * Ignore the message if the current buffer is full. That * condition indicates an overflow of the message "ring". */ if (dhcpcMessageList [slot].writeFlag == FALSE) continue; dhcpcMessageList [slot].writeFlag = FALSE; pMsgData = dhcpcMessageList [slot].msgBuffer; if (!_dhcpcBootFlag) { /* * For runtime DHCP sessions, read and discard any DHCP * messages which reach the socket layer. An (empty) * DHCP message is sent to the loopback address when a * new session begins. This operation also removes * messages which were already handled by the Berkeley * Packet Filter, but also reach the socket layer if * any device is configured with an IP address. Creating * a socket to receive them prevents the transmission of * ICMP errors. */ dataFlag = FD_ISSET (dhcpcDataSock, &readFds); if (dataFlag) { read (dhcpcDataSock, pMsgData, dhcpcBufSize); dhcpcMessageList [slot].writeFlag = TRUE; continue; } } /* Read the first available DHCP message. */ for (loop = 0; loop < dhcpcMaxLeases; loop++) { if (dhcpcLeaseList [loop]->initFlag) { fileNum = dhcpcLeaseList [loop]->ifData.bpfDev; dataFlag = FD_ISSET (fileNum, &readFds); if (dataFlag) { /* * Any users must read an entire BPF buffer. The size * is set during the initialization for each lease. */ bufSize = dhcpcLeaseList [loop]->ifData.bufSize; break; } } } if (loop == dhcpcMaxLeases) { /* No DHCP sessions are using the BPF devices. */ continue; } /* * Ignore any read errors. The DHCP protocol is designed to handle * any problems with false arrival notifications or invalid messages. */ totlen = read (fileNum, pMsgData, bufSize); /* Signal lease monitor for each DHCP message in the BPF buffer. */ newEvent.source = DHCP_AUTO_EVENT; newEvent.type = DHCP_MSG_ARRIVED; newEvent.leaseId = dhcpcLeaseList [loop]; newEvent.slot = slot; msglen = curlen = 0; pMsgHdr = (struct bpf_hdr *)pMsgData; while (curlen < totlen) { msglen = BPF_WORDALIGN(pMsgHdr->bh_hdrlen + pMsgHdr->bh_caplen); curlen += msglen; /* Set the pointer to skip the BPF and link level headers. */ newEvent.pMsg = pMsgData + pMsgHdr->bh_hdrlen + pMsgHdr->bh_linklen; if (curlen < totlen) newEvent.lastFlag = FALSE; else newEvent.lastFlag = TRUE; /* Lock interrupts to prevent conflicts with timeout thread. */ key = intLock (); rngBufPut (dhcpcEventRing, (char *) &newEvent, sizeof(newEvent)); intUnlock (key); semGive (dhcpcEventSem); pMsgData = pMsgData + msglen; pMsgHdr = (struct bpf_hdr *)pMsgData; } /* Advance to next element in message ring. */ slot = (slot + 1) % maxSlot; } }/********************************************************************************* dhcpcOptionSet - add an option to the option request list** This routine specifies which options the lease indicated by the <pCookie>* parameter will request from a server. The <option> parameter specifies an * option tag as defined in RFC 2132. See the dhcp/dhcp.h include file for a* listing of defined aliases for the available option tags. This routine will* not accept the following <option> values, which are either used by the* server for control purposes or only supplied by the client:** _DHCP_PAD_TAG* _DHCP_REQUEST_IPADDR_TAG * _DHCP_LEASE_TIME_TAG * _DHCP_OPT_OVERLOAD_TAG* _DHCP_MSGTYPE_TAG* _DHCP_SERVER_ID_TAG* _DHCP_REQ_LIST_TAG * _DHCP_ERRMSG_TAG * _DHCP_MAXMSGSIZE_TAG* _DHCP_CLASS_ID_TAG * _DHCP_CLIENT_ID_TAG * _DHCP_END_TAG** This routine also will not accept <option> values 62 or 63, which are not* currently defined.** The maximum length of the option field in a DHCP message depends on the* MTU size of the associated interface and the maximum DHCP message size set* during the DHCP library initialization. Both the option request list and* the options sent by the client through the dhcpcOptionAdd() routine share* that field. Options which exceed the limit will not be stored.** NOTE: The boot program automatically requests all options necessary for* default target configuration. This routine is only necessary to support* special circumstances in which additional options are required. Any* options requested in that case may be retrieved after the runtime image* has started.* * NOTE: The DHCP specification forbids changing the option request list after* a lease has been established. Therefore, this routine must not be used* after the dhcpcBind() call (in a runtime image) or the dhcpcBootBind() call* (for a boot image). Changing the request list at that point could have* unpredictable results.** NOTE: Options are added directly to outgoing DHCP messages, and numeric* options (e.g. lease duration time) are expected to be provided in network* byte order. Care must be taken on little-endian hosts to insure that* numeric arguments are properly byte-swapped before being passed to this* routine.** RETURNS: OK if the option was set successfully, or ERROR if the option* is invalid or storage failed.** ERRNO: S_dhcpcLib_BAD_OPTION, S_dhcpcLib_OPTION_NOT_STORED**/STATUS dhcpcOptionSet ( void * pCookie, /* identifier returned by dhcpcInit() */ int option /* RFC 2132 tag of desired option */ ) { LEASE_DATA * pLeaseData; struct dhcp_reqspec * pReqSpec; struct dhcpcOpts * pOptList; int msglen = 0; /* Length of DHCP message after inserting option */ /* * Use the cookie to access the lease-specific data structures. For now, * just typecast the cookie. This translation could be replaced with a more * sophisticated lookup at some point. */ pLeaseData = (LEASE_DATA *)pCookie; pReqSpec = &pLeaseData->leaseReqSpec; /* Check for restricted or undefined options. */ switch (option) { case _DHCP_PAD_TAG: /* fall-through */ case _DHCP_REQUEST_IPADDR_TAG: /* fall-through */ case _DHCP_LEASE_TIME_TAG: /* fall-through */ case _DHCP_OPT_OVERLOAD_TAG: /* fall-through */ case _DHCP_MSGTYPE_TAG: /* fall-through */ case _DHCP_SERVER_ID_TAG: /* fall-through */ case _DHCP_REQ_LIST_TAG: /* fall-through */ case _DHCP_ERRMSG_TAG: /* fall-through */ case _DHCP_MAXMSGSIZE_TAG: /* fall-through */ case _DHCP_CLASS_ID_TAG: /* fall-through */ case _DHCP_CLIENT_ID_TAG: /* fall-through */ case _DHCP_END_TAG: errno = S_dhcpcLib_BAD_OPTION; return (ERROR); break; default: break; } if (option == 62 || option == 63) { errno = S_dhcpcLib_BAD_OPTION; return (ERROR); } if (option < 0 || option > _DHCP_LAST_OPTION) { errno = S_dhcpcLib_BAD_OPTION; return (ERROR); } /* * Verify that the option won't exceed the MTU size for a message. * Start with an initial length equal to the UDP and IP headers and * the fixed-length portion of a DHCP message. */ msglen = UDPHL + IPHL + (DFLTDHCPLEN - DFLTOPTLEN); /* Include size of existing options and option request list. */ pOptList = pReqSpec->pOptList; if (pOptList) msglen += pReqSpec->pOptList->optlen; msglen += (pReqSpec->reqlist.len + 1); /* * Include space for required magic cookie (4 bytes), message * type option (3 bytes), maximum message size (4 bytes), and * server identifier option (6 bytes). */ msglen += 17; /* Include space for required requested IP address option (6 bytes). */ msglen += 6;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -