DWORD DSLeaseIpAddress( PipeSendFunc Send, COMM_DHCP_REQ *Req ) { COMM_DHCP_REPLY Reply; PDHCP_ADAPTER Adapter; struct protocol* proto; ApiLock(); Adapter = AdapterFindIndex( Req->AdapterIndex ); Reply.Reply = Adapter ? 1 : 0; if( Adapter ) { proto = find_protocol_by_adapter( &Adapter->DhclientInfo ); if (proto) remove_protocol(proto); add_protocol( Adapter->DhclientInfo.name, Adapter->DhclientInfo.rfdesc, got_one, &Adapter->DhclientInfo ); Adapter->DhclientInfo.client->state = S_INIT; state_reboot(&Adapter->DhclientInfo); if (AdapterStateChangedEvent != NULL) SetEvent(AdapterStateChangedEvent); } ApiUnlock(); return Send( &Reply ); }
static void remove_all_protocols(void) { NetProtocol *n = (NetProtocol *)prot_list.lh_Head, *next; while ((next = (NetProtocol *)n->ln_Succ) != NULL) { remove_protocol(n); n = next; } }
void got_one(struct protocol *l) { struct sockaddr_in from; struct hardware hfrom; struct iaddr ifrom; ssize_t result; union { /* * Packet input buffer. Must be as large as largest * possible MTU. */ unsigned char packbuf[4095]; struct dhcp_packet packet; } u; struct interface_info *ip = l->local; if ((result = receive_packet(ip, u.packbuf, sizeof(u), &from, &hfrom)) == -1) { warning("receive_packet failed on %s: %s", ip->name, strerror(errno)); ip->errors++; if ((!interface_status(ip)) || (ip->noifmedia && ip->errors > 20)) { /* our interface has gone away. */ warning("Interface %s no longer appears valid.", ip->name); ip->dead = 1; interfaces_invalidated = 1; close(l->fd); remove_protocol(l); free(ip); } return; } if (result == 0) return; if (bootp_packet_handler) { ifrom.len = 4; memcpy(ifrom.iabuf, &from.sin_addr, ifrom.len); (*bootp_packet_handler)(ip, &u.packet, result, from.sin_port, ifrom, &hfrom); } }
DWORD DSStaticRefreshParams( PipeSendFunc Send, COMM_DHCP_REQ *Req ) { NTSTATUS Status; COMM_DHCP_REPLY Reply; PDHCP_ADAPTER Adapter; struct protocol* proto; ApiLock(); Adapter = AdapterFindIndex( Req->AdapterIndex ); Reply.Reply = Adapter ? 1 : 0; if( Adapter ) { if (Adapter->NteContext) { DeleteIPAddress( Adapter->NteContext ); Adapter->NteContext = 0; } if (Adapter->RouterMib.dwForwardNextHop) { DeleteIpForwardEntry( &Adapter->RouterMib ); Adapter->RouterMib.dwForwardNextHop = 0; } Adapter->DhclientState.state = S_STATIC; proto = find_protocol_by_adapter( &Adapter->DhclientInfo ); if (proto) remove_protocol(proto); Status = AddIPAddress( Req->Body.StaticRefreshParams.IPAddress, Req->Body.StaticRefreshParams.Netmask, Req->AdapterIndex, &Adapter->NteContext, &Adapter->NteInstance ); Reply.Reply = NT_SUCCESS(Status); if (AdapterStateChangedEvent != NULL) SetEvent(AdapterStateChangedEvent); } ApiUnlock(); return Send( &Reply ); }
DWORD DSReleaseIpAddressLease( PipeSendFunc Send, COMM_DHCP_REQ *Req ) { COMM_DHCP_REPLY Reply; PDHCP_ADAPTER Adapter; struct protocol* proto; ApiLock(); Adapter = AdapterFindIndex( Req->AdapterIndex ); Reply.Reply = Adapter ? 1 : 0; if( Adapter ) { if (Adapter->NteContext) { DeleteIPAddress( Adapter->NteContext ); Adapter->NteContext = 0; } if (Adapter->RouterMib.dwForwardNextHop) { DeleteIpForwardEntry( &Adapter->RouterMib ); Adapter->RouterMib.dwForwardNextHop = 0; } proto = find_protocol_by_adapter( &Adapter->DhclientInfo ); if (proto) remove_protocol(proto); Adapter->DhclientInfo.client->active = NULL; Adapter->DhclientInfo.client->state = S_INIT; if (AdapterStateChangedEvent != NULL) SetEvent(AdapterStateChangedEvent); } ApiUnlock(); return Send( &Reply ); }
/* * XXX Figure out the way to bind a specific adapter to a socket. */ DWORD WINAPI AdapterDiscoveryThread(LPVOID Context) { PMIB_IFTABLE Table = (PMIB_IFTABLE) malloc(sizeof(MIB_IFTABLE)); DWORD Error, Size = sizeof(MIB_IFTABLE); PDHCP_ADAPTER Adapter = NULL; HANDLE AdapterStateChangedEvent = (HANDLE)Context; struct interface_info *ifi = NULL; struct protocol *proto; int i, AdapterCount = 0, Broadcast; /* FIXME: Kill this thread when the service is stopped */ do { DH_DbgPrint(MID_TRACE,("Getting Adapter List...\n")); while( (Error = GetIfTable(Table, &Size, 0 )) == ERROR_INSUFFICIENT_BUFFER ) { DH_DbgPrint(MID_TRACE,("Error %d, New Buffer Size: %d\n", Error, Size)); free( Table ); Table = (PMIB_IFTABLE) malloc( Size ); } if( Error != NO_ERROR ) { /* HACK: We are waiting until TCP/IP starts */ Sleep(2000); continue; } DH_DbgPrint(MID_TRACE,("Got Adapter List (%d entries)\n", Table->dwNumEntries)); for( i = Table->dwNumEntries - 1; i >= 0; i-- ) { DH_DbgPrint(MID_TRACE,("Getting adapter %d attributes\n", Table->table[i].dwIndex)); ApiLock(); if ((Adapter = AdapterFindByHardwareAddress(Table->table[i].bPhysAddr, Table->table[i].dwPhysAddrLen))) { proto = find_protocol_by_adapter(&Adapter->DhclientInfo); /* This is an existing adapter */ if (InterfaceConnected(&Table->table[i])) { /* We're still active so we stay in the list */ ifi = &Adapter->DhclientInfo; /* This is a hack because IP helper API sucks */ if (IsReconnectHackNeeded(Adapter, &Table->table[i])) { /* This handles a disconnect/reconnect */ if (proto) remove_protocol(proto); Adapter->DhclientInfo.client->state = S_INIT; /* These are already invalid since the media state change */ Adapter->RouterMib.dwForwardNextHop = 0; Adapter->NteContext = 0; add_protocol(Adapter->DhclientInfo.name, Adapter->DhclientInfo.rfdesc, got_one, &Adapter->DhclientInfo); state_init(&Adapter->DhclientInfo); SetEvent(AdapterStateChangedEvent); } } else { if (proto) remove_protocol(proto); /* We've lost our link so out we go */ RemoveEntryList(&Adapter->ListEntry); free(Adapter); } ApiUnlock(); continue; } ApiUnlock(); Adapter = (DHCP_ADAPTER*) calloc( sizeof( DHCP_ADAPTER ) + Table->table[i].dwMtu, 1 ); if( Adapter && Table->table[i].dwType == MIB_IF_TYPE_ETHERNET && InterfaceConnected(&Table->table[i])) { memcpy( &Adapter->IfMib, &Table->table[i], sizeof(Adapter->IfMib) ); Adapter->DhclientInfo.client = &Adapter->DhclientState; Adapter->DhclientInfo.rbuf = Adapter->recv_buf; Adapter->DhclientInfo.rbuf_max = Table->table[i].dwMtu; Adapter->DhclientInfo.rbuf_len = Adapter->DhclientInfo.rbuf_offset = 0; memcpy(Adapter->DhclientInfo.hw_address.haddr, Adapter->IfMib.bPhysAddr, Adapter->IfMib.dwPhysAddrLen); Adapter->DhclientInfo.hw_address.hlen = Adapter->IfMib.dwPhysAddrLen; /* I'm not sure where else to set this, but some DHCP servers won't take a zero. We checked the hardware type earlier in the if statement. */ Adapter->DhclientInfo.hw_address.htype = HTYPE_ETHER; if( DhcpSocket == INVALID_SOCKET ) { DhcpSocket = Adapter->DhclientInfo.rfdesc = Adapter->DhclientInfo.wfdesc = socket( AF_INET, SOCK_DGRAM, IPPROTO_UDP ); if (DhcpSocket != INVALID_SOCKET) { /* Allow broadcast on this socket */ Broadcast = 1; setsockopt(DhcpSocket, SOL_SOCKET, SO_BROADCAST, (const char *)&Broadcast, sizeof(Broadcast)); Adapter->ListenAddr.sin_family = AF_INET; Adapter->ListenAddr.sin_port = htons(LOCAL_PORT); Adapter->BindStatus = (bind( Adapter->DhclientInfo.rfdesc, (struct sockaddr *)&Adapter->ListenAddr, sizeof(Adapter->ListenAddr) ) == 0) ? 0 : WSAGetLastError(); } else { error("socket() failed: %d\n", WSAGetLastError()); } } else { Adapter->DhclientInfo.rfdesc = Adapter->DhclientInfo.wfdesc = DhcpSocket; } Adapter->DhclientConfig.timeout = DHCP_PANIC_TIMEOUT; Adapter->DhclientConfig.initial_interval = DHCP_DISCOVER_INTERVAL; Adapter->DhclientConfig.retry_interval = DHCP_DISCOVER_INTERVAL; Adapter->DhclientConfig.select_interval = 1; Adapter->DhclientConfig.reboot_timeout = DHCP_REBOOT_TIMEOUT; Adapter->DhclientConfig.backoff_cutoff = DHCP_BACKOFF_MAX; Adapter->DhclientState.interval = Adapter->DhclientConfig.retry_interval; if( PrepareAdapterForService( Adapter ) ) { Adapter->DhclientInfo.next = ifi; ifi = &Adapter->DhclientInfo; read_client_conf(&Adapter->DhclientInfo); if (Adapter->DhclientInfo.client->state == S_INIT) { add_protocol(Adapter->DhclientInfo.name, Adapter->DhclientInfo.rfdesc, got_one, &Adapter->DhclientInfo); state_init(&Adapter->DhclientInfo); } ApiLock(); InsertTailList( &AdapterList, &Adapter->ListEntry ); AdapterCount++; SetEvent(AdapterStateChangedEvent); ApiUnlock(); } else { free( Adapter ); Adapter = 0; } } else { free( Adapter ); Adapter = 0; } if( !Adapter ) DH_DbgPrint(MID_TRACE,("Adapter %d was rejected\n", Table->table[i].dwIndex)); } #if 0 Error = NotifyAddrChange(NULL, NULL); if (Error != NO_ERROR) break; #else Sleep(3000); #endif } while (TRUE); DbgPrint("DHCPCSVC: Adapter discovery thread is terminating! (Error: %d)\n", Error); if( Table ) free( Table ); return Error; }
static __saveds void net_func(void) { const char *str; BYTE od_error; struct MsgPort *write_port = NULL, *control_port = NULL; struct IOSana2Req *write_io = NULL, *control_io = NULL; bool opened = false; ULONG read_mask = 0, write_mask = 0, proc_port_mask = 0; struct Sana2DeviceQuery query_data = {sizeof(Sana2DeviceQuery)}; ULONG buffer_tags[] = { S2_CopyToBuff, (uint32)copy_to_buff, S2_CopyFromBuff, (uint32)copy_from_buff, TAG_END }; // Default: error occured proc_error = true; // Create message port for communication with main task proc_port = CreateMsgPort(); if (proc_port == NULL) goto quit; proc_port_mask = 1 << proc_port->mp_SigBit; // Create message ports for device I/O read_port = CreateMsgPort(); if (read_port == NULL) goto quit; read_mask = 1 << read_port->mp_SigBit; write_port = CreateMsgPort(); if (write_port == NULL) goto quit; write_mask = 1 << write_port->mp_SigBit; control_port = CreateMsgPort(); if (control_port == NULL) goto quit; // Create control IORequest control_io = (struct IOSana2Req *)CreateIORequest(control_port, sizeof(struct IOSana2Req)); if (control_io == NULL) goto quit; control_io->ios2_Req.io_Message.mn_Node.ln_Type = 0; // Avoid CheckIO() bug // Parse device name char dev_name[256]; ULONG dev_unit; str = PrefsFindString("ether"); if (str) { const char *FirstSlash = strchr(str, '/'); const char *LastSlash = strrchr(str, '/'); if (FirstSlash && FirstSlash && FirstSlash != LastSlash) { // Device name contains path, i.e. "Networks/xyzzy.device" const char *lp = str; char *dp = dev_name; while (lp != LastSlash) *dp++ = *lp++; *dp = '\0'; if (strlen(dev_name) < 1) goto quit; if (sscanf(LastSlash, "/%ld", &dev_unit) != 1) goto quit; } else { if (sscanf(str, "%[^/]/%ld", dev_name, &dev_unit) != 2) goto quit; } } else goto quit; // Open device control_io->ios2_BufferManagement = buffer_tags; od_error = OpenDevice((UBYTE *) dev_name, dev_unit, (struct IORequest *)control_io, 0); if (od_error != 0 || control_io->ios2_Req.io_Device == 0) { printf("WARNING: OpenDevice(<%s>, unit=%d) returned error %d)\n", (UBYTE *)dev_name, dev_unit, od_error); goto quit; } opened = true; // Is it Ethernet? control_io->ios2_Req.io_Command = S2_DEVICEQUERY; control_io->ios2_StatData = (void *)&query_data; DoIO((struct IORequest *)control_io); if (control_io->ios2_Req.io_Error) goto quit; if (query_data.HardwareType != S2WireType_Ethernet) { WarningAlert(GetString(STR_NOT_ETHERNET_WARN)); goto quit; } // Yes, create IORequest for writing write_io = (struct IOSana2Req *)CreateIORequest(write_port, sizeof(struct IOSana2Req)); if (write_io == NULL) goto quit; memcpy(write_io, control_io, sizeof(struct IOSana2Req)); write_io->ios2_Req.io_Message.mn_Node.ln_Type = 0; // Avoid CheckIO() bug write_io->ios2_Req.io_Message.mn_ReplyPort = write_port; // Configure Ethernet control_io->ios2_Req.io_Command = S2_GETSTATIONADDRESS; DoIO((struct IORequest *)control_io); memcpy(ether_addr, control_io->ios2_DstAddr, 6); memcpy(control_io->ios2_SrcAddr, control_io->ios2_DstAddr, 6); control_io->ios2_Req.io_Command = S2_CONFIGINTERFACE; DoIO((struct IORequest *)control_io); D(bug("Ethernet address %08lx %08lx\n", *(uint32 *)ether_addr, *(uint16 *)(ether_addr + 4))); // Initialization went well, inform main task proc_error = false; Signal(MainTask, SIGF_SINGLE); // Main loop for (;;) { // Wait for I/O and messages (CTRL_C is used for quitting the task) ULONG sig = Wait(proc_port_mask | read_mask | write_mask | SIGBREAKF_CTRL_C); // Main task wants to quit us if (sig & SIGBREAKF_CTRL_C) break; // Main task sent a command to us if (sig & proc_port_mask) { struct NetMessage *msg; while (msg = (NetMessage *)GetMsg(proc_port)) { D(bug("net_proc received %08lx\n", msg->what)); switch (msg->what) { case MSG_CLEANUP: remove_all_protocols(); break; case MSG_ADD_MULTI: control_io->ios2_Req.io_Command = S2_ADDMULTICASTADDRESS; Mac2Host_memcpy(control_io->ios2_SrcAddr, msg->pointer + eMultiAddr, 6); DoIO((struct IORequest *)control_io); if (control_io->ios2_Req.io_Error == S2ERR_NOT_SUPPORTED) { WarningAlert(GetString(STR_NO_MULTICAST_WARN)); msg->result = noErr; } else if (control_io->ios2_Req.io_Error) msg->result = eMultiErr; else msg->result = noErr; break; case MSG_DEL_MULTI: control_io->ios2_Req.io_Command = S2_DELMULTICASTADDRESS; Mac2Host_memcpy(control_io->ios2_SrcAddr, msg->pointer + eMultiAddr, 6); DoIO((struct IORequest *)control_io); if (control_io->ios2_Req.io_Error) msg->result = eMultiErr; else msg->result = noErr; break; case MSG_ATTACH_PH: { uint16 type = msg->type; uint32 handler = msg->pointer; // Protocol of that type already installed? NetProtocol *p = (NetProtocol *)prot_list.lh_Head, *next; while ((next = (NetProtocol *)p->ln_Succ) != NULL) { if (p->type == type) { msg->result = lapProtErr; goto reply; } p = next; } // Allocate NetProtocol, set type and handler p = (NetProtocol *)AllocMem(sizeof(NetProtocol), MEMF_PUBLIC); if (p == NULL) { msg->result = lapProtErr; goto reply; } p->type = type; p->handler = handler; // Set up and submit read requests for (int i=0; i<NUM_READ_REQUESTS; i++) { memcpy(p->read_io + i, control_io, sizeof(struct IOSana2Req)); p->read_io[i].ios2_Req.io_Message.mn_Node.ln_Name = (char *)p; // Hide pointer to NetProtocol in node name p->read_io[i].ios2_Req.io_Message.mn_Node.ln_Type = 0; // Avoid CheckIO() bug p->read_io[i].ios2_Req.io_Message.mn_ReplyPort = read_port; p->read_io[i].ios2_Req.io_Command = CMD_READ; p->read_io[i].ios2_PacketType = type; p->read_io[i].ios2_Data = p->read_buf[i]; p->read_io[i].ios2_Req.io_Flags = SANA2IOF_RAW; BeginIO((struct IORequest *)(p->read_io + i)); } // Add protocol to list AddTail(&prot_list, p); // Everything OK msg->result = noErr; break; } case MSG_DETACH_PH: { uint16 type = msg->type; msg->result = lapProtErr; NetProtocol *p = (NetProtocol *)prot_list.lh_Head, *next; while ((next = (NetProtocol *)p->ln_Succ) != NULL) { if (p->type == type) { remove_protocol(p); msg->result = noErr; break; } p = next; } break; } case MSG_WRITE: { // Get pointer to Write Data Structure uint32 wds = msg->pointer; write_io->ios2_Data = (void *)wds; // Calculate total packet length long len = 0; uint32 tmp = wds; for (;;) { int16 w = ReadMacInt16(tmp); if (w == 0) break; len += w; tmp += 6; } write_io->ios2_DataLength = len; // Get destination address uint32 hdr = ReadMacInt32(wds + 2); Mac2Host_memcpy(write_io->ios2_DstAddr, hdr, 6); // Get packet type uint32 type = ReadMacInt16(hdr + 12); if (type <= 1500) type = 0; // 802.3 packet write_io->ios2_PacketType = type; // Multicast/broadcard packet? if (write_io->ios2_DstAddr[0] & 1) { if (*(uint32 *)(write_io->ios2_DstAddr) == 0xffffffff && *(uint16 *)(write_io->ios2_DstAddr + 4) == 0xffff) write_io->ios2_Req.io_Command = S2_BROADCAST; else write_io->ios2_Req.io_Command = S2_MULTICAST; } else write_io->ios2_Req.io_Command = CMD_WRITE; // Send packet write_done = false; write_io->ios2_Req.io_Flags = SANA2IOF_RAW; BeginIO((IORequest *)write_io); break; } } reply: D(bug(" net_proc replying\n")); ReplyMsg(msg); } } // Packet received if (sig & read_mask) { D(bug(" packet received, triggering Ethernet interrupt\n")); SetInterruptFlag(INTFLAG_ETHER); TriggerInterrupt(); } // Packet write completed if (sig & write_mask) { GetMsg(write_port); WriteMacInt32(ether_data + ed_Result, write_io->ios2_Req.io_Error ? excessCollsns : 0); write_done = true; D(bug(" packet write done, triggering Ethernet interrupt\n")); SetInterruptFlag(INTFLAG_ETHER); TriggerInterrupt(); } } quit: // Close everything remove_all_protocols(); if (opened) { if (CheckIO((struct IORequest *)write_io) == 0) { AbortIO((struct IORequest *)write_io); WaitIO((struct IORequest *)write_io); } CloseDevice((struct IORequest *)control_io); } if (write_io) DeleteIORequest(write_io); if (control_io) DeleteIORequest(control_io); if (control_port) DeleteMsgPort(control_port); if (write_port) DeleteMsgPort(write_port); if (read_port) DeleteMsgPort(read_port); // Send signal to main task to confirm termination Forbid(); Signal(MainTask, SIGF_SINGLE); }