Subversion Repositories HelenOS

Rev

Rev 3471 | Only display areas with differences | Ignore whitespace | Details | Blame | Last modification | View Log | RSS feed

Rev 3471 Rev 4692
1
/*
1
/*
2
 * Copyright (c) 2008 Jiri Svoboda
2
 * Copyright (c) 2008 Jiri Svoboda
3
 * All rights reserved.
3
 * All rights reserved.
4
 *
4
 *
5
 * Redistribution and use in source and binary forms, with or without
5
 * Redistribution and use in source and binary forms, with or without
6
 * modification, are permitted provided that the following conditions
6
 * modification, are permitted provided that the following conditions
7
 * are met:
7
 * are met:
8
 *
8
 *
9
 * - Redistributions of source code must retain the above copyright
9
 * - Redistributions of source code must retain the above copyright
10
 *   notice, this list of conditions and the following disclaimer.
10
 *   notice, this list of conditions and the following disclaimer.
11
 * - Redistributions in binary form must reproduce the above copyright
11
 * - Redistributions in binary form must reproduce the above copyright
12
 *   notice, this list of conditions and the following disclaimer in the
12
 *   notice, this list of conditions and the following disclaimer in the
13
 *   documentation and/or other materials provided with the distribution.
13
 *   documentation and/or other materials provided with the distribution.
14
 * - The name of the author may not be used to endorse or promote products
14
 * - The name of the author may not be used to endorse or promote products
15
 *   derived from this software without specific prior written permission.
15
 *   derived from this software without specific prior written permission.
16
 *
16
 *
17
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
17
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18
 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
18
 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
19
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20
 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
20
 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
21
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22
 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
22
 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
23
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
25
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26
 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26
 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27
 */
27
 */
28
 
28
 
29
/** @addtogroup trace
29
/** @addtogroup trace
30
 * @{
30
 * @{
31
 */
31
 */
32
/** @file
32
/** @file
33
 */
33
 */
34
 
34
 
35
#include <stdio.h>
35
#include <stdio.h>
36
#include <stdlib.h>
36
#include <stdlib.h>
37
#include <libadt/hash_table.h>
37
#include <adt/hash_table.h>
38
 
38
 
39
#include "ipc_desc.h"
39
#include "ipc_desc.h"
40
#include "proto.h"
40
#include "proto.h"
41
#include "trace.h"
41
#include "trace.h"
42
#include "ipcp.h"
42
#include "ipcp.h"
43
 
43
 
44
#define IPCP_CALLID_SYNC 0
44
#define IPCP_CALLID_SYNC 0
45
 
45
 
46
typedef struct {
46
typedef struct {
47
    ipcarg_t phone_hash;
47
    ipcarg_t phone_hash;
48
    ipc_call_t question;
48
    ipc_call_t question;
49
    oper_t *oper;
49
    oper_t *oper;
50
 
50
 
51
    ipc_callid_t call_hash;
51
    ipc_callid_t call_hash;
52
 
52
 
53
    link_t link;
53
    link_t link;
54
} pending_call_t;
54
} pending_call_t;
55
 
55
 
56
typedef struct {
56
typedef struct {
57
    int server;
57
    int server;
58
    proto_t *proto;
58
    proto_t *proto;
59
} connection_t;
59
} connection_t;
60
 
60
 
61
#define MAX_PHONE 64
61
#define MAX_PHONE 64
62
connection_t connections[MAX_PHONE];
62
connection_t connections[MAX_PHONE];
63
int have_conn[MAX_PHONE];
63
int have_conn[MAX_PHONE];
64
 
64
 
65
#define PCALL_TABLE_CHAINS 32
65
#define PCALL_TABLE_CHAINS 32
66
hash_table_t pending_calls;
66
hash_table_t pending_calls;
67
 
67
 
68
/*
68
/*
69
 * Pseudo-protocols
69
 * Pseudo-protocols
70
 */
70
 */
71
proto_t *proto_system;      /**< Protocol describing system IPC methods. */
71
proto_t *proto_system;      /**< Protocol describing system IPC methods. */
72
proto_t *proto_unknown;     /**< Protocol with no known methods. */
72
proto_t *proto_unknown;     /**< Protocol with no known methods. */
73
 
