3 * - By John Hodge (thePowersGang)
6 * - "Network Service Requester" (UDI->IP Translation)
12 #include <trans_nsr.h>
13 #include <IPStack/include/adapters_api.h>
14 #include <workqueue.h>
16 #define NUM_RX_BUFFERS 4
17 #define NUM_TX_DESCS 4
20 ACESSNSR_OPS_CTRL = 1,
35 typedef struct acessnsr_txdesc_s
40 tIPStackBuffer *IPBuffer;
45 udi_init_context_t init_context;
47 udi_channel_t saved_active_channel;
51 tIPStack_AdapterType AdapterType;
54 tWorkqueue TXWorkQueue;
55 acessnsr_txdesc_t TXDescs[NUM_TX_DESCS];
57 udi_channel_t rx_channel;
58 udi_channel_t tx_channel;
62 // --- Management metalang
63 void acessnsr_usage_ind(udi_usage_cb_t *cb, udi_ubit8_t resource_level);
64 void acessnsr_devmgmt_req(udi_mgmt_cb_t *cb, udi_ubit8_t mgmt_op, udi_ubit8_t parent_ID);
65 void acessnsr_final_cleanup_req(udi_mgmt_cb_t *cb);
67 void acessnsr_ctrl_channel_event_ind(udi_channel_event_cb_t *cb);
68 void acessnsr_ctrl_ch_ev_ind__rx_channel_spawned(udi_cb_t *gcb, udi_channel_t channel);
69 void acessnsr_ctrl_ch_ev_ind__tx_channel_spawned(udi_cb_t *gcb, udi_channel_t channel);
70 void acessnsr_ctrl_bind_ack(udi_nic_bind_cb_t *cb, udi_status_t status);
71 void acessnsr_ctrl_bind_ack__rx_cbs_allocated(udi_cb_t *gcb, udi_cb_t *first_new_cb);
72 void acessnsr_ctrl_bind_ack__tx_cbs_allocated(udi_cb_t *gcb, udi_cb_t *first_new_cb);
73 void acessnsr_ctrl_bind_ack__std_cb_allocated(udi_cb_t *gcb, udi_cb_t *new_cb);
74 void acessnsr_ctrl_unbind_ack(udi_nic_cb_t *cb, udi_status_t status);
75 void acessnsr_ctrl_enable_ack(udi_nic_cb_t *cb, udi_status_t status);
76 void acessnsr_ctrl_disable_ack(udi_nic_cb_t *cb, udi_status_t status);
77 void acessnsr_ctrl_ctrl_ack(udi_nic_ctrl_cb_t *cb, udi_status_t status);
78 void acessnsr_ctrl_status_ind(udi_nic_status_cb_t *cb);
79 void acessnsr_ctrl_info_ack(udi_nic_info_cb_t *cb);
81 void acessnsr_tx_channel_event_ind(udi_channel_event_cb_t *cb);
82 void acessnsr_tx_rdy(udi_nic_tx_cb_t *cb);
83 void acessnsr_tx_rdy__buffer_cleared(udi_cb_t *gcb, udi_buf_t *buf);
85 void acessnsr_rx_channel_event_ind(udi_channel_event_cb_t *cb);
86 void acessnsr_rx_ind(udi_nic_rx_cb_t *cb);
87 void acessnsr_rx_exp_ind(udi_nic_rx_cb_t *cb);
89 int acessnsr_SendPacket(void *Card, tIPStackBuffer *Buffer);
90 void acessnsr_SendPacket__buf_write_complete(udi_cb_t *gcb, udi_buf_t *buf);
91 tIPStackBuffer *acessnsr_WaitForPacket(void *Card);
94 // --- Management metalang
95 void acessnsr_usage_ind(udi_usage_cb_t *cb, udi_ubit8_t resource_level)
97 acessnsr_rdata_t *rdata = UDI_GCB(cb)->context;
98 switch(resource_level)
102 Workqueue_Init(&rdata->RXQueue, "AcessNSR RX", offsetof(udi_nic_rx_cb_t, chain));
103 Workqueue_Init(&rdata->TXWorkQueue, "AcessNSR TX", offsetof(udi_nic_tx_cb_t, chain));
107 void acessnsr_devmgmt_req(udi_mgmt_cb_t *cb, udi_ubit8_t mgmt_op, udi_ubit8_t parent_ID)
111 void acessnsr_final_cleanup_req(udi_mgmt_cb_t *cb)
116 void acessnsr_ctrl_channel_event_ind(udi_channel_event_cb_t *cb)
118 acessnsr_rdata_t *rdata = UDI_GCB(cb)->context;
121 case UDI_CHANNEL_CLOSED:
123 case UDI_CHANNEL_BOUND: {
124 rdata->active_cb = UDI_GCB(cb);
125 udi_channel_spawn(acessnsr_ctrl_ch_ev_ind__rx_channel_spawned,
126 cb->params.parent_bound.bind_cb, UDI_GCB(cb)->channel,
127 1, ACESSNSR_OPS_RX, rdata);
132 void acessnsr_ctrl_ch_ev_ind__rx_channel_spawned(udi_cb_t *gcb, udi_channel_t channel)
134 acessnsr_rdata_t *rdata = gcb->context;
135 rdata->rx_channel = channel;
136 udi_channel_spawn(acessnsr_ctrl_ch_ev_ind__tx_channel_spawned, gcb, gcb->channel,
137 2, ACESSNSR_OPS_TX, rdata);
140 void acessnsr_ctrl_ch_ev_ind__tx_channel_spawned(udi_cb_t *gcb, udi_channel_t channel)
142 acessnsr_rdata_t *rdata = gcb->context;
143 rdata->tx_channel = channel;
144 udi_nic_bind_cb_t *bind_cb = UDI_MCB(gcb, udi_nic_bind_cb_t);
145 udi_nd_bind_req(bind_cb, 2, 1);
148 void acessnsr_ctrl_bind_ack(udi_nic_bind_cb_t *cb, udi_status_t status)
150 acessnsr_rdata_t *rdata = UDI_GCB(cb)->context;
151 // TODO: Parse cb and register with IPStack
152 // - Pass on capabilities and media type
153 switch(cb->media_type)
155 case UDI_NIC_ETHER: rdata->AdapterType.Type = ADAPTERTYPE_ETHERNET_10M; break;
156 case UDI_NIC_FASTETHER: rdata->AdapterType.Type = ADAPTERTYPE_ETHERNET_100M; break;
157 case UDI_NIC_GIGETHER: rdata->AdapterType.Type = ADAPTERTYPE_ETHERNET_1G; break;
159 udi_channel_event_complete( UDI_MCB(rdata->active_cb,udi_channel_event_cb_t), UDI_OK );
163 // - Register with IPStack
164 if(cb->capabilities & UDI_NIC_CAP_TX_IP_CKSUM)
165 rdata->AdapterType.Flags |= ADAPTERFLAG_OFFLOAD_IP4;
166 if(cb->capabilities & UDI_NIC_CAP_TX_TCP_CKSUM)
167 rdata->AdapterType.Flags |= ADAPTERFLAG_OFFLOAD_TCP;
168 if(cb->capabilities & UDI_NIC_CAP_TX_UDP_CKSUM)
169 rdata->AdapterType.Flags |= ADAPTERFLAG_OFFLOAD_UDP;
170 rdata->AdapterType.Name = "udi";
171 rdata->AdapterType.SendPacket = acessnsr_SendPacket;
172 rdata->AdapterType.WaitForPacket = acessnsr_WaitForPacket;
173 rdata->ipstack_handle = IPStack_Adapter_Add(&rdata->AdapterType, rdata, cb->mac_addr);
175 // Allocate RX CBs and buffers
176 // EVIL: Save and change channel of event CB
177 rdata->saved_active_channel = rdata->active_cb->channel;
178 rdata->active_cb->channel = rdata->rx_channel;
179 udi_cb_alloc_batch( acessnsr_ctrl_bind_ack__rx_cbs_allocated, rdata->active_cb,
180 ACESSNSR_CB_RX, NUM_RX_BUFFERS, TRUE, 0, NULL);
183 void acessnsr_ctrl_bind_ack__rx_cbs_allocated(udi_cb_t *gcb, udi_cb_t *first_new_cb)
185 acessnsr_rdata_t *rdata = gcb->context;
186 // Send of the entire list
187 ASSERT(first_new_cb);
188 udi_nd_rx_rdy( UDI_MCB(first_new_cb, udi_nic_rx_cb_t) );
190 // Allocate batch (no buffers)
191 gcb->channel = rdata->tx_channel;
192 udi_cb_alloc_batch( acessnsr_ctrl_bind_ack__tx_cbs_allocated, gcb,
193 ACESSNSR_CB_TX, NUM_TX_DESCS, FALSE, 0, NULL);
196 void acessnsr_ctrl_bind_ack__tx_cbs_allocated(udi_cb_t *gcb, udi_cb_t *first_new_cb)
198 acessnsr_rdata_t *rdata = gcb->context;
199 ASSERT(first_new_cb);
202 udi_nic_tx_cb_t *cb, *next_cb;
203 cb = UDI_MCB(first_new_cb, udi_nic_tx_cb_t);
208 Workqueue_AddWork( &rdata->TXWorkQueue, cb );
212 // Allocate standard control CB (for enable/disable)
213 udi_cb_alloc(acessnsr_ctrl_bind_ack__std_cb_allocated, gcb,
214 ACESSNSR_CB_STD, rdata->saved_active_channel);
217 void acessnsr_ctrl_bind_ack__std_cb_allocated(udi_cb_t *gcb, udi_cb_t *new_cb)
220 // - Enable card (RX won't happen until this is called)
221 udi_nd_enable_req( UDI_MCB(new_cb, udi_nic_cb_t) );
222 // Continued in acessnsr_ctrl_enable_ack
224 void acessnsr_ctrl_unbind_ack(udi_nic_cb_t *cb, udi_status_t status)
228 void acessnsr_ctrl_enable_ack(udi_nic_cb_t *cb, udi_status_t status)
230 udi_cb_t *gcb = UDI_GCB(cb);
231 acessnsr_rdata_t *rdata = gcb->context;
233 rdata->active_cb->channel = rdata->saved_active_channel;
234 udi_channel_event_complete( UDI_MCB(rdata->active_cb,udi_channel_event_cb_t), UDI_OK );
237 void acessnsr_ctrl_disable_ack(udi_nic_cb_t *cb, udi_status_t status)
241 void acessnsr_ctrl_ctrl_ack(udi_nic_ctrl_cb_t *cb, udi_status_t status)
245 void acessnsr_ctrl_status_ind(udi_nic_status_cb_t *cb)
249 void acessnsr_ctrl_info_ack(udi_nic_info_cb_t *cb)
254 void acessnsr_tx_channel_event_ind(udi_channel_event_cb_t *cb)
258 void acessnsr_tx_rdy(udi_nic_tx_cb_t *cb)
260 //acessnsr_txdesc_t *tx = UDI_GCB(cb)->context;
261 // TODO: Can errors be detected here?
262 UDI_BUF_DELETE(acessnsr_tx_rdy__buffer_cleared, UDI_GCB(cb), cb->tx_buf->buf_size, cb->tx_buf, 0);
264 void acessnsr_tx_rdy__buffer_cleared(udi_cb_t *gcb, udi_buf_t *buf)
266 acessnsr_txdesc_t *tx = gcb->scratch;
267 udi_nic_tx_cb_t *cb = UDI_MCB(gcb, udi_nic_tx_cb_t);
269 Mutex_Release(&tx->CompleteMutex); // triggers acessnsr_SendPacket
272 void acessnsr_rx_channel_event_ind(udi_channel_event_cb_t *cb)
276 void acessnsr_rx_ind(udi_nic_rx_cb_t *cb)
278 acessnsr_rdata_t *rdata = UDI_GCB(cb)->context;
279 udi_nic_rx_cb_t *next;
282 Workqueue_AddWork(&rdata->RXQueue, cb);
283 } while( (cb = next) );
285 void acessnsr_rx_exp_ind(udi_nic_rx_cb_t *cb)
291 int acessnsr_SendPacket(void *Card, tIPStackBuffer *Buffer)
293 acessnsr_rdata_t *rdata = Card;
294 LOG("Card=%p,Buffer=%p", Card, Buffer);
295 udi_nic_tx_cb_t *cb = Workqueue_GetWork(&rdata->TXWorkQueue);
297 acessnsr_txdesc_t *tx = UDI_GCB(cb)->scratch;
300 LOG("Mutex acquire #1 %p", cb);
301 Mutex_Acquire(&tx->CompleteMutex);
302 tx->IPBuffer = Buffer;
304 acessnsr_SendPacket__buf_write_complete(UDI_GCB(cb), NULL);
306 // Double lock is resolved once TX is complete
307 Mutex_Acquire(&tx->CompleteMutex);
308 Mutex_Release(&tx->CompleteMutex);
311 LOG("Release %p", cb);
312 Workqueue_AddWork(&rdata->TXWorkQueue, cb);
315 void acessnsr_SendPacket__buf_write_complete(udi_cb_t *gcb, udi_buf_t *buf)
317 acessnsr_txdesc_t *tx = gcb->scratch;
318 udi_nic_tx_cb_t *cb = UDI_MCB(gcb, udi_nic_tx_cb_t);
319 if( tx->BufIdx >= 0 ) {
324 if( (tx->BufIdx = IPStack_Buffer_GetBuffer(tx->IPBuffer, tx->BufIdx, &buflen, &bufptr )) != -1 )
326 Debug_HexDump("NSR", bufptr, buflen);
327 udi_buf_write(acessnsr_SendPacket__buf_write_complete, gcb,
328 bufptr, buflen, cb->tx_buf, (cb->tx_buf ? cb->tx_buf->buf_size : 0), 0, NULL);
334 // continued in acessnsr_tx_rdy
336 void _FreeHeapSubBuf(void *Arg, size_t Pre, size_t Post, const void *DataBuf)
340 tIPStackBuffer *acessnsr_WaitForPacket(void *Card)
342 acessnsr_rdata_t *rdata = Card;
343 udi_nic_rx_cb_t *cb = Workqueue_GetWork(&rdata->RXQueue);
345 tIPStackBuffer *ret = IPStack_Buffer_CreateBuffer(1);
346 void *data = malloc( cb->rx_buf->buf_size );
347 udi_buf_read(cb->rx_buf, 0, cb->rx_buf->buf_size, data);
348 IPStack_Buffer_AppendSubBuffer(ret, cb->rx_buf->buf_size, 0, data, _FreeHeapSubBuf, data);
354 // === UDI Bindings ===
355 udi_mgmt_ops_t acessnsr_mgmt_ops = {
357 udi_enumerate_no_children,
358 acessnsr_devmgmt_req,
359 acessnsr_final_cleanup_req
361 udi_ubit8_t acessnsr_mgmt_ops_flags[4] = {0,0,0,0};
363 udi_primary_init_t acessnsr_pri_init = {
364 .mgmt_ops = &acessnsr_mgmt_ops,
365 .mgmt_op_flags = acessnsr_mgmt_ops_flags,
366 .mgmt_scratch_requirement = 0,
367 .enumeration_attr_list_length = 4,
368 .rdata_size = sizeof(acessnsr_rdata_t),
369 .child_data_size = 0,
370 .per_parent_paths = 0
373 udi_nsr_ctrl_ops_t acessnsr_ctrl_ops = {
374 acessnsr_ctrl_channel_event_ind,
375 acessnsr_ctrl_bind_ack,
376 acessnsr_ctrl_unbind_ack,
377 acessnsr_ctrl_enable_ack,
378 acessnsr_ctrl_ctrl_ack,
379 acessnsr_ctrl_info_ack,
380 acessnsr_ctrl_status_ind
382 udi_ubit8_t acessnsr_ctrl_op_flags[7] = {0};
384 udi_nsr_tx_ops_t acessnsr_tx_ops = {
385 acessnsr_tx_channel_event_ind,
388 udi_ubit8_t acessnsr_tx_ops_flags[2] = {0};
390 udi_nsr_rx_ops_t acessnsr_rx_ops = {
391 acessnsr_rx_channel_event_ind,
395 udi_ubit8_t acessnsr_rx_ops_flags[3] = {0};
397 udi_ops_init_t acessnsr_ops_list[] = {
399 ACESSNSR_OPS_CTRL, ACESSNSR_META_NIC, UDI_NSR_CTRL_OPS_NUM,
400 0, (udi_ops_vector_t*)&acessnsr_ctrl_ops, acessnsr_ctrl_op_flags
403 ACESSNSR_OPS_TX, ACESSNSR_META_NIC, UDI_NSR_TX_OPS_NUM,
404 0, (udi_ops_vector_t*)&acessnsr_tx_ops, acessnsr_tx_ops_flags
407 ACESSNSR_OPS_RX, ACESSNSR_META_NIC, UDI_NSR_RX_OPS_NUM,
408 0, (udi_ops_vector_t*)&acessnsr_rx_ops, acessnsr_rx_ops_flags
412 udi_cb_init_t acessnsr_cb_init_list[] = {
413 {ACESSNSR_CB_CTRL, ACESSNSR_META_NIC, UDI_NIC_BIND_CB_NUM, 0, 0,NULL},
414 {ACESSNSR_CB_RX, ACESSNSR_META_NIC, UDI_NIC_RX_CB_NUM, 0, 0,NULL},
415 {ACESSNSR_CB_TX, ACESSNSR_META_NIC, UDI_NIC_TX_CB_NUM, sizeof(acessnsr_txdesc_t), 0,NULL},
416 {ACESSNSR_CB_STD, ACESSNSR_META_NIC, UDI_NIC_TX_CB_NUM, 0, 0,NULL},
419 const udi_init_t acessnsr_init = {
420 .primary_init_info = &acessnsr_pri_init,
421 .ops_init_list = acessnsr_ops_list,
422 .cb_init_list = acessnsr_cb_init_list,
424 const char acessnsr_udiprops[] =
425 "properties_version 0x101\0"
426 "message 1 Acess2 Kernel\0"
428 "message 3 Acess2 NSR\0"
433 "shortname acessnsr\0"
434 "requires udi 0x101\0"
435 "requires udi_nic 0x101\0"
437 "message 101 Ethernet Adapter\0"
438 "device 101 1 if_media string eth\0"
439 "parent_bind_ops 1 0 1 1\0"
441 size_t acessnsr_udiprops_size = sizeof(acessnsr_udiprops);