Subversion Repositories HelenOS

Rev

Rev 3444 | Rev 3454 | Go to most recent revision | Only display areas with differences | Ignore whitespace | Details | Blame | Last modification | View Log | RSS feed

Rev 3444 Rev 3452
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 <libadt/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
    int phone_hash;
47
    int phone_hash;
48
    ipc_call_t question;
48
    ipc_call_t question;
-
 
49
    oper_t *oper;
49
 
50
 
50
    int call_hash;
51
    int call_hash;
51
 
52
 
52
    link_t link;
53
    link_t link;
53
} pending_call_t;
54
} pending_call_t;
54
 
55
 
55
typedef struct {
56
typedef struct {
56
    int server;
57
    int server;
57
    proto_t *proto;
58
    proto_t *proto;
58
} connection_t;
59
} connection_t;
59
 
60
 
60
#define MAX_PHONE 64
61
#define MAX_PHONE 64
61
connection_t connections[MAX_PHONE];
62
connection_t connections[MAX_PHONE];
62
int have_conn[MAX_PHONE];
63
int have_conn[MAX_PHONE];
63
 
64
 
64
#define PCALL_TABLE_CHAINS 32
65
#define PCALL_TABLE_CHAINS 32
65
hash_table_t pending_calls;
66
hash_table_t pending_calls;
66
 
67
 
67
/*
68
/*
68
 * Pseudo-protocols
69
 * Pseudo-protocols
69
 */
70
 */
70
proto_t *proto_system;      /**< Protocol describing system IPC methods. */
71
proto_t *proto_system;      /**< Protocol describing system IPC methods. */
71
proto_t *proto_unknown;     /**< Protocol with no known methods. */
72
proto_t *proto_unknown;     /**< Protocol with no known methods. */
72
 
73
 
73
static hash_index_t pending_call_hash(unsigned long key[]);
74
static hash_index_t pending_call_hash(unsigned long key[]);
74
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,
75
    link_t *item);
76
    link_t *item);
76
static void pending_call_remove_callback(link_t *item);
77
static void pending_call_remove_callback(link_t *item);
77
 
78
 
78
hash_table_operations_t pending_call_ops = {
79
hash_table_operations_t pending_call_ops = {
79
    .hash = pending_call_hash,
80
    .hash = pending_call_hash,
80
    .compare = pending_call_compare,
81
    .compare = pending_call_compare,
81
    .remove_callback = pending_call_remove_callback
82
    .remove_callback = pending_call_remove_callback
82
};
83
};
83
 
84
 
84
 
85
 
85
static hash_index_t pending_call_hash(unsigned long key[])
86
static hash_index_t pending_call_hash(unsigned long key[])
86
{
87
{
87
//  printf("pending_call_hash\n");
88
//  printf("pending_call_hash\n");
88
    return key[0] % PCALL_TABLE_CHAINS;
89
    return key[0] % PCALL_TABLE_CHAINS;
89
}
90
}
90
 
91
 
91
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,
92
    link_t *item)
93
    link_t *item)
93
{
94
{
94
    pending_call_t *hs;
95
    pending_call_t *hs;
95
 
96
 
96
//  printf("pending_call_compare\n");
97
//  printf("pending_call_compare\n");
97
    hs = hash_table_get_instance(item, pending_call_t, link);
98
    hs = hash_table_get_instance(item, pending_call_t, link);
98
 
99
 
99
    return key[0] == hs->call_hash;
100
    return key[0] == hs->call_hash;
100
}
101
}
101
 
102
 
102
static void pending_call_remove_callback(link_t *item)
103
static void pending_call_remove_callback(link_t *item)
103
{
104
{
104
//  printf("pending_call_remove_callback\n");
105
//  printf("pending_call_remove_callback\n");
105
}
106
}
106
 
107
 
107
 
108
 
108
void ipcp_connection_set(int phone, int server, proto_t *proto)
109
void ipcp_connection_set(int phone, int server, proto_t *proto)
109
{
110
{
110
    if (phone <0 || phone >= MAX_PHONE) return;
111
    if (phone <0 || phone >= MAX_PHONE) return;
111
    connections[phone].server = server;
112
    connections[phone].server = server;
112
    connections[phone].proto = proto;
113
    connections[phone].proto = proto;
113
    have_conn[phone] = 1;
114
    have_conn[phone] = 1;
114
}
115
}
115
 
116
 