73
 
74
static hash_index_t pending_call_hash(unsigned long key[]);
74
static hash_index_t pending_call_hash(unsigned long key[]);
75
static int pending_call_compare(unsigned long key[], hash_count_t keys,
75
static int pending_call_compare(unsigned long key[], hash_count_t keys,
76
    link_t *item);
76
    link_t *item);
77
static void pending_call_remove_callback(link_t *item);
77
static void pending_call_remove_callback(link_t *item);
78
 
78
 
79
hash_table_operations_t pending_call_ops = {
79
hash_table_operations_t pending_call_ops = {
80
    .hash = pending_call_hash,
80
    .hash = pending_call_hash,
81
    .compare = pending_call_compare,
81
    .compare = pending_call_compare,
82
    .remove_callback = pending_call_remove_callback
82
    .remove_callback = pending_call_remove_callback
83
};
83
};
84
 
84
 
85
 
85
 
86
static hash_index_t pending_call_hash(unsigned long key[])
86
static hash_index_t pending_call_hash(unsigned long key[])
87
{
87
{
88
//  printf("pending_call_hash\n");
88
//  printf("pending_call_hash\n");
89
    return key[0] % PCALL_TABLE_CHAINS;
89
    return key[0] % PCALL_TABLE_CHAINS;
90
}
90
}
91
 
91
 
92
static int pending_call_compare(unsigned long key[], hash_count_t keys,
92
static int pending_call_compare(unsigned long key[], hash_count_t keys,
93
    link_t *item)
93
    link_t *item)
94
{
94
{
95
    pending_call_t *hs;
95
    pending_call_t *hs;
96
 
96
 
97
//  printf("pending_call_compare\n");
97
//  printf("pending_call_compare\n");
98
    hs = hash_table_get_instance(item, pending_call_t, link);
98
    hs = hash_table_get_instance(item, pending_call_t, link);
99
 
99
 
100
    // FIXME: this will fail if sizeof(long) < sizeof(void *).
100
    // FIXME: this will fail if sizeof(long) < sizeof(void *).
101
    return key[0] == hs->call_hash;
101
    return key[0] == hs->call_hash;
102
}
102
}
103
 
103
 
104
static void pending_call_remove_callback(link_t *item)
104
static void pending_call_remove_callback(link_t *item)
105
{
105
{
106
//  printf("pending_call_remove_callback\n");
106
//  printf("pending_call_remove_callback\n");
107
}
107
}
108
 
108
 
109
 
109
 
110
void ipcp_connection_set(int phone, int server, proto_t *proto)
110
void ipcp_connection_set(int phone, int server, proto_t *proto)
111
{
111
{
112
    if (phone <0 || phone >= MAX_PHONE) return;
112
    if (phone <0 || phone >= MAX_PHONE) return;
113
    connections[phone].server = server;
113
    connections[phone].server = server;
114
    connections[phone].proto = proto;
114
    connections[phone].proto = proto;
115
    have_conn[phone] = 1;
115
    have_conn[phone] = 1;
116
}
116
}
117
 
117
 
118
void ipcp_connection_clear(int phone)
118
void ipcp_connection_clear(int phone)
119
{
119
{
120
    have_conn[phone] = 0;
120
    have_conn[phone] = 0;
121
    connections[phone].server = 0;
121
    connections[phone].server = 0;
122
    connections[phone].proto = NULL;
122
    connections[phone].proto = NULL;
123
}
123
}
124
 
124
 
125
static void ipc_m_print(proto_t *proto, ipcarg_t method)
125
static void ipc_m_print(proto_t *proto, ipcarg_t method)
126
{
126
{
127
    oper_t *oper;
127
    oper_t *oper;
128
 
128
 
129
    /* Try system methods first */
129
    /* Try system methods first */
130
    oper = proto_get_oper(proto_system, method);
130
    oper = proto_get_oper(proto_system, method);
131
 
131
 
132
    if (oper == NULL && proto != NULL) {
132
    if (oper == NULL && proto != NULL) {
133
        /* Not a system method, try the user protocol. */
133
        /* Not a system method, try the user protocol. */
134
        oper = proto_get_oper(proto, method);
134
        oper = proto_get_oper(proto, method);
135
    }
135
    }
136
 
136
 
137
    if (oper != NULL) {
137
    if (oper != NULL) {
138
        printf("%s (%ld)", oper->name, method);
138
        printf("%s (%ld)", oper->name, method);
139
        return;
139
        return;
140
    }
140
    }
141
 
141
 
142
    printf("%ld", method);
142
    printf("%ld", method);
143
}
143
}
144
 
