tPAddr *gTmpCR3 = (void*)TMP_CR3_ADDR;
int gilTempMappings = 0;
int gilTempFractal = 0;
-Uint32 gWorkerStacks[NUM_WORKER_STACKS/32];
+Uint32 gWorkerStacks[(NUM_WORKER_STACKS+31)/32];
int giLastUsedWorker = 0;
// === CODE ===
if( gWorkerStacks[base/32] & (1 << base) ) {
continue;
}
+ break;
}
if(base >= NUM_WORKER_STACKS) {
Warning("Uh-oh! Out of worker stacks");
//! \todo Move 0xBC000000 to mm_virt.h\r
#define BIN_HIGHEST (0xBC000000-BIN_GRANUALITY) // Just below the kernel\r
#define KLIB_LOWEST MM_MODULE_MIN\r
-#define KLIB_GRANUALITY 0x8000 // 32KiB\r
+#define KLIB_GRANUALITY 0x10000 // 32KiB\r
#define KLIB_HIGHEST (MM_MODULE_MAX-KLIB_GRANUALITY)\r
\r
// === TYPES ===\r
#define MAX_INPUT_CHARS32 64
#define MAX_INPUT_CHARS8 (MAX_INPUT_CHARS32*4)
#define VT_SCROLLBACK 1 // 2 Screens of text
-//#define DEFAULT_OUTPUT "VGA"
-#define DEFAULT_OUTPUT "BochsGA"
+#define DEFAULT_OUTPUT "VGA"
+//#define DEFAULT_OUTPUT "BochsGA"
#define DEFAULT_INPUT "PS2Keyboard"
#define DEFAULT_WIDTH 80
#define DEFAULT_HEIGHT 25
# define ENTER(_types...) Debug_Enter((char*)__func__, _types)
# define LOG(_fmt...) Debug_Log((char*)__func__, _fmt)
# define LEAVE(_t...) Debug_Leave((char*)__func__, _t)
+# define LEAVE_RET(_t,_v...) do{LEAVE(_t,_v);return _v;}while(0)
+//# define LEAVE_RET(_t) do{LEAVE(_t);return;}
#else
# define ENTER(...)
# define LOG(...)
# define LEAVE(...)
+# define LEAVE_RET(_t,_v...) return (_v)
#endif
/**
* \}
.PHONY: all clean
-MODULES = IPStack
+MODULES = FS_Ext2 FDD BochsGA IPStack NE2000
USRLIBS = ld-acess.so libacess.so libgcc.so libc.so
-USRAPPS = init login CLIShell cat ls mount
+USRAPPS = init login CLIShell cat ls mount ifconfig
all:
@for mod in $(MODULES); do \
- (echo === $$mod && $(MAKE) all --no-print-directory -C Modules/$$mod) \
+ (echo === Module: $$mod && $(MAKE) all --no-print-directory -C Modules/$$mod) \
done
@echo === Kernel
@$(MAKE) all --no-print-directory -C Kernel
@for lib in $(USRLIBS); do \
- (echo === $$lib && $(MAKE) all --no-print-directory -C Usermode/Libraries/`echo $$lib`_src) \
+ (echo === User Library: $$lib && $(MAKE) all --no-print-directory -C Usermode/Libraries/`echo $$lib`_src) \
done
@for app in $(USRAPPS); do \
- (echo === $$app && $(MAKE) all --no-print-directory -C Usermode/Applications/`echo $$app`_src) \
+ (echo === User Application: $$app && $(MAKE) all --no-print-directory -C Usermode/Applications/`echo $$app`_src) \
done
# @echo === ld-acess.so
# @$(MAKE) all --no-print-directory -C Usermode/Applications/mount_src
clean:
+ @for mod in $(MODULES); do \
+ ($(MAKE) clean --no-print-directory -C Modules/$$mod) \
+ done
+
@make clean --no-print-directory -C Kernel/
@for lib in $(USRLIBS); do \
--- /dev/null
+#
+#
+
+OBJ = bochsvbe.o
+NAME = BochsGA
+
+-include ../Makefile.tpl
--- /dev/null
+/**\r
+ * \file drv_bochsvbe.c\r
+ * \brief BGA (Bochs Graphic Adapter) Driver\r
+ * \note for Acess2\r
+ * \warning This driver does NOT support the Bochs PCI VGA driver\r
+*/\r
+#define DEBUG 0\r
+#include <common.h>\r
+#include <errno.h>\r
+#include <modules.h>\r
+#include <vfs.h>\r
+#include <fs_devfs.h>\r
+#include <drv_pci.h>\r
+#include <tpl_drv_video.h>\r
+\r
+//#define INT static\r
+#define INT\r
+\r
+// === TYPEDEFS ===\r
+typedef struct {\r
+ Uint16 width;\r
+ Uint16 height;\r
+ Uint16 bpp;\r
+ Uint16 flags;\r
+ Uint32 fbSize;\r
+} t_bga_mode;\r
+\r
+// === CONSTANTS ===\r
+enum eMode_Flags {\r
+ MODEFLAG_TEXT = 1\r
+};\r
+#define BGA_LFB_MAXSIZE (1024*768*4)\r
+#define VBE_DISPI_BANK_ADDRESS 0xA0000\r
+#define VBE_DISPI_LFB_PHYSICAL_ADDRESS 0xE0000000\r
+#define VBE_DISPI_IOPORT_INDEX 0x01CE\r
+#define VBE_DISPI_IOPORT_DATA 0x01CF\r
+#define VBE_DISPI_DISABLED 0x00\r
+#define VBE_DISPI_ENABLED 0x01\r
+#define VBE_DISPI_LFB_ENABLED 0x40\r
+#define VBE_DISPI_NOCLEARMEM 0x80\r
+enum {\r
+ VBE_DISPI_INDEX_ID,\r
+ VBE_DISPI_INDEX_XRES,\r
+ VBE_DISPI_INDEX_YRES,\r
+ VBE_DISPI_INDEX_BPP,\r
+ VBE_DISPI_INDEX_ENABLE,\r
+ VBE_DISPI_INDEX_BANK,\r
+ VBE_DISPI_INDEX_VIRT_WIDTH,\r
+ VBE_DISPI_INDEX_VIRT_HEIGHT,\r
+ VBE_DISPI_INDEX_X_OFFSET,\r
+ VBE_DISPI_INDEX_Y_OFFSET\r
+};\r
+\r
+\r
+// === PROTOTYPES ===\r
+// Driver\r
+ int BGA_Install(char **Arguments);\r
+void BGA_Uninstall();\r
+// Internal\r
+void BGA_int_WriteRegister(Uint16 reg, Uint16 value);\r
+Uint16 BGA_int_ReadRegister(Uint16 reg);\r
+void BGA_int_SetBank(Uint16 bank);\r
+void BGA_int_SetMode(Uint16 width, Uint16 height);\r
+ int BGA_int_UpdateMode(int id);\r
+ int BGA_int_FindMode(tVideo_IOCtl_Mode *info);\r
+ int BGA_int_ModeInfo(tVideo_IOCtl_Mode *info);\r
+ int BGA_int_MapFB(void *Dest);\r
+// Filesystem\r
+Uint64 BGA_Read(tVFS_Node *node, Uint64 off, Uint64 len, void *buffer);\r
+Uint64 BGA_Write(tVFS_Node *node, Uint64 off, Uint64 len, void *buffer);\r
+ int BGA_Ioctl(tVFS_Node *node, int id, void *data);\r
+\r
+// === GLOBALS ===\r
+MODULE_DEFINE(0, 0x0032, BochsGA, BGA_Install, NULL, NULL);\r
+tDevFS_Driver gBGA_DriverStruct = {\r
+ NULL, "BochsGA",\r
+ {\r
+ .Read = BGA_Read,\r
+ .Write = BGA_Write,\r
+ .IOCtl = BGA_Ioctl\r
+ }\r
+};\r
+ int giBGA_CurrentMode = -1;\r
+tVideo_IOCtl_Pos gBGA_CursorPos = {-1,-1};\r
+ int giBGA_DriverId = -1;\r
+Uint *gBGA_Framebuffer;\r
+t_bga_mode gBGA_Modes[] = {\r
+ {},\r
+ { 80,25, 12, MODEFLAG_TEXT, 80*25*8}, // 640 x 480\r
+ {100,37, 12, MODEFLAG_TEXT, 100*37*8}, // 800 x 600\r
+ {640,480,8, 0, 640*480},\r
+ {640,480,32, 0, 640*480*4},\r
+ {800,600,8, 0, 800*600},\r
+ {800,600,32, 0, 800*600*4},\r
+};\r
+#define BGA_MODE_COUNT (sizeof(gBGA_Modes)/sizeof(gBGA_Modes[0]))\r
+\r
+// === CODE ===\r
+/**\r
+ * \fn int BGA_Install(char **Arguments)\r
+ */\r
+int BGA_Install(char **Arguments)\r
+{\r
+ int bga_version = 0;\r
+ \r
+ // Check BGA Version\r
+ bga_version = BGA_int_ReadRegister(VBE_DISPI_INDEX_ID);\r
+ // NOTE: This driver was written for 0xB0C4, but they seem to be backwards compatable\r
+ if(bga_version < 0xB0C4 || bga_version > 0xB0C5) {\r
+ Warning("[BGA ] Bochs Adapter Version is not 0xB0C4 or 0xB0C5, instead 0x%x", bga_version);\r
+ return 0;\r
+ }\r
+ \r
+ // Install Device\r
+ giBGA_DriverId = DevFS_AddDevice( &gBGA_DriverStruct );\r
+ if(giBGA_DriverId == -1) {\r
+ Warning("[BGA ] Unable to register with DevFS, maybe already loaded?");\r
+ return 0;\r
+ }\r
+ \r
+ // Map Framebuffer to hardware address\r
+ gBGA_Framebuffer = (void *) MM_MapHWPage(VBE_DISPI_LFB_PHYSICAL_ADDRESS, 768); // 768 pages (3Mb)\r
+ \r
+ return 1;\r
+}\r
+\r
+/**\r
+ * \fn void BGA_Uninstall()\r
+ */\r
+void BGA_Uninstall()\r
+{\r
+ //DevFS_DelDevice( giBGA_DriverId );\r
+ MM_UnmapHWPage( VBE_DISPI_LFB_PHYSICAL_ADDRESS, 768 );\r
+}\r
+\r
+/**\r
+ * \fn Uint64 BGA_Read(tVFS_Node *node, Uint64 off, Uint64 len, void *buffer)\r
+ * \brief Read from the framebuffer\r
+ */\r
+Uint64 BGA_Read(tVFS_Node *node, Uint64 off, Uint64 len, void *buffer)\r
+{\r
+ // Check Mode\r
+ if(giBGA_CurrentMode == -1) return -1;\r
+ \r
+ // Check Offset and Length against Framebuffer Size\r
+ if(off+len > gBGA_Modes[giBGA_CurrentMode].fbSize)\r
+ return -1;\r
+ \r
+ // Copy from Framebuffer\r
+ memcpy(buffer, (void*)((Uint)gBGA_Framebuffer + (Uint)off), len);\r
+ return len;\r
+}\r
+\r
+/**\r
+ * \fn Uint64 BGA_Write(tVFS_Node *node, Uint64 off, Uint64 len, void *buffer)\r
+ * \brief Write to the framebuffer\r
+ */\r
+Uint64 BGA_Write(tVFS_Node *node, Uint64 off, Uint64 len, void *buffer)\r
+{ \r
+ ENTER("xoff xlen", off, len);\r
+ \r
+ // Check Mode\r
+ if(giBGA_CurrentMode == -1) {\r
+ LEAVE('i', -1);\r
+ return -1;\r
+ }\r
+ \r
+ // Check Input against Frambuffer Size\r
+ if(off+len > gBGA_Modes[giBGA_CurrentMode].fbSize) {\r
+ LEAVE('i', -1);\r
+ return -1;\r
+ }\r
+ \r
+ // Text Mode\r
+ if( gBGA_Modes[giBGA_CurrentMode].flags & MODEFLAG_TEXT )\r
+ {\r
+ tVT_Char *chars = buffer;\r
+ int pitch = gBGA_Modes[giBGA_CurrentMode].width * giVT_CharWidth;\r
+ int x, y;\r
+ Uint32 *dest;\r
+ \r
+ off /= sizeof(tVT_Char);\r
+ dest = (void*)gBGA_Framebuffer;\r
+ x = (off % gBGA_Modes[giBGA_CurrentMode].width) * giVT_CharWidth;\r
+ y = (off / gBGA_Modes[giBGA_CurrentMode].width) * giVT_CharHeight;\r
+ dest += y * pitch;\r
+ dest += x * giVT_CharWidth;\r
+ len /= sizeof(tVT_Char);\r
+ while(len--)\r
+ {\r
+ VT_Font_Render(\r
+ chars->Ch,\r
+ dest, pitch,\r
+ VT_Colour12to24(chars->BGCol),\r
+ VT_Colour12to24(chars->FGCol)\r
+ );\r
+ \r
+ dest += giVT_CharWidth;\r
+ \r
+ chars ++;\r
+ x += giVT_CharWidth;\r
+ if( x >= pitch ) {\r
+ x = 0;\r
+ y += giVT_CharHeight;\r
+ dest += pitch*(giVT_CharHeight-1);\r
+ }\r
+ }\r
+ }\r
+ else\r
+ {\r
+ Uint8 *destBuf = (Uint8*) ((Uint)gBGA_Framebuffer + (Uint)off);\r
+ \r
+ LOG("buffer = %p\n", buffer);\r
+ LOG("Updating Framebuffer (%p to %p)\n", \r
+ destBuf, destBuf + (Uint)len);\r
+ \r
+ \r
+ // Copy to Frambuffer\r
+ memcpy(destBuf, buffer, len);\r
+ \r
+ LOG("BGA Framebuffer updated\n");\r
+ }\r
+ \r
+ LEAVE('i', len);\r
+ return len;\r
+}\r
+\r
+/**\r
+ * \fn INT int BGA_Ioctl(tVFS_Node *node, int ID, void *Data)\r
+ * \brief Handle messages to the device\r
+ */\r
+INT int BGA_Ioctl(tVFS_Node *node, int ID, void *Data)\r
+{\r
+ int ret = -2;\r
+ ENTER("pNode iId pData", node, ID, Data);\r
+ \r
+ switch(ID)\r
+ {\r
+ case DRV_IOCTL_TYPE:\r
+ ret = DRV_TYPE_VIDEO;\r
+ break;\r
+ case DRV_IOCTL_IDENT:\r
+ memcpy(Data, "BGA1", 4);\r
+ ret = 1;\r
+ break;\r
+ case DRV_IOCTL_VERSION:\r
+ ret = 0x100;\r
+ break;\r
+ case DRV_IOCTL_LOOKUP: // TODO: Implement\r
+ ret = 0;\r
+ break;\r
+ \r
+ case VIDEO_IOCTL_SETMODE:\r
+ ret = BGA_int_UpdateMode(*(int*)(Data));\r
+ break;\r
+ \r
+ case VIDEO_IOCTL_GETMODE:\r
+ ret = giBGA_CurrentMode;\r
+ break;\r
+ \r
+ case VIDEO_IOCTL_FINDMODE:\r
+ ret = BGA_int_FindMode((tVideo_IOCtl_Mode*)Data);\r
+ break;\r
+ \r
+ case VIDEO_IOCTL_MODEINFO:\r
+ ret = BGA_int_ModeInfo((tVideo_IOCtl_Mode*)Data);\r
+ break;\r
+ \r
+ // Request Access to LFB\r
+ case VIDEO_IOCTL_REQLFB:\r
+ ret = BGA_int_MapFB( *(void**)Data );\r
+ break;\r
+ \r
+ case VIDEO_IOCTL_SETCURSOR:\r
+ gBGA_CursorPos.x = ((tVideo_IOCtl_Pos*)Data)->x;\r
+ gBGA_CursorPos.y = ((tVideo_IOCtl_Pos*)Data)->y;\r
+ break;\r
+ \r
+ default:\r
+ LEAVE('i', -2);\r
+ return -2;\r
+ }\r
+ \r
+ LEAVE('i', ret);\r
+ return ret;\r
+}\r
+\r
+//== Internal Functions ==\r
+/**\r
+ * \fn void BGA_int_WriteRegister(Uint16 reg, Uint16 value)\r
+ * \brief Writes to a BGA register\r
+ */\r
+void BGA_int_WriteRegister(Uint16 reg, Uint16 value)\r
+{\r
+ outw(VBE_DISPI_IOPORT_INDEX, reg);\r
+ outw(VBE_DISPI_IOPORT_DATA, value);\r
+}\r
+\r
+INT Uint16 BGA_int_ReadRegister(Uint16 reg)\r
+{\r
+ outw(VBE_DISPI_IOPORT_INDEX, reg);\r
+ return inw(VBE_DISPI_IOPORT_DATA);\r
+}\r
+\r
+#if 0\r
+INT void BGA_int_SetBank(Uint16 bank)\r
+{\r
+ BGA_int_WriteRegister(VBE_DISPI_INDEX_BANK, bank);\r
+}\r
+#endif\r
+\r
+/**\r
+ * \fn void BGA_int_SetMode(Uint16 width, Uint16 height, Uint16 bpp)\r
+ * \brief Sets the video mode from the dimensions and bpp given\r
+ */\r
+void BGA_int_SetMode(Uint16 width, Uint16 height)\r
+{\r
+ ENTER("iwidth iheight ibpp", width, height, bpp);\r
+ BGA_int_WriteRegister(VBE_DISPI_INDEX_ENABLE, VBE_DISPI_DISABLED);\r
+ BGA_int_WriteRegister(VBE_DISPI_INDEX_XRES, width);\r
+ BGA_int_WriteRegister(VBE_DISPI_INDEX_YRES, height);\r
+ BGA_int_WriteRegister(VBE_DISPI_INDEX_BPP, 32);\r
+ BGA_int_WriteRegister(VBE_DISPI_INDEX_ENABLE, VBE_DISPI_ENABLED | VBE_DISPI_NOCLEARMEM | VBE_DISPI_LFB_ENABLED);\r
+ //BGA_int_WriteRegister(VBE_DISPI_INDEX_ENABLE, VBE_DISPI_ENABLED | VBE_DISPI_NOCLEARMEM);\r
+ LEAVE('-');\r
+}\r
+\r
+/**\r
+ * \fn int BGA_int_UpdateMode(int id)\r
+ * \brief Set current vide mode given a mode id\r
+ */\r
+int BGA_int_UpdateMode(int id)\r
+{\r
+ // Sanity Check\r
+ if(id < 0 || id >= BGA_MODE_COUNT) return -1;\r
+ \r
+ // Check if it is a text mode\r
+ if( gBGA_Modes[id].flags & MODEFLAG_TEXT )\r
+ BGA_int_SetMode(\r
+ gBGA_Modes[id].width*giVT_CharWidth,\r
+ gBGA_Modes[id].height*giVT_CharHeight);\r
+ else // Graphics?\r
+ BGA_int_SetMode(\r
+ gBGA_Modes[id].width,\r
+ gBGA_Modes[id].height);\r
+ \r
+ giBGA_CurrentMode = id;\r
+ return id;\r
+}\r
+\r
+/**\r
+ * \fn int BGA_int_FindMode(tVideo_IOCtl_Mode *info)\r
+ * \brief Find a mode matching the given options\r
+ */\r
+int BGA_int_FindMode(tVideo_IOCtl_Mode *info)\r
+{\r
+ int i;\r
+ int best = 0, bestFactor = 1000;\r
+ int factor, tmp;\r
+ int rqdProduct = info->width * info->height * info->bpp;\r
+ \r
+ ENTER("pinfo", info);\r
+ LOG("info = {width:%i,height:%i,bpp:%i})\n", info->width, info->height, info->bpp);\r
+ \r
+ for(i = 0; i < BGA_MODE_COUNT; i++)\r
+ {\r
+ #if DEBUG >= 2\r
+ LogF("Mode %i (%ix%ix%i), ", i, gBGA_Modes[i].width, gBGA_Modes[i].height, gBGA_Modes[i].bpp);\r
+ #endif\r
+ \r
+ // Check if this mode is the same type as what we want\r
+ if( !(gBGA_Modes[i].flags & MODEFLAG_TEXT) != !(info->flags & VIDEO_FLAG_TEXT) )\r
+ continue;\r
+ \r
+ // Ooh! A perfect match\r
+ if(gBGA_Modes[i].width == info->width\r
+ && gBGA_Modes[i].height == info->height\r
+ && gBGA_Modes[i].bpp == info->bpp)\r
+ {\r
+ #if DEBUG >= 2\r
+ LogF("Perfect!\n");\r
+ #endif\r
+ best = i;\r
+ break;\r
+ }\r
+ \r
+ // If not, how close are we?\r
+ tmp = gBGA_Modes[i].width * gBGA_Modes[i].height * gBGA_Modes[i].bpp;\r
+ tmp -= rqdProduct;\r
+ tmp = tmp < 0 ? -tmp : tmp; // tmp = ABS(tmp)\r
+ factor = tmp * 100 / rqdProduct;\r
+ \r
+ #if DEBUG >= 2\r
+ LogF("factor = %i\n", factor);\r
+ #endif\r
+ \r
+ if(factor < bestFactor)\r
+ {\r
+ bestFactor = factor;\r
+ best = i;\r
+ }\r
+ }\r
+ \r
+ info->id = best;\r
+ info->width = gBGA_Modes[best].width;\r
+ info->height = gBGA_Modes[best].height;\r
+ info->bpp = gBGA_Modes[best].bpp;\r
+ \r
+ info->flags = 0;\r
+ if(gBGA_Modes[best].flags & MODEFLAG_TEXT)\r
+ info->flags |= VIDEO_FLAG_TEXT;\r
+ \r
+ return best;\r
+}\r
+\r
+/**\r
+ * \fn int BGA_int_ModeInfo(tVideo_IOCtl_Mode *info)\r
+ * \brief Get mode information\r
+ */\r
+int BGA_int_ModeInfo(tVideo_IOCtl_Mode *info)\r
+{\r
+ // Sanity Check\r
+ //if( !MM_IsUser( (Uint)info, sizeof(tVideo_IOCtl_Mode) ) ) {\r
+ // return -EINVAL;\r
+ //}\r
+ \r
+ if(info->id < 0 || info->id >= BGA_MODE_COUNT) return -1;\r
+ \r
+ info->width = gBGA_Modes[info->id].width;\r
+ info->height = gBGA_Modes[info->id].height;\r
+ info->bpp = gBGA_Modes[info->id].bpp;\r
+ \r
+ info->flags = 0;\r
+ if(gBGA_Modes[info->id].flags & MODEFLAG_TEXT)\r
+ info->flags |= VIDEO_FLAG_TEXT;\r
+ \r
+ return 1;\r
+}\r
+\r
+/**\r
+ * \fn int BGA_int_MapFB(void *Dest)\r
+ * \brief Map the framebuffer into a process's space\r
+ * \param Dest User address to load to\r
+ */\r
+int BGA_int_MapFB(void *Dest)\r
+{\r
+ Uint i;\r
+ Uint pages;\r
+ \r
+ // Sanity Check\r
+ if((Uint)Dest > 0xC0000000) return 0;\r
+ if(gBGA_Modes[giBGA_CurrentMode].bpp < 15) return 0; // Only non-pallete modes are supported\r
+ \r
+ // Count required pages\r
+ pages = (gBGA_Modes[giBGA_CurrentMode].fbSize + 0xFFF) >> 12;\r
+ \r
+ // Check if there is space\r
+ for( i = 0; i < pages; i++ )\r
+ {\r
+ if(MM_GetPhysAddr( (Uint)Dest + (i << 12) ))\r
+ return 0;\r
+ }\r
+ \r
+ // Map\r
+ for( i = 0; i < pages; i++ )\r
+ MM_Map( (Uint)Dest + (i<<12), VBE_DISPI_LFB_PHYSICAL_ADDRESS + (i<<12) );\r
+ \r
+ return 1;\r
+}\r
extern void Link_RegisterType(Uint16 Type, tPacketCallback Callback);
extern void Link_SendPacket(tAdapter *Interface, Uint16 Type, tMacAddr To, int Length, void *Buffer);
+extern void Link_WatchDevice(tAdapter *Adapter);
// === INTERNAL ===
typedef struct sEthernetHeader tEthernetHeader;
#define DEBUG 0
#define VERSION ((0<<8)|10)
#include "ipstack.h"
+#include "link.h"
#include <modules.h>
#include <fs_devfs.h>
#include <tpl_drv_common.h>
.ACLs = &gVFS_ACL_EveryoneRX,
.Flags = VFS_FFLAG_DIRECTORY,
.ReadDir = IPStack_ReadDir,
- .FindDir = IPStack_FindDir
+ .FindDir = IPStack_FindDir,
+ .IOCtl = IPStack_IOCtl
}
};
int glIP_Interfaces = 0;
tInterface *gIP_Interfaces = NULL;
tInterface *gIP_Interfaces_Last = NULL;
+ int giIP_NextIfaceId = 1;
int glIP_Adapters = 0;
tAdapter *gIP_Adapters = NULL;
}
}
+ DevFS_AddDevice( &gIP_DriverInfo );
+
return 1;
}
char *IPStack_ReadDir(tVFS_Node *Node, int Pos)
{
tInterface *iface;
- char name[5] = "ip0\0\0";
+ char name[] = "ip0\0\0\0";
+ ENTER("pNode iPos", Node, Pos);
+
+ // Traverse the list
+ for( iface = gIP_Interfaces; iface && Pos--; iface = iface->Next ) ;
+
+ // Did we run off the end?
+ if(!iface) {
+ LEAVE('n');
+ return NULL;
+ }
// Create the name
+ Pos = iface->Node.ImplInt;
if(Pos < 10)
name[2] = '0' + Pos;
- else {
+ else if(Pos < 100) {
name[2] = '0' + Pos/10;
name[3] = '0' + Pos%10;
}
+ else {
+ name[2] = '0' + Pos/100;
+ name[3] = '0' + (Pos/10)%10;
+ name[4] = '0' + Pos%10;
+ }
- // Traverse the list
- for( iface = gIP_Interfaces; iface && Pos--; iface = iface->Next ) ;
-
- // Did we run off the end?
- if(!iface) return NULL;
-
+ LEAVE('s', name);
// Return the pre-generated name
return strdup(name);
}
*/
tVFS_Node *IPStack_FindDir(tVFS_Node *Node, char *Name)
{
- int i;
- tInterface *iface;
+ int i, num;
+ tInterface *iface;
- if(Name[0] != 'i' || Name[1] != 'p') return NULL;
- if(Name[2] < '0' || Name[2] > '9') return NULL;
+ ENTER("pNode sName", Node, Name);
- if(Name[3] == '\0') {
- i = Name[2] - '0';
- for( iface = gIP_Interfaces; iface && i--; iface = iface->Next ) ;
- if(!iface) return NULL;
- return &iface->Node;
+ if(Name[0] != 'i' || Name[1] != 'p') {
+ LEAVE('n');
+ return NULL;
}
- if(Name[3] < '0' || Name[3] > '9') return NULL;
-
- i = (Name[2] - '0')*10;
- i += Name[3] - '0';
+ i = 2; num = 0;
+ while('0' <= Name[i] && Name[i] <= '9')
+ {
+ num *= 10;
+ num += Name[i] - '0';
+ i ++;
+ }
+ if(Name[i] != '\0') {
+ LEAVE('n');
+ return NULL;
+ }
- for( iface = gIP_Interfaces; iface && i--; iface = iface->Next ) ;
- if(!iface) return NULL;
- return &iface->Node;
+ for( iface = gIP_Interfaces; iface; iface = iface->Next )
+ {
+ if( iface->Node.ImplInt == num )
+ {
+ LEAVE('p', &iface->Node);
+ return &iface->Node;
+ }
+ }
+ LEAVE('p', NULL);
+ return NULL;
}
static const char *casIOCtls_Root[] = { DRV_IOCTLNAMES, "add_interface", NULL };
*/
int IPStack_IOCtl(tVFS_Node *Node, int ID, void *Data)
{
+ int tmp;
+ ENTER("pNode iID pData", Node, ID, Data);
+
switch(ID)
{
// --- Standard IOCtls (0-3) ---
case DRV_IOCTL_TYPE:
+ LEAVE('i', DRV_TYPE_MISC);
return DRV_TYPE_MISC;
case DRV_IOCTL_IDENT:
- if( !CheckMem( Data, 4 ) ) return -1;
+ if( !CheckMem( Data, 4 ) ) LEAVE_RET('i', -1);
memcpy(Data, "IP\0\0", 4);
+ LEAVE('i', 1);
return 1;
case DRV_IOCTL_VERSION:
+ LEAVE('x', VERSION);
return VERSION;
case DRV_IOCTL_LOOKUP:
- if( !CheckString( Data ) ) return -1;
-
+ if( !CheckString( Data ) ) LEAVE_RET('i', -1);
+ LOG("Lookup '%s'", Data);
if( Node == &gIP_DriverInfo.RootNode )
- return LookupString( (char**)casIOCtls_Root, (char*)Data );
+ tmp = LookupString( (char**)casIOCtls_Root, (char*)Data );
else
- return LookupString( (char**)casIOCtls_Iface, (char*)Data );
+ tmp = LookupString( (char**)casIOCtls_Iface, (char*)Data );
+ LEAVE('i', tmp);
+ return tmp;
}
if(Node == &gIP_DriverInfo.RootNode)
* - Adds a new IP interface and binds it to a device
*/
case 4:
- if( Threads_GetUID() != 0 ) return -1;
- if( !CheckString( Data ) ) return -1;
- return IPStack_AddInterface(Data);
+ if( Threads_GetUID() != 0 ) LEAVE_RET('i', -1);
+ if( !CheckString( Data ) ) LEAVE_RET('i', -1);
+ tmp = IPStack_AddInterface(Data);
+ LEAVE_RET('i', tmp);
}
+ LEAVE('i', 0);
return 0;
}
else
* - Get/Set the interface type
*/
case 4:
- // Get Type?
- if( !Data ) return iface->Type;
- // Ok, it's set type
- if( Threads_GetUID() != 0 ) return -1;
- if( !CheckMem( Data, sizeof(int) ) ) return -1;
- switch( *(int*)Data )
+ // Set Type?
+ if( Data )
{
- case 0: // Disable
- iface->Type = 0;
- memset(&iface->IP6, 0, sizeof(tIPv6)); // Clear address
- break;
- case 4: // IPv4
- iface->Type = 4;
- memset(&iface->IP4, 0, sizeof(tIPv4));
- break;
- case 6: // IPv6
- iface->Type = 6;
- memset(&iface->IP6, 0, sizeof(tIPv6));
- break;
- default:
- return -1;
+ // Ok, it's set type
+ if( Threads_GetUID() != 0 ) {
+ LOG("Attempt by non-root to alter an interface (%i)", Threads_GetUID());
+ LEAVE('i', -1);
+ return -1;
+ }
+ if( !CheckMem( Data, sizeof(int) ) ) {
+ LOG("Invalid pointer %p", Data);
+ LEAVE('i', -1);
+ return -1;
+ }
+ switch( *(int*)Data )
+ {
+ case 0: // Disable
+ iface->Type = 0;
+ memset(&iface->IP6, 0, sizeof(tIPv6)); // Clear address
+ break;
+ case 4: // IPv4
+ iface->Type = 4;
+ memset(&iface->IP4, 0, sizeof(tIPv4));
+ break;
+ case 6: // IPv6
+ iface->Type = 6;
+ memset(&iface->IP6, 0, sizeof(tIPv6));
+ break;
+ default:
+ LEAVE('i', -1);
+ return -1;
+ }
}
- return 0;
+ LEAVE('i', iface->Type);
+ return iface->Type;
/*
* get_address
case 5:
switch(iface->Type)
{
- case 0: return 1;
+ case 0: LEAVE_RET('i', 1);
case 4:
- if( !CheckMem( Data, sizeof(tIPv4) ) ) return -1;
- memcpy( Data, &iface->IP4, sizeof(tIPv4) );
- return 1;
+ if( !CheckMem( Data, sizeof(tIPv4) ) ) LEAVE_RET('i', -1);
+ memcpy( Data, &iface->IP4.Address, sizeof(tIPv4) );
+ LEAVE_RET('i', 1);
case 6:
- if( !CheckMem( Data, sizeof(tIPv6) ) ) return -1;
- memcpy( Data, &iface->IP6, sizeof(tIPv6) );
- return 1;
+ if( !CheckMem( Data, sizeof(tIPv6) ) ) LEAVE_RET('i', -1);
+ memcpy( Data, &iface->IP6.Address, sizeof(tIPv6) );
+ LEAVE_RET('i', 1);
}
- return 0;
+ LEAVE_RET('i', 0);
/*
* set_address
* - Get the interface's address
*/
case 6:
- if( Threads_GetUID() != 0 ) return -1;
+ if( Threads_GetUID() != 0 ) LEAVE_RET('i', -1);
switch(iface->Type)
{
- case 0: return 1;
+ case 0: LEAVE_RET('i', 1);
case 4:
- if( !CheckMem( Data, sizeof(tIPv4) ) ) return -1;
+ if( !CheckMem( Data, sizeof(tIPv4) ) ) LEAVE_RET('i', -1);
iface->Type = 0; // One very hacky mutex/trash protector
- memcpy( &iface->IP4, Data, sizeof(tIPv4) );
+ memcpy( &iface->IP4.Address, Data, sizeof(tIPv4) );
iface->Type = 4;
- return 1;
+ LEAVE_RET('i', 1);
case 6:
- if( !CheckMem( Data, sizeof(tIPv6) ) ) return -1;
+ if( !CheckMem( Data, sizeof(tIPv6) ) ) LEAVE_RET('i', -1);
iface->Type = 0;
- memcpy( &iface->IP6, Data, sizeof(tIPv6) );
+ memcpy( &iface->IP6.Address, Data, sizeof(tIPv6) );
iface->Type = 6;
- return 1;
+ LEAVE_RET('i', 1);
}
- return 0;
+ LEAVE_RET('i', 0);
/*
* getset_subnet
{
switch( iface->Type )
{
- case 4: return iface->IP4.SubnetBits;
- case 6: return iface->IP6.SubnetBits;
- default: return 0;
+ case 4: LEAVE_RET('i', iface->IP4.SubnetBits);
+ case 6: LEAVE_RET('i', iface->IP6.SubnetBits);
+ default: LEAVE_RET('i', 0);
}
}
// Ok, set.
- if( Threads_GetUID() != 0 ) return -1;
- if( !CheckMem(Data, sizeof(int)) ) return -1;
+ if( Threads_GetUID() != 0 ) LEAVE_RET('i', -1);
+ if( !CheckMem(Data, sizeof(int)) ) LEAVE_RET('i', -1);
// Check and set the subnet bits
switch( iface->Type )
{
case 4:
- if( *(int*)Data < 0 || *(int*)Data > 31 ) return -1;
+ if( *(int*)Data < 0 || *(int*)Data > 31 ) LEAVE_RET('i', -1);
iface->IP4.SubnetBits = *(int*)Data;
- return iface->IP4.SubnetBits;
+ LEAVE_RET('i', iface->IP4.SubnetBits);
case 6:
- if( *(int*)Data < 0 || *(int*)Data > 127 ) return -1;
+ if( *(int*)Data < 0 || *(int*)Data > 127 ) LEAVE_RET('i', -1);
iface->IP6.SubnetBits = *(int*)Data;
- return iface->IP6.SubnetBits;
+ LEAVE_RET('i', iface->IP6.SubnetBits);
default:
break;
}
+ LEAVE('i', 0);
+ return 0;
+
+ /*
+ * get_gateway
+ * - Get the interface's IPv4 gateway
+ */
+ case 8:
+ switch(iface->Type)
+ {
+ case 0:
+ LEAVE_RET('i', 1);
+ case 4:
+ if( !CheckMem( Data, sizeof(tIPv4) ) ) LEAVE_RET('i', -1);
+ memcpy( Data, &iface->IP4.Gateway, sizeof(tIPv4) );
+ LEAVE_RET('i', 1);
+ case 6:
+ LEAVE_RET('i', 1);
+ }
+ LEAVE('i', 0);
return 0;
+
+ /*
+ * set_gateway
+ * - Get the interface's IPv4 gateway
+ */
+ case 9:
+ if( Threads_GetUID() != 0 ) LEAVE_RET('i', -1);
+ switch(iface->Type)
+ {
+ case 0:
+ LEAVE_RET('i', 1);
+
+ case 4:
+ if( !CheckMem( Data, sizeof(tIPv4) ) ) LEAVE_RET('i', -1);
+ iface->Type = 0; // One very hacky mutex/trash protector
+ memcpy( &iface->IP4.Gateway, Data, sizeof(tIPv4) );
+ iface->Type = 4;
+ LEAVE_RET('i', 1);
+
+ case 6:
+ LEAVE_RET('i', 1);
+ }
+ LEAVE_RET('i', 0);
}
}
+ LEAVE('i', 0);
return 0;
}
{
tInterface *iface;
+ ENTER("sDevice", Device);
+
iface = malloc(sizeof(tInterface));
- if(!iface) return -2; // Return ERR_MYBAD
+ if(!iface) {
+ LEAVE('i', -2);
+ return -2; // Return ERR_MYBAD
+ }
iface->Next = NULL;
iface->Type = 0; // Unset type
// Create Node
+ iface->Node.ImplPtr = iface;
+ iface->Node.ImplInt = giIP_NextIfaceId++;
iface->Node.Flags = VFS_FFLAG_DIRECTORY;
iface->Node.Size = 0;
iface->Node.NumACLs = 1;
iface->Node.ACLs = &gVFS_ACL_EveryoneRX;
iface->Node.ReadDir = NULL;
iface->Node.FindDir = NULL;
+ iface->Node.IOCtl = IPStack_IOCtl;
// Get adapter handle
iface->Adapter = IPStack_GetAdapter(Device);
if( !iface->Adapter ) {
free( iface );
+ LEAVE('i', -1);
return -1; // Return ERR_YOUFAIL
}
}
RELEASE( &glIP_Interfaces );
+ gIP_DriverInfo.RootNode.Size ++;
+
// Success!
- return 1;
+ LEAVE('i', iface->Node.ImplInt);
+ return iface->Node.ImplInt;
}
/**
tAdapter *IPStack_GetAdapter(char *Path)
{
tAdapter *dev;
+ int tmp;
+
+ ENTER("sPath", Path);
LOCK( &glIP_Adapters );
if( strcmp(dev->Device, Path) == 0 ) {
dev->NRef ++;
RELEASE( &glIP_Adapters );
+ LEAVE('p', dev);
return dev;
}
}
dev = malloc( sizeof(tAdapter) + strlen(Path) + 1 );
if(!dev) {
RELEASE( &glIP_Adapters );
+ LEAVE('n');
return NULL;
}
if( dev->DeviceFD == -1 ) {
free( dev );
RELEASE( &glIP_Adapters );
+ LEAVE('n');
return NULL;
}
// Check that it is a network interface
- if( VFS_IOCtl(dev->DeviceFD, 0, NULL) != DRV_TYPE_NETWORK ) {
+ tmp = VFS_IOCtl(dev->DeviceFD, 0, NULL);
+ LOG("Device type = %i", tmp);
+ if( tmp != DRV_TYPE_NETWORK ) {
Warning("IPStack_GetAdapter: '%s' is not a network interface", dev->Device);
VFS_Close( dev->DeviceFD );
free( dev );
RELEASE( &glIP_Adapters );
+ LEAVE('n');
return NULL;
}
gIP_Adapters = dev;
RELEASE( &glIP_Adapters );
+
+ // Start watcher
+ Link_WatchDevice( dev );
+
+ LEAVE('p', dev);
return dev;
}
-include ../../Makefile.cfg
CPPFLAGS = -I../../Kernel/include -I../../Kernel/arch/$(ARCHDIR)/include -DARCH=$(ARCH)
-CFLAGS = -Wall -Werror $(CPPFLAGS)
+CFLAGS = -Wall -Werror -fno-stack-protector $(CPPFLAGS)
OBJ := $(addsuffix .$(ARCH),$(OBJ))
BIN = ../$(NAME).kmd.$(ARCH)
all: $(BIN)
clean:
- $(RM) $(BIN) $(KOBJ) $(OBJ) $(DEPFILES)
+ $(RM) $(BIN) $(BIN).dsm $(KOBJ) $(OBJ) $(DEPFILES)
$(BIN): $(OBJ)
@echo --- $(LD) -o $@
@$(LD) -T ../link.ld -shared -nostdlib -o $@ $(OBJ)
# @$(LD) -shared -nostdlib -o $@ $(OBJ)
+ @$(OBJDUMP) -d $(BIN) > $(BIN).dsm
cp $@ $(DISTROOT)/Modules/$(NAME).kmd
@echo --- $(LD) -o $(KOBJ)
@$(CC) -Wl,-r -nostdlib -o $(KOBJ) $(OBJ)
#include <modules.h>
#include <fs_devfs.h>
#include <drv_pci.h>
+#include <tpl_drv_network.h>
// === CONSTANTS ===
#define MEM_START 0x40
.ACLs = &gVFS_ACL_EveryoneRX,
.Flags = VFS_FFLAG_DIRECTORY,
.ReadDir = Ne2k_ReadDir,
- .FindDir = Ne2k_FindDir
+ .FindDir = Ne2k_FindDir,
+ .IOCtl = Ne2k_IOCtl
}
};
Uint16 gNe2k_BaseAddress;
*/
int Ne2k_IOCtl(tVFS_Node *Node, int ID, void *Data)
{
+ int tmp;
+ ENTER("pNode iID pData", Node, ID, Data);
switch( ID )
{
- case DRV_IOCTL_TYPE: return DRV_TYPE_NETWORK;
+ case DRV_IOCTL_TYPE:
+ LEAVE('i', DRV_TYPE_NETWORK);
+ return DRV_TYPE_NETWORK;
+
case DRV_IOCTL_IDENT:
- if(!CheckMem(Data, 4)) return -1;
+ if(!CheckMem(Data, 4)) {
+ LEAVE('i', -1);
+ return -1;
+ }
memcpy(Data, "NE2K", 4);
+ LEAVE('i', 1);
return 1;
- case DRV_IOCTL_VERSION: return VERSION;
+
+ case DRV_IOCTL_VERSION:
+ LEAVE('x', VERSION);
+ return VERSION;
+
case DRV_IOCTL_LOOKUP:
- if(!CheckString(Data)) return -1;
- return LookupString( casIOCtls, Data );
+ if( !CheckString(Data) ) {
+ LEAVE('i', -1);
+ return -1;
+ }
+ tmp = LookupString( (char**)casIOCtls, Data );
+ LEAVE('i', tmp);
+ return tmp;
}
// If this is the root, return
- if( Node == &gNe2k_DriverInfo.Node ) return 0;
+ if( Node == &gNe2k_DriverInfo.RootNode ) {
+ LEAVE('i', 0);
+ return 0;
+ }
// Device specific settings
switch( ID )
{
case NET_IOCTL_GETMAC:
- if(!CheckMem(Data, 6)) return -1;
+ if( !CheckMem(Data, 6) ) {
+ LEAVE('i', -1);
+ return -1;
+ }
memcpy( Data, ((tCard*)Node->ImplPtr)->MacAddr, 6 );
+ LEAVE('i', 1);
return 1;
}
+ LEAVE('i', 0);
return 0;
}
--- /dev/null
+# Project: ifconfig\r
+\r
+-include ../Makefile.cfg\r
+\r
+COBJ = main.o
+BIN = ../ifconfig\r
+\r
+CFLAGS += -Wall -fno-builtin -fno-stack-protector\r
+LDFLAGS += \r
+\r
+.PHONY : all clean\r
+\r
+all: $(BIN)\r
+\r
+$(BIN): $(COBJ)\r
+ @echo --- $(LD) -o $@\r
+ @$(LD) $(LDFLAGS) -o $@ $(COBJ) -Map Map.txt\r
+ @objdump -d $(BIN) > $(BIN).dsm\r
+ cp $(BIN) $(DISTROOT)/Bin/
+\r
+clean:\r
+ @$(RM) $(COBJ) $(BIN) $(BIN).dsm Map.txt
+\r
+$(COBJ): %.o: %.c\r
+ @echo --- GCC -o $@
+ @$(CC) $(CFLAGS) -c $? -o $@
+\r
--- /dev/null
+/*
+ * Acess2 IFCONFIG command
+ */
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <acess/sys.h>
+
+// === CONSTANTS ===
+#define FILENAME_MAX 255
+#define IPSTACK_ROOT "/Devices/ip"
+
+// === PROTOTYPES ===
+void PrintUsage(char *ProgName);
+void DumpInterfaces( int DumpAll );
+ int AddInterface( char *Address );
+ int DoAutoConfig( char *Device );
+
+// === CODE ===
+/**
+ * \fn int main(int argc, char *argv[])
+ * \brief Entrypoint
+ */
+int main(int argc, char *argv[])
+{
+ if(argc == 1) {
+ DumpInterfaces(0);
+ return 0;
+ }
+
+ if( strcmp(argv[1], "add") == 0 ) {
+ if( argc < 3 ) {
+ fprintf(stderr, "ERROR: `add` requires an argument\n");
+ PrintUsage(argv[0]);
+ return 0;
+ }
+ return AddInterface( argv[2] );
+ }
+
+ if( strcmp(argv[1], "autoconf") == 0 ) {
+ DoAutoConfig(argv[2]);
+ }
+
+ return 0;
+}
+
+void PrintUsage(char *ProgName)
+{
+ fprintf(stderr, "Usage: %s [add <ipaddr>]\n", ProgName);
+}
+
+void DumpInterfaces(int DumpAll)
+{
+ int dp, fd;
+ int type;
+ char path[sizeof(IPSTACK_ROOT)+1+FILENAME_MAX] = IPSTACK_ROOT"/";
+ char *filename = &path[sizeof(IPSTACK_ROOT)];
+
+ dp = open(IPSTACK_ROOT, OPENFLAG_READ);
+
+ while( readdir(dp, filename) )
+ {
+ if(filename[0] == '.') continue;
+ if(filename[0] != 'i' || filename[1] != 'p') continue;
+
+ fd = open(path, OPENFLAG_READ);
+ if(fd == -1) {
+ printf("%s:\tUnable to open ('%s'\n\n", filename, path);
+ }
+
+ type = ioctl(fd, 4, NULL);
+
+ printf("%s:\t", filename);
+ switch(type)
+ {
+ case 0:
+ printf("DISABLED\n");
+ break;
+ case 4:
+ {
+ uint8_t ip[4];
+ int subnet;
+ printf("IPv4\n");
+ ioctl(fd, 5, ip); // Get IP Address
+ subnet = ioctl(fd, 7, NULL); // Get Subnet Bits
+ printf("\t%i.%i.%i.%i/%i\n", ip[0], ip[1], ip[2], ip[3], subnet);
+ ioctl(fd, 8, ip); // Get Gateway
+ printf("\tGateway: %i.%i.%i.%i\n", ip[0], ip[1], ip[2], ip[3]);
+ }
+ break;
+ case 6:
+ {
+ uint16_t ip[8];
+ int subnet;
+ printf("IPv6\n");
+ ioctl(fd, 5, ip); // Get IP Address
+ subnet = ioctl(fd, 7, NULL); // Get Subnet Bits
+ printf("\t%x:%x:%x:%x:%x:%x:%x:%x/%i\n",
+ ip[0], ip[1], ip[2], ip[3],
+ ip[4], ip[5], ip[6], ip[7],
+ subnet);
+ }
+ break;
+ default:
+ printf("UNKNOWN\n");
+ break;
+ }
+ printf("\n");
+
+ close(fd);
+ }
+
+ close(dp);
+}
+
+int AddInterface( char *Device )
+{
+ int dp, ret;
+
+ dp = open(IPSTACK_ROOT, OPENFLAG_READ);
+ ret = ioctl(dp, 4, Device);
+ close(dp);
+
+ if( ret < 0 ) {
+ fprintf(stderr, "Unable to add '%s' as a network interface\n", Device);
+ return -1;
+ }
+
+ printf("-- Added '"IPSTACK_ROOT"/ip%i' using device %s\n", ret, Device);
+
+ return ret;
+}
+
+int DoAutoConfig( char *Device )
+{
+ int tmp, fd;
+ char path[sizeof(IPSTACK_ROOT)+5+1]; // ip000
+ uint8_t addr[4] = {192,168,1,39};
+ uint8_t gw[4] = {192,168,1,1};
+
+ tmp = AddInterface(Device);
+ if( tmp < 0 ) return tmp;
+
+ sprintf(path, IPSTACK_ROOT"/ip%i", tmp);
+
+ fd = open(path, OPENFLAG_READ);
+ if( fd == -1 ) {
+ fprintf(stderr, "Unable to open '%s'\n", path);
+ return -1;
+ }
+
+ tmp = 4; // IPv4
+ tmp = ioctl(fd, ioctl(fd, 3, "getset_type"), &tmp);
+ if( tmp != 4 ) {
+ fprintf(stderr, "Error in setting address type (got %i, expected 4)\n", tmp);
+ return -1;
+ }
+ // Set Address
+ ioctl(fd, ioctl(fd, 3, "set_address"), addr);
+ // Set Subnet
+ tmp = 24;
+ ioctl(fd, ioctl(fd, 3, "getset_subnet"), &tmp);
+ // Set Gateway
+ ioctl(fd, ioctl(fd, 3, "set_gateway"), gw);
+
+ close(fd);
+
+ printf("Set address to 192.168.1.39/24 (GW: 192.168.1.1)\n");
+
+ return 0;
+}