]> git.decadent.org.uk Git - ap-utils.git/blob - src/bridge.c
Imported Upstream version 1.5~pre1
[ap-utils.git] / src / bridge.c
1 /*
2  *      bridge.c from Access Point SNMP Utils for Linux
3  *
4  * Copyright (c) 2002 Roman Festchook <roma at polesye dot net>
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License Version 2 from
8  * June 1991 as published by the Free Software Foundation.
9  *
10  * This program is distributed in the hope that it will be useful, but
11  * WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License along
16  * with this program; if not, write to the Free Software Foundation, Inc.,
17  * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18  *
19  */
20
21 #include <stdlib.h>
22 #include <string.h>
23 #include <sys/types.h>
24 #include "ap-utils.h"
25
26 #define IPADDR _("[I] IP: ")
27 #define NETMASK _("[N] Netmask: ")
28 #define GATEWAY _("[G] Gateway: ")
29 #define IP_FILTER _("[F] Filter non-IP traffic: ")
30 #define PR_PORT _("[P] Primary port: ")
31 #define SB_ATTMAC _("Attached station MAC: ")
32 #define DHCP _("[D] DHCP client: ")
33 #define OPER _("[O] Operational mode: ")
34 #define REMOTE_MAC _("[M] Preferred BSSID (remote MAC addr.): ")
35 #define CF_PORT _("[C] Configuration-enabled port(s): ")
36 #define TRAP_PORT _("[T] Trap-sending port(s): ")
37 #define FW_BCAST _("[R] Forward broadcast traffic: ")
38 #define SB_BCAST _("[B] Isolate wireless clients (broadcast traffic): ")
39 #define SB_UCAST _("[U] Isolate wireless clients (unicast traffic): ")
40 #define HELP _("INGFPDOMSCTRBU - set; W - write conf; Q - quit to menu")
41
42 extern short ap_type, ap_vendorext;
43
44 void bridging()
45 {
46     char sysTrapSwitch[] = {
47         0x2B, 0x06, 0x01, 0x04, 0x01, 0x83, 0x1A, 0x01, 0x01, 0x01, 0x03, 0x00
48     };
49
50     char operIPAddress[] = {
51         0x2B, 0x06, 0x01, 0x04, 0x01, 0x83, 0x1A, 0x01, 0x01, 0x02, 0x01, 0x00
52     };
53     char operIPMask[] = {
54         0x2B, 0x06, 0x01, 0x04, 0x01, 0x83, 0x1A, 0x01, 0x01, 0x02, 0x02, 0x00
55     };
56     char operEthernetAddress[] = {
57         0x2B, 0x06, 0x01, 0x04, 0x01, 0x83, 0x1A, 0x01, 0x01, 0x02, 0x03, 0x00
58     };
59     char operGateway[] = {
60         0x2B, 0x06, 0x01, 0x04, 0x01, 0x83, 0x1A, 0x01, 0x01, 0x02, 0x04, 0x00
61     };
62     char operDHCP[] = {
63         0x2B, 0x06, 0x01, 0x04, 0x01, 0x83, 0x1A, 0x01, 0x01, 0x02, 0x05, 0x00
64     };
65     char PrimaryPort[] = {
66         0x2B, 0x06, 0x01, 0x04, 0x01, 0x83, 0x1A, 0x01, 0x01, 0x02, 0x06, 0x00
67     };
68     /* This one is ATMEL12350 MIB specific. */
69     char ConfigPort[] = {
70         0x2B, 0x06, 0x01, 0x04, 0x01, 0xE0, 0x3E, 0x01, 0x01, 0x02, 0x07, 0x00
71     };
72     /* This one is ATMEL12350 TELLUS MIB specific. */
73     char TrapPort[] = {
74         0x2B, 0x06, 0x01, 0x04, 0x01, 0xE0, 0x3E, 0x01, 0x01, 0x02, 0x08, 0x00
75     };
76
77     char IPFilter[] = {
78         0x2B, 0x06, 0x01, 0x04, 0x01, 0x83, 0x1A, 0x01, 0x01, 0x03, 0x01, 0x00
79     };
80     /* These 3 are ATMEL12350 MIB specific. */
81     char ForwardBroadcast[] = {
82         0x2B, 0x06, 0x01, 0x04, 0x01, 0xE0, 0x3E, 0x01, 0x01, 0x03, 0x02, 0x00
83     };
84     char SendBackBcast[] = {
85         0x2B, 0x06, 0x01, 0x04, 0x01, 0xE0, 0x3E, 0x01, 0x01, 0x03, 0x03, 0x00
86     };
87     char SendBackUnicast[] = {
88         0x2B, 0x06, 0x01, 0x04, 0x01, 0xE0, 0x3E, 0x01, 0x01, 0x03, 0x04, 0x00
89     };
90
91     char bridgeOperationalMode[] = {
92         0x2B, 0x06, 0x01, 0x04, 0x01, 0x83, 0x1A, 0x01, 0x01, 0x04, 0x01, 0x00
93     };
94     char bridgeRemoteBridgeBSSID[] = {
95         0x2B, 0x06, 0x01, 0x04, 0x01, 0x83, 0x1A, 0x01, 0x01, 0x04, 0x02, 0x00
96     };
97
98     extern WINDOW *main_sub;
99     varbind varbinds[15];
100     struct in_addr ip, mask, gw;
101     unsigned char message[1024], filter, primary_port, dhcp, RemoteBSSID[6],
102         bridge_mode, traps, config_port, fw_bcast, sb_bcast,
103         sb_ucast;
104     char m_filter = 0, m_bridge_mode = 0, m_primary_port = 0, m_traps = 0,
105         m_dhcp = 0, m_ip = 0, m_mask = 0, m_gw = 0, m_remote_bssid = 0,
106         m_config_port = 0, m_trap_port = 0, m_fw_bcast = 0, m_sb_bcast = 0,
107         m_sb_ucast = 0;
108     char *bridge_modes[6] = {
109         _("Wireless Bridge Point to MultiPoint"),
110         _("Access Point"),
111         _("Access Point client"),
112         _("Wireless Bridge Point to Point"),
113         _("Repeater"),
114         ("unknown")
115     }, *pr_ports[2] = {
116         _("Ethernet"),
117         _("Wireless")
118     }, *cf_trap_ports[3] = {
119         _("Both"),
120         _("Ethernet"),
121         _("Wireless")
122     };
123     int i;
124     unsigned int trap_port = 0;
125
126     if (ap_type == ATMEL12350) {
127         operEthernetAddress[5] = 0xE0;
128         operEthernetAddress[6] = 0x3E;
129         IPFilter[5] = 0xE0;
130         IPFilter[6] = 0x3E;
131         PrimaryPort[5] = 0xE0;
132         PrimaryPort[6] = 0x3E;
133         operDHCP[5] = 0xE0;
134         operDHCP[6] = 0x3E;
135         operIPAddress[5] = 0xE0;
136         operIPAddress[6] = 0x3E;
137         operIPMask[5] = 0xE0;
138         operIPMask[6] = 0x3E;
139         operGateway[5] = 0xE0;
140         operGateway[6] = 0x3E;
141         bridgeOperationalMode[5] = 0xE0;
142         bridgeOperationalMode[6] = 0x3E;
143         bridgeRemoteBridgeBSSID[5] = 0xE0;
144         bridgeRemoteBridgeBSSID[6] = 0x3E;
145         sysTrapSwitch[5] = 0xE0;
146         sysTrapSwitch[6] = 0x3E;
147     }
148
149     for (i = 0; i < 15; i++) {
150         varbinds[i].type = NULL_VALUE;
151         varbinds[i].len_val = 0;
152         varbinds[i].len_oid = sizeof(sysTrapSwitch);
153     }
154
155     i = 0;
156
157     varbinds[i++].oid = operEthernetAddress;
158     varbinds[i++].oid = IPFilter;
159     varbinds[i++].oid = PrimaryPort;
160     varbinds[i++].oid = operDHCP;
161     varbinds[i++].oid = operIPAddress;
162     varbinds[i++].oid = operIPMask;
163     varbinds[i++].oid = operGateway;
164     varbinds[i++].oid = bridgeOperationalMode;
165     varbinds[i++].oid = sysTrapSwitch;
166     varbinds[i++].oid = bridgeRemoteBridgeBSSID;
167     if (ap_type == ATMEL12350) {
168         varbinds[i++].oid = ConfigPort;
169         varbinds[i++].oid = ForwardBroadcast;
170         varbinds[i++].oid = SendBackBcast;
171         varbinds[i++].oid = SendBackUnicast;
172         if (ap_vendorext == TELLUS || ap_vendorext == VERNET)
173             varbinds[i++].oid = TrapPort;
174     }
175
176     print_help(WAIT_RET);
177     if (snmp(varbinds, i, GET) <= 0) {
178         print_helperr(ERR_RET);
179         goto exit;
180     }
181
182     print_top(NULL, _("Bridging"));
183
184     sprintf(message, "%s%02X%02X%02X%02X%02X%02X", MAC,
185             varbinds[0].value[0] & 0xFF,
186             varbinds[0].value[1] & 0xFF,
187             varbinds[0].value[2] & 0xFF,
188             varbinds[0].value[3] & 0xFF,
189             varbinds[0].value[4] & 0xFF,
190             varbinds[0].value[5] & 0xFF);
191     mvwaddstr(main_sub, 0, 0, message);
192
193     memcpy(&ip.s_addr, varbinds[4].value, 4);
194     sprintf(message, "%s%s", IPADDR, inet_ntoa(ip));
195     mvwaddstr(main_sub, 1, 0, message);
196
197     memcpy(&mask.s_addr, varbinds[5].value, 4);
198     sprintf(message, "%s%s", NETMASK, inet_ntoa(mask));
199     mvwaddstr(main_sub, 1, 24, message);
200
201     memcpy(&gw.s_addr, varbinds[6].value, 4);
202     sprintf(message, "%s%s", GATEWAY, inet_ntoa(gw));
203     mvwaddstr(main_sub, 2, 0, message);
204
205     filter = *(varbinds[1].value);
206     sprintf(message, "%s%s", IP_FILTER, (filter == 1) ? ON : OFF);
207     mvwaddstr(main_sub, 3, 0, message);
208
209     if (ap_vendorext == SBRIDGES) {
210         sprintf(message, "%s%02X%02X%02X%02X%02X%02X", SB_ATTMAC,
211                 *(varbinds[2].value +0) & 0xFF, *(varbinds[2].value +1) & 0xFF,
212                 *(varbinds[2].value +2) & 0xFF, *(varbinds[2].value +3) & 0xFF,
213                 *(varbinds[2].value +4) & 0xFF, *(varbinds[2].value +5) & 0xFF);
214     } else {
215         primary_port = *(varbinds[2].value);
216         if (primary_port < 1 || primary_port > 2) {
217             primary_port = 1;
218         }
219         sprintf(message, "%s%s", PR_PORT, pr_ports[primary_port - 1]);
220     }
221     mvwaddstr(main_sub, 4, 0, message);
222
223     dhcp = *(varbinds[3].value);
224     sprintf(message, "%s%s", DHCP, (dhcp == 1) ? ON : OFF);
225     mvwaddstr(main_sub, 5, 0, message);
226
227     memcpy(RemoteBSSID, varbinds[9].value, 6);
228     if ((bridge_mode = *(varbinds[7].value)) != 2) {
229         sprintf(message, "%s%02X%02X%02X%02X%02X%02X", REMOTE_MAC,
230                 *(RemoteBSSID + 0) & 0xFF, *(RemoteBSSID + 1) & 0xFF,
231                 *(RemoteBSSID + 2) & 0xFF, *(RemoteBSSID + 3) & 0xFF,
232                 *(RemoteBSSID + 4) & 0xFF, *(RemoteBSSID + 5) & 0xFF);
233         mvwaddstr(main_sub, 7, 0, message);
234     }
235     if (bridge_mode > 5)
236         bridge_mode  = 6;
237     sprintf(message, "%s%s", OPER, bridge_modes[bridge_mode - 1]);
238     mvwaddstr(main_sub, 6, 0, message);
239
240     traps = *(varbinds[8].value);
241     sprintf(message, "%s%s", TRAPS, (traps == 1) ? ON : OFF);
242     mvwaddstr(main_sub, 8, 0, message);
243
244     if (ap_type == ATMEL12350) {
245         config_port = *(varbinds[10].value);
246         sprintf(message, "%s%s", CF_PORT, cf_trap_ports[config_port]);
247         mvwaddstr(main_sub, 9, 0, message);
248
249         if (ap_vendorext == TELLUS || ap_vendorext == VERNET) {
250             for (i = 0; i < varbinds[14].len_val;
251                     trap_port += varbinds[14].value[i] *
252                     (1 << ((varbinds[14].len_val - i - 1) * 8)), i++);
253             sprintf(message, "%s%u", TRAP_PORT, trap_port);
254             mvwaddstr(main_sub, 10, 0, message);
255         }
256
257         fw_bcast = *(varbinds[11].value);
258         sprintf(message, "%s%s", FW_BCAST, (fw_bcast == 1) ? ON : OFF);
259         mvwaddstr(main_sub, 11, 0, message);
260
261         sb_bcast = *(varbinds[12].value);
262         sprintf(message, "%s%s", SB_BCAST, (sb_bcast == 1) ? ON : OFF);
263         mvwaddstr(main_sub, 12, 0, message);
264
265         sb_ucast = *(varbinds[13].value);
266         sprintf(message, "%s%s", SB_UCAST, (sb_ucast == 1) ? ON : OFF);
267         mvwaddstr(main_sub, 13, 0, message);
268     }
269     wrefresh(main_sub);
270     noecho();
271
272     print_help(HELP);
273     while (1) {
274         switch (getch()) {
275         case 'I':
276         case 'i':
277             get_ip(&ip, 1, strlen(IPADDR), HELP);
278             m_ip = 1;
279             continue;
280         case 'N':
281         case 'n':
282             get_mask(&mask, 1, strlen(IPADDR) + 16 + strlen(NETMASK), HELP);
283             m_mask = 1;
284             continue;
285         case 'G':
286         case 'g':
287             get_ip(&gw, 2, strlen(GATEWAY), HELP);
288             m_gw = 1;
289             continue;
290         case 'F':
291         case 'f':
292             filter = on_off(3, strlen(IP_FILTER));
293             clear_main_new(3, 4);
294             print_menusel(3, 0, IP_FILTER, (filter == 1) ? ON : OFF);
295             m_filter = 1;
296             continue;
297         case 'P':
298         case 'p':
299             if (ap_vendorext != SBRIDGES) {
300                 primary_port = menu_choose(4, strlen(PR_PORT), pr_ports, 2) + 1;
301                 clear_main_new(4, 5);
302                 print_menusel(4, 0, PR_PORT, pr_ports[primary_port - 1]);
303                 m_primary_port = 1;
304             }   
305             continue;
306         case 'D':
307         case 'd':
308             dhcp = on_off(5, strlen(DHCP));
309             clear_main_new(5, 6);
310             print_menusel(5, 0, DHCP, (dhcp == 1) ? ON : OFF);
311             m_dhcp = 1;
312             continue;
313         case 'O':
314         case 'o':
315             bridge_mode = menu_choose(6, strlen(OPER), bridge_modes, 5) + 1;
316             clear_main_new(6, 8);
317             print_menusel(6, 0, OPER, bridge_modes[bridge_mode - 1]);
318             if (bridge_mode != 2) {
319                 sprintf(message, "%02X%02X%02X%02X%02X%02X",
320                         *(RemoteBSSID + 0) & 0xFF,
321                         *(RemoteBSSID + 1) & 0xFF,
322                         *(RemoteBSSID + 2) & 0xFF,
323                         *(RemoteBSSID + 3) & 0xFF,
324                         *(RemoteBSSID + 4) & 0xFF,
325                         *(RemoteBSSID + 5) & 0xFF);
326                 print_menusel(7, 0, REMOTE_MAC, message);
327             }
328             m_bridge_mode = 1;
329             continue;
330         case 'M':
331         case 'm':
332             if (bridge_mode == 2)
333                 continue;
334
335             get_mac(RemoteBSSID, 7, strlen(REMOTE_MAC));
336 /*          mvwaddstr(main_sub, 7, 21, "  :  :  :  :  :  ");
337             for (i = 0; i < 6; i++) {
338                 get_value(message, 7, 21 + i * 3, 3, ANY_STRING, 0, 0, NULL);
339                 RemoteBSSID[i] = strtol(message, NULL, 16);
340             }
341             sprintf(message, "%s%02X%02X%02X%02X%02X%02X", REMOTE_MAC,
342                 *(RemoteBSSID + 0) & 0xFF, *(RemoteBSSID + 1) & 0xFF,
343                 *(RemoteBSSID + 2) & 0xFF, *(RemoteBSSID + 3) & 0xFF,
344                 *(RemoteBSSID + 4) & 0xFF, *(RemoteBSSID + 5) & 0xFF);
345 */
346             m_remote_bssid = 1;
347             continue;
348         case 'S':
349         case 's':
350             traps = on_off(8, strlen(TRAPS));
351             clear_main_new(8, 9);
352             print_menusel(8, 0, TRAPS, (traps == 1) ? ON : OFF);
353             m_traps = 1;
354             continue;
355         case 'C':
356         case 'c':
357             if (ap_type == ATMEL12350) {
358                 config_port = menu_choose(9, strlen(CF_PORT), cf_trap_ports, 3);
359                 clear_main_new(9, 10);
360                 print_menusel(9, 0, CF_PORT, cf_trap_ports[config_port]);
361                 m_config_port = 1;
362             }
363             continue;
364         case 'T':
365         case 't':
366             if (ap_vendorext == TELLUS || ap_vendorext == VERNET) {
367                 get_value(message, 10, strlen(TRAP_PORT), 6, INT_STRING,
368                     0, 65535, HELP);
369                 trap_port = atoi(message);
370                 m_trap_port = 1;
371             }
372             continue;
373         case 'R':
374         case 'r':
375             if (ap_type == ATMEL12350) {
376                 fw_bcast = on_off(11, strlen(FW_BCAST));
377                 clear_main_new(11, 12);
378                 print_menusel(11, 0, FW_BCAST, (fw_bcast == 1) ? ON : OFF);
379                 m_fw_bcast = 1;
380             }
381             continue;
382         case 'B':
383         case 'b':
384             if (ap_type == ATMEL12350) {
385                 sb_bcast = on_off(12, strlen(SB_BCAST));
386                 clear_main_new(12, 13);
387                 print_menusel(12, 0, SB_BCAST, (sb_bcast == 1) ? ON : OFF);
388                 m_sb_bcast = 1;
389             }
390             continue;
391         case 'U':
392         case 'u':
393             if (ap_type == ATMEL12350) {
394                 sb_ucast = on_off(13, strlen(SB_UCAST));
395                 clear_main_new(13, 14);
396                 print_menusel(13, 0, SB_UCAST, (sb_ucast == 1) ? ON : OFF);
397                 m_sb_ucast = 1;
398             }
399             continue;
400         case 'w':
401         case 'W':
402             i = 0;
403             if (m_filter) {
404                 varbinds[i].oid = IPFilter;
405                 varbinds[i].len_oid = sizeof(IPFilter);
406                 varbinds[i].type = INT_VALUE;
407                 varbinds[i].value = (char *) &filter;
408                 varbinds[i].len_val = 1;
409                 i++;
410             }
411             if (m_primary_port) {
412                 varbinds[i].oid = PrimaryPort;
413                 varbinds[i].len_oid = sizeof(PrimaryPort);
414                 varbinds[i].type = INT_VALUE;
415                 varbinds[i].value = (char *) &primary_port;
416                 varbinds[i].len_val = 1;
417                 i++;
418             }
419             if (m_dhcp) {
420                 varbinds[i].oid = operDHCP;
421                 varbinds[i].len_oid = sizeof(operDHCP);
422                 varbinds[i].type = INT_VALUE;
423                 varbinds[i].value = (char *) &dhcp;
424                 varbinds[i].len_val = 1;
425                 i++;
426             }
427             if (m_ip) {
428                 varbinds[i].oid = operIPAddress;
429                 varbinds[i].len_oid = sizeof(operIPAddress);
430                 ip.s_addr = htonl(ip.s_addr);
431                 ip.s_addr = swap4(ip.s_addr);
432                 varbinds[i].value = (char *) &ip.s_addr;
433                 varbinds[i].len_val = 4;
434                 varbinds[i].type = INT_VALUE;
435                 i++;
436             }
437             if (m_mask) {
438                 varbinds[i].oid = operIPMask;
439                 varbinds[i].len_oid = sizeof(operIPMask);
440                 mask.s_addr = htonl(mask.s_addr);
441                 mask.s_addr = swap4(mask.s_addr);
442                 varbinds[i].value = (char *) &mask.s_addr;
443                 varbinds[i].len_val = 4;
444                 varbinds[i].type = INT_VALUE;
445                 i++;
446             }
447             if (m_gw) {
448                 varbinds[i].oid = operGateway;
449                 gw.s_addr = htonl(gw.s_addr);
450                 gw.s_addr = swap4(gw.s_addr);
451                 varbinds[i].len_oid = sizeof(operGateway);
452                 varbinds[i].value = (char *) &gw.s_addr;
453                 varbinds[i].len_val = 4;
454                 varbinds[i].type = INT_VALUE;
455                 i++;
456             }
457             if (m_traps) {
458                 varbinds[i].oid = sysTrapSwitch;
459                 varbinds[i].len_oid = sizeof(sysTrapSwitch);
460                 varbinds[i].value = &traps;
461                 varbinds[i].len_val = 1;
462                 varbinds[i].type = INT_VALUE;
463                 i++;
464             }
465             if (m_bridge_mode) {
466                 varbinds[i].oid = bridgeOperationalMode;
467                 varbinds[i].len_oid = sizeof(bridgeOperationalMode);
468                 varbinds[i].value = (char *) &bridge_mode;
469                 varbinds[i].len_val = 1;
470                 varbinds[i].type = INT_VALUE;
471                 i++;
472             }
473             if (m_remote_bssid) {
474                 varbinds[i].oid = bridgeRemoteBridgeBSSID;
475                 varbinds[i].len_oid = sizeof(bridgeRemoteBridgeBSSID);
476                 varbinds[i].value = RemoteBSSID;
477                 varbinds[i].len_val = 6;
478                 varbinds[i].type = STRING_VALUE;
479                 i++;
480             }
481             if (m_config_port) {
482                 varbinds[i].oid = ConfigPort;
483                 varbinds[i].len_oid = sizeof(ConfigPort);
484                 varbinds[i].type = INT_VALUE;
485                 varbinds[i].value = (char *) &config_port;
486                 varbinds[i].len_val = 1;
487                 i++;
488             }
489             if (m_fw_bcast) {
490                 varbinds[i].oid = ForwardBroadcast;
491                 varbinds[i].len_oid = sizeof(ForwardBroadcast);
492                 varbinds[i].type = INT_VALUE;
493                 varbinds[i].value = (char *) &fw_bcast;
494                 varbinds[i].len_val = 1;
495                 i++;
496             }
497             if (m_sb_bcast) {
498                 varbinds[i].oid = SendBackBcast;
499                 varbinds[i].len_oid = sizeof(SendBackBcast);
500                 varbinds[i].type = INT_VALUE;
501                 varbinds[i].value = (char *) &sb_bcast;
502                 varbinds[i].len_val = 1;
503                 i++;
504             }
505             if (m_sb_ucast) {
506                 varbinds[i].oid = SendBackUnicast;
507                 varbinds[i].len_oid = sizeof(SendBackUnicast);
508                 varbinds[i].type = INT_VALUE;
509                 varbinds[i].value = (char *) &sb_ucast;
510                 varbinds[i].len_val = 1;
511                 i++;
512             }
513             if (m_trap_port) {
514                 int len_val;
515
516                 len_val = (trap_port > 0x7fff) ? 3 : (trap_port > 0x7f) ? 2 : 1;
517                 varbinds[i].oid = TrapPort;
518                 varbinds[i].len_oid = sizeof(TrapPort);
519                 varbinds[i].type = STRING_VALUE;
520                 varbinds[i].value = (char *) &trap_port;
521                 varbinds[i].len_val = len_val;
522                 i++;
523             }
524
525             print_help(WAIT_SET);
526             if (snmp(varbinds, i, SET) <= 0)
527                 print_helperr(ERR_SET);
528             else
529                 print_help(DONE_SET);
530             goto exit;
531         case 'Q':
532         case 'q':
533             goto quit;
534         }
535         continue;
536     }
537   exit:
538     getch();
539   quit:
540     print_top(NULL, NULL);
541     clear_main(0);
542 }
543