144
 
145
void ipcp_init(void)
145
void ipcp_init(void)
146
{
146
{
147
    ipc_m_desc_t *desc;
147
    ipc_m_desc_t *desc;
148
    oper_t *oper;
148
    oper_t *oper;
149
 
149
 
150
    val_type_t arg_def[OPER_MAX_ARGS] = {
150
    val_type_t arg_def[OPER_MAX_ARGS] = {
151
        V_INTEGER,
151
        V_INTEGER,
152
        V_INTEGER,
152
        V_INTEGER,
153
        V_INTEGER,
153
        V_INTEGER,
154
        V_INTEGER,
154
        V_INTEGER,
155
        V_INTEGER      
155
        V_INTEGER      
156
    };
156
    };
157
 
157
 
158
    /*
158
    /*
159
     * Create a pseudo-protocol 'unknown' that has no known methods.
159
     * Create a pseudo-protocol 'unknown' that has no known methods.
160
     */
160
     */
161
    proto_unknown = proto_new("unknown");
161
    proto_unknown = proto_new("unknown");
162
 
162
 
163
    /*
163
    /*
164
     * Create a pseudo-protocol 'system' defining names of system IPC
164
     * Create a pseudo-protocol 'system' defining names of system IPC
165
     * methods.
165
     * methods.
166
     */
166
     */
167
    proto_system = proto_new("system");
167
    proto_system = proto_new("system");
168
 
168
 
169
    desc = ipc_methods;
169
    desc = ipc_methods;
170
    while (desc->number != 0) {
170
    while (desc->number != 0) {
171
        oper = oper_new(desc->name, OPER_MAX_ARGS, arg_def, V_INTEGER,
171
        oper = oper_new(desc->name, OPER_MAX_ARGS, arg_def, V_INTEGER,
172
            OPER_MAX_ARGS, arg_def);
172
            OPER_MAX_ARGS, arg_def);
173
        proto_add_oper(proto_system, desc->number, oper);
173
        proto_add_oper(proto_system, desc->number, oper);
174
 
174
 
175
        ++desc;
175
        ++desc;
176
    }
176
    }
177
 
177
 
178
    hash_table_create(&pending_calls, PCALL_TABLE_CHAINS, 1, &pending_call_ops);
178
    hash_table_create(&pending_calls, PCALL_TABLE_CHAINS, 1, &pending_call_ops);
179
}
179
}
180
 
180
 
181
void ipcp_cleanup(void)
181
void ipcp_cleanup(void)
182
{
182
{
183
    proto_delete(proto_system);
183
    proto_delete(proto_system);
184
    hash_table_destroy(&pending_calls);
184
    hash_table_destroy(&pending_calls);
185
}
185
}
186
 
186
 