116
void ipcp_connection_clear(int phone)
117
void ipcp_connection_clear(int phone)
117
{
118
{
118
    have_conn[phone] = 0;
119
    have_conn[phone] = 0;
119
    connections[phone].server = 0;
120
    connections[phone].server = 0;
120
    connections[phone].proto = NULL;
121
    connections[phone].proto = NULL;
121
}
122
}
122
 
123
 
123
static void ipc_m_print(proto_t *proto, ipcarg_t method)
124
static void ipc_m_print(proto_t *proto, ipcarg_t method)
124
{
125
{
125
    oper_t *oper;
126
    oper_t *oper;
126
 
127
 
127
    /* Try system methods first */
128
    /* Try system methods first */
128
    oper = proto_get_oper(proto_system, method);
129
    oper = proto_get_oper(proto_system, method);
129
 
130
 
130
    if (oper == NULL && proto != NULL) {
131
    if (oper == NULL && proto != NULL) {
131
        /* Not a system method, try the user protocol. */
132
        /* Not a system method, try the user protocol. */
132
        oper = proto_get_oper(proto, method);
133
        oper = proto_get_oper(proto, method);
133
    }
134
    }
134
 
135
 
135
    if (oper != NULL) {
136
    if (oper != NULL) {
136
        printf("%s (%d)", oper->name, method);
137
        printf("%s (%d)", oper->name, method);
137
        return;
138
        return;
138
    }
139
    }
139
 
140
 
140
    printf("%d", method);
141
    printf("%d", method);
141
}
142
}
142
 
143
 
143
void ipcp_init(void)
144
void ipcp_init(void)
144
{
145
{
145
    ipc_m_desc_t *desc;
146
    ipc_m_desc_t *desc;
146
    oper_t *oper;
147
    oper_t *oper;
147
 
148
 
-
 
149
    val_type_t arg_def[OPER_MAX_ARGS] = {
-
 
150
        V_INTEGER,
-
 
151
        V_INTEGER,
-
 
152
        V_INTEGER,
-
 
153
        V_INTEGER,
-
 
154
        V_INTEGER      
-
 
155
    };
-
 
156
 
148
    /*
157
    /*
149
     * Create a pseudo-protocol 'unknown' that has no known methods.
158
     * Create a pseudo-protocol 'unknown' that has no known methods.
150
     */
159
     */
151
    proto_unknown = proto_new("unknown");
160
    proto_unknown = proto_new("unknown");
152
 
161
 
153
    /*
162
    /*
154
     * Create a pseudo-protocol 'system' defining names of system IPC
163
     * Create a pseudo-protocol 'system' defining names of system IPC
155
     * methods.
164
     * methods.
156
     */
165
     */
157
    proto_system = proto_new("system");
166
    proto_system = proto_new("system");
158
 
167
 
159
    desc = ipc_methods;
168
    desc = ipc_methods;
160
    while (desc->number != 0) {
169
    while (desc->number != 0) {
161
        oper = oper_new(desc->name);
170
        oper = oper_new(desc->name, OPER_MAX_ARGS, arg_def, V_INTEGER,
-
 
171
            OPER_MAX_ARGS, arg_def);
162
        proto_add_oper(proto_system, desc->number, oper);
172
        proto_add_oper(proto_system, desc->number, oper);
163
 
173
 
164
        ++desc;
174
        ++desc;
165
    }
175
    }
166
 
176
 
167
    hash_table_create(&pending_calls, PCALL_TABLE_CHAINS, 1, &pending_call_ops);
177
    hash_table_create(&pending_calls, PCALL_TABLE_CHAINS, 1, &pending_call_ops);
168
}
178
}
169
 
179
 
170
void ipcp_cleanup(void)
180
void ipcp_cleanup(void)
171
{
181
{
172
    proto_delete(proto_system);
182
    proto_delete(proto_system);
173
    hash_table_destroy(&pending_calls);
183
    hash_table_destroy(&pending_calls);
174
}
184
}
175
 
185
 
