1 /* 2 * Copyright 2006, Haiku, Inc. All Rights Reserved. 3 * Distributed under the terms of the MIT License. 4 * 5 * Authors: 6 * Axel Dörfler, axeld@pinc-software.de 7 */ 8 9 10 #include <net_buffer.h> 11 #include <net_device.h> 12 #include <net_stack.h> 13 14 #include <KernelExport.h> 15 16 #include <net/if.h> 17 #include <net/if_types.h> 18 #include <new> 19 #include <stdlib.h> 20 #include <string.h> 21 22 23 struct loopback_device : net_device { 24 net_fifo fifo; 25 }; 26 27 28 struct net_buffer_module_info *gBufferModule; 29 static struct net_stack_module_info *sStackModule; 30 31 32 /*! 33 Swaps \a size bytes of the memory pointed to by \a and \b with each other. 34 */ 35 void 36 swap_memory(void *a, void *b, size_t size) 37 { 38 uint32 *a4 = (uint32 *)a; 39 uint32 *b4 = (uint32 *)b; 40 while (size > 4) { 41 uint32 temp = *a4; 42 *(a4++) = *b4; 43 *(b4++) = temp; 44 45 size -= 4; 46 } 47 48 uint8 *a1 = (uint8 *)a4; 49 uint8 *b1 = (uint8 *)b4; 50 while (size > 0) { 51 uint8 temp = *a1; 52 *(a1++) = *b1; 53 *(b1++) = temp; 54 55 size--; 56 } 57 } 58 59 60 // #pragma mark - 61 62 63 status_t 64 loopback_init(const char *name, net_device **_device) 65 { 66 loopback_device *device; 67 68 if (strncmp(name, "loop", 4)) 69 return B_BAD_VALUE; 70 71 status_t status = get_module(NET_STACK_MODULE_NAME, (module_info **)&sStackModule); 72 if (status < B_OK) 73 return status; 74 75 status = get_module(NET_BUFFER_MODULE_NAME, (module_info **)&gBufferModule); 76 if (status < B_OK) 77 goto err1; 78 79 device = new (std::nothrow) loopback_device; 80 if (device == NULL) { 81 status = B_NO_MEMORY; 82 goto err2; 83 } 84 85 memset(device, 0, sizeof(loopback_device)); 86 87 strcpy(device->name, name); 88 device->flags = IFF_LOOPBACK; 89 device->type = IFT_LOOP; 90 device->mtu = 16384; 91 92 *_device = device; 93 return B_OK; 94 95 err2: 96 put_module(NET_BUFFER_MODULE_NAME); 97 err1: 98 put_module(NET_STACK_MODULE_NAME); 99 return status; 100 } 101 102 103 status_t 104 loopback_uninit(net_device *_device) 105 { 106 loopback_device *device = (loopback_device *)_device; 107 108 put_module(NET_STACK_MODULE_NAME); 109 put_module(NET_BUFFER_MODULE_NAME); 110 delete device; 111 112 return B_OK; 113 } 114 115 116 status_t 117 loopback_up(net_device *_device) 118 { 119 loopback_device *device = (loopback_device *)_device; 120 return sStackModule->init_fifo(&device->fifo, "loopback fifo", 65536); 121 } 122 123 124 void 125 loopback_down(net_device *_device) 126 { 127 loopback_device *device = (loopback_device *)_device; 128 sStackModule->uninit_fifo(&device->fifo); 129 } 130 131 132 status_t 133 loopback_control(net_device *device, int32 op, void *argument, 134 size_t length) 135 { 136 return B_BAD_VALUE; 137 } 138 139 140 status_t 141 loopback_send_data(net_device *_device, net_buffer *buffer) 142 { 143 loopback_device *device = (loopback_device *)_device; 144 return sStackModule->fifo_enqueue_buffer(&device->fifo, buffer); 145 } 146 147 148 status_t 149 loopback_receive_data(net_device *_device, net_buffer **_buffer) 150 { 151 loopback_device *device = (loopback_device *)_device; 152 net_buffer *buffer; 153 154 status_t status = sStackModule->fifo_dequeue_buffer(&device->fifo, 0, 0, &buffer); 155 if (status < B_OK) 156 return status; 157 158 // switch network addresses before delivering 159 swap_memory(&buffer->source, &buffer->destination, 160 max_c(buffer->source.ss_len, buffer->destination.ss_len)); 161 162 *_buffer = buffer; 163 return B_OK; 164 } 165 166 167 status_t 168 loopback_set_mtu(net_device *device, size_t mtu) 169 { 170 if (mtu > 65536 171 || mtu < 16) 172 return B_BAD_VALUE; 173 174 device->mtu = mtu; 175 return B_OK; 176 } 177 178 179 status_t 180 loopback_set_promiscuous(net_device *device, bool promiscuous) 181 { 182 return EOPNOTSUPP; 183 } 184 185 186 status_t 187 loopback_set_media(net_device *device, uint32 media) 188 { 189 return EOPNOTSUPP; 190 } 191 192 193 static status_t 194 loopback_std_ops(int32 op, ...) 195 { 196 switch (op) { 197 case B_MODULE_INIT: 198 case B_MODULE_UNINIT: 199 return B_OK; 200 201 default: 202 return B_ERROR; 203 } 204 } 205 206 207 net_device_module_info sLoopbackModule = { 208 { 209 "network/devices/loopback/v1", 210 0, 211 loopback_std_ops 212 }, 213 loopback_init, 214 loopback_uninit, 215 loopback_up, 216 loopback_down, 217 loopback_control, 218 loopback_send_data, 219 loopback_receive_data, 220 loopback_set_mtu, 221 loopback_set_promiscuous, 222 loopback_set_media, 223 }; 224 225 module_info *modules[] = { 226 (module_info *)&sLoopbackModule, 227 NULL 228 }; 229