187
void ipcp_call_out(int phone, ipc_call_t *call, ipc_callid_t hash)
187
void ipcp_call_out(int phone, ipc_call_t *call, ipc_callid_t hash)
188
{
188
{
189
    pending_call_t *pcall;
189
    pending_call_t *pcall;
190
    proto_t *proto;
190
    proto_t *proto;
191
    unsigned long key[1];
191
    unsigned long key[1];
192
    oper_t *oper;
192
    oper_t *oper;
193
    ipcarg_t *args;
193
    ipcarg_t *args;
194
    int i;
194
    int i;
195
 
195
 
196
    if (have_conn[phone]) proto = connections[phone].proto;
196
    if (have_conn[phone]) proto = connections[phone].proto;
197
    else proto = NULL;
197
    else proto = NULL;
198
 
198
 
199
    args = call->args;
199
    args = call->args;
200
 
200
 
201
    if ((display_mask & DM_IPC) != 0) {
201
    if ((display_mask & DM_IPC) != 0) {
202
        printf("Call ID: 0x%lx, phone: %d, proto: %s, method: ", hash,
202
        printf("Call ID: 0x%lx, phone: %d, proto: %s, method: ", hash,
203
            phone, (proto ? proto->name : "n/a"));
203
            phone, (proto ? proto->name : "n/a"));
204
        ipc_m_print(proto, IPC_GET_METHOD(*call));
204
        ipc_m_print(proto, IPC_GET_METHOD(*call));
205
        printf(" args: (%lu, %lu, %lu, %lu, %lu)\n", args[1], args[2],
205
        printf(" args: (%lu, %lu, %lu, %lu, %lu)\n", args[1], args[2],
206
            args[3], args[4], args[5]);
206
            args[3], args[4], args[5]);
207
    }
207
    }
208
 
208
 
209
 
209
 
210
    if ((display_mask & DM_USER) != 0) {
210
    if ((display_mask & DM_USER) != 0) {
211
 
211
 
212
        if (proto != NULL) {
212
        if (proto != NULL) {
213
            oper = proto_get_oper(proto, IPC_GET_METHOD(*call));
213
            oper = proto_get_oper(proto, IPC_GET_METHOD(*call));
214
        } else {
214
        } else {
215
            oper = NULL;
215
            oper = NULL;
216
        }
216
        }
217
 
217
 
218
        if (oper != NULL) {
218
        if (oper != NULL) {
219
 
219
 
220
            printf("%s(%d).%s", (proto ? proto->name : "n/a"),
220
            printf("%s(%d).%s", (proto ? proto->name : "n/a"),
221
                phone, (oper ? oper->name : "unknown"));
221
                phone, (oper ? oper->name : "unknown"));
222
 
222
 
223
            putchar('(');
223
            putchar('(');
224
            for (i = 1; i <= oper->argc; ++i) {
224
            for (i = 1; i <= oper->argc; ++i) {
225
                if (i > 1) printf(", ");
225
                if (i > 1) printf(", ");
226
                val_print(args[i], oper->arg_type[i - 1]);
226
                val_print(args[i], oper->arg_type[i - 1]);
227
            }
227
            }
228
            putchar(')');
228
            putchar(')');
229
 
229
 
230
            if (oper->rv_type == V_VOID && oper->respc == 0) {
230
            if (oper->rv_type == V_VOID && oper->respc == 0) {
231
                /*
231
                /*
232
                 * No response data (typically the task will
232
                 * No response data (typically the task will
233
                 * not be interested in the response).
233
                 * not be interested in the response).
234
                 * We will not display response.
234
                 * We will not display response.
235
                 */
235
                 */
236
                putchar('.');
236
                putchar('.');
237
            }
237
            }
238
 
238
 
239
            putchar('\n');
239
            putchar('\n');
240
        }
240
        }
241
    } else {
241
    } else {
242
        oper = NULL;
242
        oper = NULL;
243
    }
243
    }
244
 
244
 
245
    /* Store call in hash table for response matching */
245
    /* Store call in hash table for response matching */
246
 
246
 
247
    pcall = malloc(sizeof(pending_call_t));
247
    pcall = malloc(sizeof(pending_call_t));
248
    pcall->phone_hash = phone;
248
    pcall->phone_hash = phone;
249
    pcall->question = *call;
249
    pcall->question = *call;
250
    pcall->call_hash = hash;
250
    pcall->call_hash = hash;
251
    pcall->oper = oper;
251
    pcall->oper = oper;
252
 
252
 
253
    key[0] = hash;
253
    key[0] = hash;
254
 
254
 
255
    hash_table_insert(&pending_calls, key, &pcall->link);
255
    hash_table_insert(&pending_calls, key, &pcall->link);
256
}
256
}
257
 
257
 
258
static void parse_answer(ipc_callid_t hash, pending_call_t *pcall,
258
static void parse_answer(ipc_callid_t hash, pending_call_t *pcall,
259
    ipc_call_t *answer)
259
    ipc_call_t *answer)