176
void ipcp_call_out(int phone, ipc_call_t *call, ipc_callid_t hash)
186
void ipcp_call_out(int phone, ipc_call_t *call, ipc_callid_t hash)
177
{
187
{
178
    pending_call_t *pcall;
188
    pending_call_t *pcall;
179
    proto_t *proto;
189
    proto_t *proto;
180
    unsigned long key[1];
190
    unsigned long key[1];
181
    oper_t *oper;
191
    oper_t *oper;
-
 
192
    ipcarg_t *args;
-
 
193
    int i;
182
 
194
 
183
    if (have_conn[phone]) proto = connections[phone].proto;
195
    if (have_conn[phone]) proto = connections[phone].proto;
184
    else proto = NULL;
196
    else proto = NULL;
185
 
197
 
-
 
198
    args = call->args;
-
 
199
 
186
    if ((display_mask & DM_IPC) != 0) {
200
    if ((display_mask & DM_IPC) != 0) {
187
        printf("Call ID: 0x%x, phone: %d, proto: %s, method: ", hash,
201
        printf("Call ID: 0x%x, phone: %d, proto: %s, method: ", hash,
188
            phone, (proto ? proto->name : "n/a"));
202
            phone, (proto ? proto->name : "n/a"));
189
        ipc_m_print(proto, IPC_GET_METHOD(*call));
203
        ipc_m_print(proto, IPC_GET_METHOD(*call));
190
        printf(" args: (%u, %u, %u, %u, %u)\n",
204
        printf(" args: (%u, %u, %u, %u, %u)\n", args[1], args[2],
191
            IPC_GET_ARG1(*call),
-
 
192
            IPC_GET_ARG2(*call),
-
 
193
            IPC_GET_ARG3(*call),
-
 
194
            IPC_GET_ARG4(*call),
205
            args[3], args[4], args[5]);
195
            IPC_GET_ARG5(*call)
-
 
196
        );
-
 
197
    }
206
    }
198
 
207
 
199
 
208
 
200
    if ((display_mask & DM_USER) != 0) {
209
    if ((display_mask & DM_USER) != 0) {
201
 
210
 
202
        if (proto != NULL) {
211
        if (proto != NULL) {
203
            oper = proto_get_oper(proto, IPC_GET_METHOD(*call));
212
            oper = proto_get_oper(proto, IPC_GET_METHOD(*call));
204
        } else {
213
        } else {
205
            oper = NULL;
214
            oper = NULL;
206
        }
215
        }
207
 
216
 
208
        if (oper != NULL) {
217
        if (oper != NULL) {
209
 
218
 
210
            printf("%s(%d).%s", (proto ? proto->name : "n/a"),
219
            printf("%s(%d).%s", (proto ? proto->name : "n/a"),
211
                phone, (oper ? oper->name : "unknown"));
220
                phone, (oper ? oper->name : "unknown"));
212
 
221
 
-
 
222
            putchar('(');
213
            printf("(%u, %u, %u, %u, %u)\n",
223
            for (i = 1; i <= oper->argc; ++i) {
214
                IPC_GET_ARG1(*call),
224
                if (i > 1) printf(", ");
-
 
225
                val_print(args[i], oper->arg_type[i - 1]);
-
 
226
            }
215
                IPC_GET_ARG2(*call),
227
            putchar(')');
-
 
228
 
-
 
229
            if (oper->rv_type == V_VOID && oper->respc == 0) {
-
 
230
                /*
-
 
231
                 * No response data (typically the task will
216
                IPC_GET_ARG3(*call),
232
                 * not be interested in the response).
217
                IPC_GET_ARG4(*call),
233
                 * We will not display response.
-
 
234
                 */
218
                IPC_GET_ARG5(*call)
235
                putchar('.');
219
            );
236
            }
-
 
237
 
-
 
238
            putchar('\n');
220
        }
239
        }
-
 
240
    } else {
-
 
241
        oper = NULL;
221
    }
242
    }
222
 
243
 
223
    /* Store call in hash table for response matching */
244
    /* Store call in hash table for response matching */
224
 
245
 
225
    pcall = malloc(sizeof(pending_call_t));
246
    pcall = malloc(sizeof(pending_call_t));
226
    pcall->phone_hash = phone;
247
    pcall->phone_hash = phone;
227
    pcall->question = *call;
248
    pcall->question = *call;
228
    pcall->call_hash = hash;
249
    pcall->call_hash = hash;
-
 
250
    pcall->oper = oper;
229
 
251
 
230
    key[0] = hash;
252
    key[0] = hash;
231
 
253
 
232
    hash_table_insert(&pending_calls, key, &pcall->link);
254
    hash_table_insert(&pending_calls, key, &pcall->link);
233
}
255
}
234
 
256
 