260
{
260
{
261
    ipcarg_t phone;
261
    ipcarg_t phone;
262
    ipcarg_t method;
262
    ipcarg_t method;
263
    ipcarg_t service;
263
    ipcarg_t service;
264
    ipcarg_t retval;
264
    ipcarg_t retval;
265
    proto_t *proto;
265
    proto_t *proto;
266
    int cphone;
266
    int cphone;
267
 
267
 
268
    ipcarg_t *resp;
268
    ipcarg_t *resp;
269
    oper_t *oper;
269
    oper_t *oper;
270
    int i;
270
    int i;
271
 
271
 
272
//  printf("parse_answer\n");
272
//  printf("parse_answer\n");
273
 
273
 
274
    phone = pcall->phone_hash;
274
    phone = pcall->phone_hash;
275
    method = IPC_GET_METHOD(pcall->question);
275
    method = IPC_GET_METHOD(pcall->question);
276
    retval = IPC_GET_RETVAL(*answer);
276
    retval = IPC_GET_RETVAL(*answer);
277
 
277
 
278
    resp = answer->args;
278
    resp = answer->args;
279
 
279
 
280
    if ((display_mask & DM_IPC) != 0) {
280
    if ((display_mask & DM_IPC) != 0) {
281
        printf("Response to 0x%lx: retval=%ld, args = (%lu, %lu, %lu, %lu, %lu)\n",
281
        printf("Response to 0x%lx: retval=%ld, args = (%lu, %lu, %lu, %lu, %lu)\n",
282
            hash, retval, IPC_GET_ARG1(*answer),
282
            hash, retval, IPC_GET_ARG1(*answer),
283
            IPC_GET_ARG2(*answer), IPC_GET_ARG3(*answer),
283
            IPC_GET_ARG2(*answer), IPC_GET_ARG3(*answer),
284
            IPC_GET_ARG4(*answer), IPC_GET_ARG5(*answer));
284
            IPC_GET_ARG4(*answer), IPC_GET_ARG5(*answer));
285
    }
285
    }
286
 
286
 
287
    if ((display_mask & DM_USER) != 0) {
287
    if ((display_mask & DM_USER) != 0) {
288
        oper = pcall->oper;
288
        oper = pcall->oper;
289
 
289
 
290
        if (oper != NULL && (oper->rv_type != V_VOID || oper->respc > 0)) {
290
        if (oper != NULL && (oper->rv_type != V_VOID || oper->respc > 0)) {
291
            printf("->");
291
            printf("->");
292
 
292
 
293
            if (oper->rv_type != V_VOID) {
293
            if (oper->rv_type != V_VOID) {
294
                putchar(' ');
294
                putchar(' ');
295
                val_print(retval, oper->rv_type);
295
                val_print(retval, oper->rv_type);
296
            }
296
            }
297
           
297
           
298
            if (oper->respc > 0) {
298
            if (oper->respc > 0) {
299
                putchar(' ');
299
                putchar(' ');
300
                putchar('(');
300
                putchar('(');
301
                for (i = 1; i <= oper->respc; ++i) {
301
                for (i = 1; i <= oper->respc; ++i) {
302
                    if (i > 1) printf(", ");
302
                    if (i > 1) printf(", ");
303
                    val_print(resp[i], oper->resp_type[i - 1]);
303
                    val_print(resp[i], oper->resp_type[i - 1]);
304
                }
304
                }
305
                putchar(')');
305
                putchar(')');
306
            }
306
            }
307
 
307
 
308
            putchar('\n');
308
            putchar('\n');
309
        }
309
        }
310
    }
310
    }
311
 
311
 
312
    if (phone == 0 && method == IPC_M_CONNECT_ME_TO && retval == 0) {
312
    if (phone == 0 && method == IPC_M_CONNECT_ME_TO && retval == 0) {
313
        /* Connected to a service (through NS) */
313
        /* Connected to a service (through NS) */
314
        service = IPC_GET_ARG1(pcall->question);
314
        service = IPC_GET_ARG1(pcall->question);
315
        proto = proto_get_by_srv(service);
315
        proto = proto_get_by_srv(service);
316
        if (proto == NULL) proto = proto_unknown;
316
        if (proto == NULL) proto = proto_unknown;
317
 
317
 
318
        cphone = IPC_GET_ARG5(*answer);
318
        cphone = IPC_GET_ARG5(*answer);
319
        if ((display_mask & DM_SYSTEM) != 0) {
319
        if ((display_mask & DM_SYSTEM) != 0) {
320
            printf("Registering connection (phone %d, protocol: %s)\n", cphone,
320
            printf("Registering connection (phone %d, protocol: %s)\n", cphone,
321
                    proto->name);
321
                    proto->name);
322
        }
322
        }
323
        ipcp_connection_set(cphone, 0, proto);
323
        ipcp_connection_set(cphone, 0, proto);
324
    }
324
    }
325
}
325
}
326
 
326
 
327
void ipcp_call_in(ipc_call_t *call, ipc_callid_t hash)
327
void ipcp_call_in(ipc_call_t *call, ipc_callid_t hash)
328
{
328
{
329
    link_t *item;
329
    link_t *item;
330
    pending_call_t *pcall;
330
    pending_call_t *pcall;
331
    unsigned long key[1];
331
    unsigned long key[1];
332
 
332
 
333
//  printf("ipcp_call_in()\n");
333
//  printf("ipcp_call_in()\n");
334
 
334
 
335
    if ((hash & IPC_CALLID_ANSWERED) == 0 && hash != IPCP_CALLID_SYNC) {
335
    if ((hash & IPC_CALLID_ANSWERED) == 0 && hash != IPCP_CALLID_SYNC) {
336
        /* Not a response */
336
        /* Not a response */
337
        if ((display_mask & DM_IPC) != 0) {
337
        if ((display_mask & DM_IPC) != 0) {
338
            printf("Not a response (hash 0x%lx)\n", hash);
338
            printf("Not a response (hash 0x%lx)\n", hash);
339
        }
339
        }
340
        return;
340
        return;
341
    }
341
    }
342
 
342
 
343
    hash = hash & ~IPC_CALLID_ANSWERED;
343
    hash = hash & ~IPC_CALLID_ANSWERED;
344
    key[0] = hash;
344
    key[0] = hash;
345
 
345
 
346
    item = hash_table_find(&pending_calls, key);
346
    item = hash_table_find(&pending_calls, key);
347
    if (item == NULL) return; // No matching question found
347
    if (item == NULL) return; // No matching question found
348
 
348
 
349
    /*
349
    /*
350
     * Response matched to question.
350
     * Response matched to question.
351
     */
351
     */
352
   
352
   
353
    pcall = hash_table_get_instance(item, pending_call_t, link);
353
    pcall = hash_table_get_instance(item, pending_call_t, link);
354
    hash_table_remove(&pending_calls, key, 1);
354
    hash_table_remove(&pending_calls, key, 1);
355
 
355
 
356
    parse_answer(hash, pcall, call);
356
    parse_answer(hash, pcall, call);
357
    free(pcall);
357
    free(pcall);
358
}
358
}
359
 
359
 
360
void ipcp_call_sync(int phone, ipc_call_t *call, ipc_call_t *answer)
360
void ipcp_call_sync(int phone, ipc_call_t *call, ipc_call_t *answer)
361
{
361
{
362
    ipcp_call_out(phone, call, IPCP_CALLID_SYNC);
362
    ipcp_call_out(phone, call, IPCP_CALLID_SYNC);
363
    ipcp_call_in(answer, IPCP_CALLID_SYNC);
363
    ipcp_call_in(answer, IPCP_CALLID_SYNC);
364
}
364
}
365
 
365
 
366
void ipcp_hangup(int phone, int rc)
366
void ipcp_hangup(int phone, int rc)
367
{
367
{
368
    if ((display_mask & DM_SYSTEM) != 0) {
368
    if ((display_mask & DM_SYSTEM) != 0) {
369
        printf("Hang phone %d up -> %d\n", phone, rc);
369
        printf("Hang phone %d up -> %d\n", phone, rc);
370
        ipcp_connection_clear(phone);
370
        ipcp_connection_clear(phone);
371
    }
371
    }
372
}
372
}
373
 
373
 
374
/** @}
374
/** @}
375
 */
375
 */
376
 
376