235
static void parse_answer(ipc_callid_t hash, pending_call_t *pcall,
257
static void parse_answer(ipc_callid_t hash, pending_call_t *pcall,
236
    ipc_call_t *answer)
258
    ipc_call_t *answer)
237
{
259
{
238
    int phone;
260
    int phone;
239
    ipcarg_t method;
261
    ipcarg_t method;
240
    ipcarg_t service;
262
    ipcarg_t service;
241
    int retval;
263
    int retval;
242
    proto_t *proto;
264
    proto_t *proto;
243
    int cphone;
265
    int cphone;
244
 
266
 
-
 
267
    ipcarg_t *resp;
-
 
268
    oper_t *oper;
-
 
269
    int i;
-
 
270
 
245
//  printf("parse_answer\n");
271
//  printf("parse_answer\n");
246
 
272
 
247
    phone = pcall->phone_hash;
273
    phone = pcall->phone_hash;
248
    method = IPC_GET_METHOD(pcall->question);
274
    method = IPC_GET_METHOD(pcall->question);
249
    retval = IPC_GET_RETVAL(*answer);
275
    retval = IPC_GET_RETVAL(*answer);
250
 
276
 
-
 
277
    resp = answer->args;
-
 
278
 
251
    if ((display_mask & DM_IPC) != 0) {
279
    if ((display_mask & DM_IPC) != 0) {
252
        printf("Response to 0x%x: retval=%d, args = (%u, %u, %u, %u, %u)\n",
280
        printf("Response to 0x%x: retval=%d, args = (%u, %u, %u, %u, %u)\n",
253
            hash, retval, IPC_GET_ARG1(*answer),
281
            hash, retval, IPC_GET_ARG1(*answer),
254
            IPC_GET_ARG2(*answer), IPC_GET_ARG3(*answer),
282
            IPC_GET_ARG2(*answer), IPC_GET_ARG3(*answer),
255
            IPC_GET_ARG4(*answer), IPC_GET_ARG5(*answer));
283
            IPC_GET_ARG4(*answer), IPC_GET_ARG5(*answer));
256
    }
284
    }
257
 
285
 
258
    if ((display_mask & DM_USER) != 0) {
286
    if ((display_mask & DM_USER) != 0) {
-
 
287
        oper = pcall->oper;
-
 
288
 
-
 
289
        if (oper->rv_type != V_VOID || oper->respc > 0) {
259
        printf("-> %d\n", retval);
290
            printf("->");
-
 
291
 
-
 
292
            if (oper->rv_type != V_VOID) {
-
 
293
                putchar(' ');
-
 
294
                val_print(retval, oper->rv_type);
-
 
295
            }
-
 
296
           
-
 
297
            if (oper->respc > 0) {
-
 
298
                putchar(' ');
-
 
299
                putchar('(');
-
 
300
                for (i = 1; i <= oper->respc; ++i) {
-
 
301
                    if (i > 1) printf(", ");
-
 
302
                    val_print(resp[i], oper->resp_type[i - 1]);
-
 
303
                }
-
 
304
                putchar(')');
-
 
305
            }
-
 
306
 
-
 
307
            putchar('\n');
-
 
308
        }
260
    }
309
    }
261
 
310
 
262
    if (phone == 0 && method == IPC_M_CONNECT_ME_TO && retval == 0) {
311
    if (phone == 0 && method == IPC_M_CONNECT_ME_TO && retval == 0) {
263
        /* Connected to a service (through NS) */
312
        /* Connected to a service (through NS) */
264
        service = IPC_GET_ARG1(pcall->question);
313
        service = IPC_GET_ARG1(pcall->question);
265
        proto = proto_get_by_srv(service);
314
        proto = proto_get_by_srv(service);
266
        if (proto == NULL) proto = proto_unknown;
315
        if (proto == NULL) proto = proto_unknown;
267
 
316
 
268
        cphone = IPC_GET_ARG5(*answer);
317
        cphone = IPC_GET_ARG5(*answer);
269
        if ((display_mask & DM_SYSTEM) != 0) {
318
        if ((display_mask & DM_SYSTEM) != 0) {
270
            printf("Registering connection (phone %d, protocol: %s)\n", cphone,
319
            printf("Registering connection (phone %d, protocol: %s)\n", cphone,
271
                    proto->name);
320
                    proto->name);
272
        }
321
        }
273
        ipcp_connection_set(cphone, 0, proto);
322
        ipcp_connection_set(cphone, 0, proto);
274
    }
323
    }
275
}
324
}
276
 
325
 
277
void ipcp_call_in(ipc_call_t *call, ipc_callid_t hash)
326
void ipcp_call_in(ipc_call_t *call, ipc_callid_t hash)
278
{
327
{
279
    link_t *item;
328
    link_t *item;
280
    pending_call_t *pcall;
329
    pending_call_t *pcall;
281
    unsigned long key[1];
330
    unsigned long key[1];
282
 
331
 
283
//  printf("ipcp_call_in()\n");
332
//  printf("ipcp_call_in()\n");
284
/*  printf("phone: %d, method: ", call->in_phone_hash);
333
/*  printf("phone: %d, method: ", call->in_phone_hash);
285
    ipc_m_print(IPC_GET_METHOD(*call));
334
    ipc_m_print(IPC_GET_METHOD(*call));
286
    printf(" args: (%u, %u, %u, %u, %u)\n",
335
    printf(" args: (%u, %u, %u, %u, %u)\n",
287
        IPC_GET_ARG1(*call),
336
        IPC_GET_ARG1(*call),
288
        IPC_GET_ARG2(*call),
337
        IPC_GET_ARG2(*call),
289
        IPC_GET_ARG3(*call),
338
        IPC_GET_ARG3(*call),
290
        IPC_GET_ARG4(*call),
339
        IPC_GET_ARG4(*call),
291
        IPC_GET_ARG5(*call)
340
        IPC_GET_ARG5(*call)
292
    );*/
341
    );*/
293
 
342
 
294
    if ((hash & IPC_CALLID_ANSWERED) == 0 && hash != IPCP_CALLID_SYNC) {
343
    if ((hash & IPC_CALLID_ANSWERED) == 0 && hash != IPCP_CALLID_SYNC) {
295
        /* Not a response */
344
        /* Not a response */
296
        if ((display_mask & DM_IPC) != 0) {
345
        if ((display_mask & DM_IPC) != 0) {
297
            printf("Not a response (hash %d)\n", hash);
346
            printf("Not a response (hash %d)\n", hash);
298
        }
347
        }
299
        return;
348
        return;
300
    }
349
    }
301
 
350
 
302
    hash = hash & ~IPC_CALLID_ANSWERED;
351
    hash = hash & ~IPC_CALLID_ANSWERED;
303
    key[0] = hash;
352
    key[0] = hash;
304
 
353
 
305
    item = hash_table_find(&pending_calls, key);
354
    item = hash_table_find(&pending_calls, key);
306
    if (item == NULL) return; // No matching question found
355
    if (item == NULL) return; // No matching question found
307
 
356
 
308
    /*
357
    /*
309
     * Response matched to question.
358
     * Response matched to question.
310
     */
359
     */
311
   
360
   
312
    pcall = hash_table_get_instance(item, pending_call_t, link);
361
    pcall = hash_table_get_instance(item, pending_call_t, link);
313
    hash_table_remove(&pending_calls, key, 1);
362
    hash_table_remove(&pending_calls, key, 1);
314
 
363
 
315
    parse_answer(hash, pcall, call);
364
    parse_answer(hash, pcall, call);
316
    free(pcall);
365
    free(pcall);
317
}
366
}
318
 
367
 
319
void ipcp_call_sync(int phone, ipc_call_t *call, ipc_call_t *answer)
368
void ipcp_call_sync(int phone, ipc_call_t *call, ipc_call_t *answer)
320
{
369
{
321
    ipcp_call_out(phone, call, IPCP_CALLID_SYNC);
370
    ipcp_call_out(phone, call, IPCP_CALLID_SYNC);
322
    ipcp_call_in(answer, IPCP_CALLID_SYNC);
371
    ipcp_call_in(answer, IPCP_CALLID_SYNC);
323
}
372
}
324
 
373
 
325
void ipcp_hangup(int phone, int rc)
374
void ipcp_hangup(int phone, int rc)
326
{
375
{
327
    if ((display_mask & DM_SYSTEM) != 0) {
376
    if ((display_mask & DM_SYSTEM) != 0) {
328
        printf("Hang phone %d up -> %d\n", phone, rc);
377
        printf("Hang phone %d up -> %d\n", phone, rc);
329
        ipcp_connection_clear(phone);
378
        ipcp_connection_clear(phone);
330
    }
379
    }
331
}
380
}
332
 
381
 
333
/** @}
382
/** @}
334
 */
383
 */
335
 
384