歡迎來到Linux教程網
Linux教程網
Linux教程網
Linux教程網
Linux教程網 >> Linux綜合 >> Linux資訊 >> Linux文化 >> 在Linux下使用ISDN撥號上網

在Linux下使用ISDN撥號上網

日期:2017/2/27 12:15:52   编辑:Linux文化

經過嘗試,我成功地做到了這一點。我的配置為:藍點Linux 2.0,Kernel-2.2.16,isdn4linux v3.1pre1,上海貝爾生產的ISDN內置卡,型號為SBT6021。
下面介紹具體做法。介紹順序為:內核->isdn4linux安裝->撥號配置->測試。

1、 內核
上海貝爾SBT6021型ISDN內置卡,使用的芯片為Winbond W6692,這是一種與西門子HiSax驅動程序兼容的芯片,該卡是即插即用的,無需手工設定中斷請求號和I/O地址。要Linux內核支持這種卡,在編譯內核時,必須選中下列選項:

ISDN Support
Support synchronous PPP
(多數ISDN設備撥號上網都是使用同步PPP方式)
Hisax SiemensChipset driver support
Hisax Support for DSS1
(絕大多數ISDN設備使用的協議都是DSS1)
Hisax Support for Winbond W6692

但我不必急於編譯內核,如果現有的內核已經包含這些選項了,我又何必重復一遍呢。那我怎麼知道現有內核是否已經包含這些選項了呢?看內核編譯配置文件/usr/src/linux/.config(注意:文件名以"."開頭的文件是隱藏文件,要用ls -a才可看到。)我看到其中有下面這5行內容,對應於剛才的5個選項:

CONFIG_ISDN=m
CONFIG_ISDN_PPP=y
CONFIG_ISDN_DRV_HISAX=m
CONFIG_HISAX_EURO=y
CONFIG_HISAX_W6692=y

"=y"表示內核直接支持(代碼已鏈入內核中),"=m"表示模塊支持(代碼在另外的內核中,可由內核載入)。於是這就表明,藍點Linux 2.0的原有內核已包含這些選項了,我就不用重新編譯內核啦。

2、 isdn4linux安裝
欲配置ISDN,要用到isdn4linux這一套軟件。isdn4linux的主要文件有isdnctrl, ipppd等。
獲取isdn4linux源碼的地址為:
http://isdn4linux.org
取得的文件為isdn4k-utils.v3.1pre1.tar.gz,放於/usr/src目錄下。
進入/usr/src目錄中,開始安裝過程。
進入/usr/src:
cd /usr/src
解開壓縮文件:
tar xzvf isdn4k-utils.v3.1pre1.tar.gz
命令完成後多了一個子目錄isdn4k-utils,isdn4linux的源碼文件就在其中。
進入該子目錄:
cd isdn4k-utils
該目錄中的README文件詳細介紹了如何安裝isdn4linux,照章行事即可。
進行配置:
make config
不做任何改變,用缺省的即可。
開始編譯:
make
未能通過,失敗原因是linux/autoconf.h文件或目錄不存在。這個文件就是/usr/include/linux/autoconf.h文件,一查確實不存在。它是在編譯內核的時候生成的,而我並未編譯內核,所以當然沒有了。好吧,想辦法生成它吧。
到linux目錄並進行配置:
cd /usr/src/linux
make menuconfig
不做任何改變,退出,保存即可。此時一看,/usr/include/linux/autoconf.h文件出來了,這就夠了,不必真的去編譯內核。
回到isdn4linux目錄再編譯:
cd /usr/src/isdn4k-utils
make
剛才的問題沒有了,但還是未能通過,失敗原因是capi20/capi20.c文件中下面幾個符號未定義:

CAPI_GET_FLAGS
CAPI_SET_FLAGS
CAPI_CLR_FLAGS
CAPI_NCCI_GETUNIT
CAPI_NCCI_OPENCOUNT

對應的一段源代碼為:

int
capi20ext_get_flags(unsigned ApplID, unsigned *flagsptr)
{
if (ioctl(applid2fd(ApplID), CAPI_GET_FLAGS, flagsptr) < 0)
return CapiMsgOSResourceErr;
return CapiNoError;
}

int
capi20ext_set_flags(unsigned ApplID, unsigned flags)
{
if (ioctl(applid2fd(ApplID), CAPI_SET_FLAGS, &flags) < 0)
return CapiMsgOSResourceErr;
return CapiNoError;
}

int
capi20ext_clr_flags(unsigned ApplID, unsigned flags)
{
if (ioctl(applid2fd(ApplID), CAPI_CLR_FLAGS, &flags) < 0)
return CapiMsgOSResourceErr;
return CapiNoError;
}

char *
capi20ext_get_tty_devname(unsigned applid, unsigned ncci, char *buf, size_t size)
{
int unit;
unit = ioctl(applid2fd(applid), CAPI_NCCI_GETUNIT, &ncci);
if (unit < 0)
return 0;
snprintf(buf, size, "/dev/capi/%d", unit);
return buf;
}

char *
capi20ext_get_raw_devname(unsigned applid, unsigned ncci, char *buf, size_t size)
{
int unit;
unit = ioctl(applid2fd(applid), CAPI_NCCI_GETUNIT, &ncci);
if (unit < 0)
return 0;
snprintf(buf, size, "/dev/capi/r%d", unit);
return buf;
}

int capi20ext_ncci_opencount(unsigned applid, unsigned ncci)
{
return ioctl(applid2fd(applid), CAPI_NCCI_OPENCOUNT, &ncci);
}

作者未定義它們,我也不知道這幾個常量該是多少,怎麼辦?我從capi20/capi20.h文件中發現,這幾個函數是" extentions functions (no standard functions)",擴展的非標准函數,我猜測,這幾個函數即使功能不正確,也不會影響ISDN的使用,那麼,我就可以把那幾個未定義的符號注解起來,使編譯通過。修改源碼如下:

int
capi20ext_get_flags(unsigned ApplID, unsigned *flagsptr)
{
// if (ioctl(applid2fd(ApplID), CAPI_GET_FLAGS, flagsptr) < 0)
// return CapiMsgOSResourceErr;
return CapiNoError;
}

int
capi20ext_set_flags(unsigned ApplID, unsigned flags)
{
// if (ioctl(applid2fd(ApplID), CAPI_SET_FLAGS, &flags) < 0)
// return CapiMsgOSResourceErr;
return CapiNoError;
}

int
capi20ext_clr_flags(unsigned ApplID, unsigned flags)
{
// if (ioctl(applid2fd(ApplID), CAPI_CLR_FLAGS, &flags) < 0)
// return CapiMsgOSResourceErr;
return CapiNoError;
}

char *
capi20ext_get_tty_devname(unsigned applid, unsigned ncci, char *buf, size_t size)
{
int unit;
// unit = ioctl(applid2fd(applid), CAPI_NCCI_GETUNIT, &ncci);
if (unit < 0)
return 0;
snprintf(buf, size, "/dev/capi/%d", unit);
return buf;
}

char *
capi20ext_get_raw_devname(unsigned applid, unsigned ncci, char *buf, size_t size)
{
int unit;
// unit = ioctl(applid2fd(applid), CAPI_NCCI_GETUNIT, &ncci);
if (unit < 0)
return 0;
snprintf(buf, size, "/dev/capi/r%d", unit);
return buf;
}

int capi20ext_ncci_opencount(unsigned applid, unsigned ncci)
{
// return ioctl(applid2fd(applid), CAPI_NCCI_OPENCOUNT, &ncci);
return 0;
}

再次編譯:
make
通過了,接著安裝:
make install
命令完成後,isdnctrl和ipppd被拷到/sbin目錄下。

3、 撥號配置
我看了一些別人寫的介紹文章,取用他們寫好的例子,修改其中的電話號碼,用戶名等必須修改的相關內容,然後運行。不幸的是,通常都不能成功。因為這些例子都比較完善而復雜,因此難免和我的配置情況不符合而出錯。我決定從簡單入手,只進行最基本最必要的配置,先不寫成shell文件,而是一條命令一條命令地輸入執行,仔細理解其意義,查看其執行結果。等全部試驗成功後,再寫成shell文件。現在看來,這種做法非常有效,我會同樣來處理類似的問題。

echo 1 > /proc/sys/net/ipv4/ip_dynaddr
撥號上網大部分都是使用動態IP地址,比如我上163網,只知道撥打163號碼,並不知道遠程服務器(即中國電信機房內的163撥號服務器)的IP地址是多少,也不知道它會給我的機器分配什麼IP地址。往/proc/sys/net/ipv4/ip_dynaddr中寫入"1",就是告訴內核要使用動態IP地址。
modprobe hisax type=36 protocol=2
裝入ISDN卡的驅動程序。前面已經說過,上海貝爾SBT6021型ISDN內置卡中使用的芯片W6692是由HiSax驅動程序驅動的,type=36指明了是使用W6692芯片,protocol=2指明了ISDN協議是用DSS1,詳細內容可看/usr/src/linux/Documentation/isdn/README.HiSax文件。
isdnctrl addif ippp0
ISDN通過同步PPP方式上網,其對應的Interface會是/dev/ippp0, /dev/ippp1, ...等。這條命令告訴內核,加入ippp0這個Interface,換句話說,告訴內核我有個ISDN設備,准備通過同步PPP方式上網。從此以後,ippp0就代表了我的ISDN設備。
isdnctrl addphone ippp0 out 163
指明撥出的電話號碼,我撥出的是163,在中國大陸,通過中國電信上網的大部分也都是163。
isdnctrl eaz ippp0 3382460
指明我自己這台ISDN的電話號碼為3382460。
isdnctrl l2_prot ippp0 hdlc
第2層協議用的是hdlc。
isdnctrl l3_prot ippp0 trans
第3層協議用的是trans。
isdnctrl encap ippp0 syncppp
用同步PPP方式包裝。
isdnctrl dialmode ippp0 manual
手工撥號方式,在此方式下,要撥號時下isdnctrl dial ippp0命令,要掛斷時下isdnctrl hangup ippp0命令。另外還有auto自動方式,不過,還是先用手工方式比較直觀穩妥一點吧。
isdnctrl dialmax ippp0 3
1次撥號有可能連不通,不要緊,程序會自動重撥的,這裡規定了最多重撥3次。
isdnctrl huptimeout ippp0 600
線路空閒一段時間後,會自動掛斷,缺省是空閒10秒後掛斷,太短了,我改為600秒。

ISDN特定的基本配置就這麼多了,下面轉到普通的網絡配置上來。Linux的普通網絡配置主要有兩個方面:(1)對各Interface本身的配置。Interface指以太網卡,Modem,ISDN等設備,配置信息包括網絡地址,網絡掩碼,網關等,相應的配置工具為ifconfig程序。(2)對路由表的配置。路由表規定了到各個目的地的數據包應走哪個網關,使用哪個Interface等,相應的配置工具為route程序。

在進行配置之前,先看一下我目前的配置情況是什麼樣的。我這台Linux機器在一個局域網上,局域網的域名為thalia.com,地址為210.96.100.0,這台機器的主機名為gate,地址為210.96.100.10。
看Interface配置:
ifconfig
得到類似下面的信息:

eth0 Link encap:Ethernet HWaddr 00:20:AF:F1:0A:4A
inet addr:210.96.100.10 Bcast:210.96.100.255 Mask:255.255.255.0
inet6 addr: fe80::220:afff:fef1:a4a/10 Scope:Link
inet6 addr: fe80::20:aff1:a4a/10 Scope:Link
UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1
RX packets:14 errors:0 dropped:0 overruns:0 frame:0
TX packets:34 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:100
Interrupt:10 Base address:0x6000

lo Link encap:Local Loopback
inet addr:127.0.0.1 Mask:255.0.0.0
inet6 addr: ::1/128 Scope:Host
UP LOOPBACK RUNNING MTU:3924 Metric:1
RX packets:38 errors:0 dropped:0 overruns:0 frame:0
TX packets:38 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:0

有2個Interface,eth0代表了以太網卡,lo是個“虛”的loopback設備。
看路由表配置:
route
得到類似下面的信息:

Kernel IP routing table
Destination Gateway Genmask Flags Metric Ref Use Iface
gate.thalia.com * 255.255.255.255 UH 0 0 0 eth0
210.96.100.0 * 255.255.255.0 U 0 0 0 eth0
127.0.0.0 * 255.0.0.0 U 0 0 0 lo

有3條路由信息。
要用上ISDN(ippp0),必須用ifconfig對ippp0進行配置,並用route增加1條使用它的路由。
配置ippp0:
ifconfig ippp0 0.0.0.0 pointopoint 0.0.0.0 netmask 0.0.0.0
指明使用PPP(pointopoint)協議,pointopoint前面是本機地址,後面是遠程服務器地址,這裡全是0.0.0.0,行嗎?行,因為前面已經作了配置echo 1 > /proc/sys/net/ipv4/ip_dynaddr,告訴內核將使用動態IP地址,因此在這裡用0.0.0.0並無所謂,當這個PPP連接建立起來後,它會自動用真正的IP地址代替這些0.0.0.0的。
這時候再用ifconfig看一下情況如何:
ifconfig
得到類似下面的信息:

eth0 Link encap:Ethernet HWaddr 00:20:AF:F1:0A:4A
inet addr:210.96.100.10 Bcast:210.96.100.255 Mask:255.255.255.0
inet6 addr: fe80::220:afff:fef1:a4a/10 Scope:Link
inet6 addr: fe80::20:aff1:a4a/10 Scope:Link
UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1
RX packets:64 errors:0 dropped:0 overruns:0 frame:0
TX packets:38 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:100
Interrupt:10 Base address:0x6000

ippp0 Link encap:Point-to-Point Protocol
UP POINTOPOINT RUNNING NOARP MTU:1500 Metric:1
RX packets:0 errors:0 dropped:0 overruns:0 frame:0
TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:30

lo Link encap:Local Loopback
inet addr:127.0.0.1 Mask:255.0.0.0
inet6 addr: ::1/128 Scope:Host
UP LOOPBACK RUNNING MTU:3924 Metric:1
RX packets:44 errors:0 dropped:0 overruns:0 frame:0
TX packets:44 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:0

多了1個ippp0 Interface,但由於未曾建立真正的連接,它的本機地址和遠程服務器地址都未給出。
增加1條使用ippp0的路由:
route add default ippp0
這裡指定缺省(default)的數據包都經過ippp0傳送。缺省的數據包?什麼意思?剛才我用route看時有3條路由信息,這些信息指定了發往3個目的地(Destination)的數據包該怎麼走,其它沒有指定怎麼走的數據包(在這裡,就是除了哪3種數據包之外的所有數據包),即為缺省數據包,比如要到168.160.224.103(新浪網sina.com.cn)的數據包,就屬於缺省數據包。於是這條命令就做到了這一點:如果我要上新浪網看新聞,就得經過ippp0(ISDN),這正是我所希望的。
這時候再用route看一下情況如何:
route
得到類似下面的信息:

Kernel IP routing table
Destination Gateway Genmask Flags Metric Ref Use Iface
gate.thalia.com * 255.255.255.255 UH 0 0 0 eth0
210.96.100.0 * 255.255.255.0 U 0 0 0 eth0
127.0.0.0 * 255.0.0.0 U 0 0 0 lo
default * 0.0.0.0 U 0 0 0 ippp0

多了1條default路由信息。注意其對應的gateway是"*"。
需要有一個後台服務程序ipppd來為ISDN PPP服務:
ipppd user zzh noipdefault ipcp-accept-local ipcp-accept-remote defaultroute mru 1500 mtu 1500 /dev/ippp0 &
前面的user zzh指定了用戶名為zzh,口令呢?多數163撥號上網使用的認證方法都是PAP認證,用戶名,口令信息放在/etc/ppp/pap-secrets文件中,我的用戶名為zzh,口令為51888(“我要發發發”,信不信由你,哈),於是修改/etc/ppp/pap-secrets文件如下:

# Secrets for authentication using PAP
# client server secret IP addresses
zzh * 51888

後面的noipdefault ipcp-accept-local ipcp-accept-remote指明了接受遠程撥號服務器分配的本機地址和遠程服務器地址,這正是動態IP地址的含義。defaultroute指明了當連接建立起來後,增加default路由條目,這是很關鍵的。mru 1500 mtu 1500指定了最大發送單元和最大接收單元均為1500字節。這個程序為/dev/ippp0提供服務。

4、 測試
好啦,都准備好啦,試一下吧。
撥號:
isdnctrl dial ippp0
看看發生了什麼情況:
ifconfig
得到類似下面的信息:

eth0 Link encap:Ethernet HWaddr 00:20:AF:F1:0A:4A
inet addr:210.96.100.10 Bcast:210.96.100.255 Mask:255.255.255.0
inet6 addr: fe80::220:afff:fef1:a4a/10 Scope:Link
inet6 addr: fe80::20:aff1:a4a/10 Scope:Link
UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1
RX packets:29 errors:0 dropped:0 overruns:0 frame:0
TX packets:36 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:100
Interrupt:10 Base address:0x6000

ippp0 Link encap:Point-to-Point Protocol
inet addr:61.142.84.71 P-t-P:202.105.161.206 Mask:255.0.0.0
UP POINTOPOINT RUNNING NOARP MTU:1500 Metric:1
RX packets:22 errors:0 dropped:0 overruns:0 frame:0
TX packets:21 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:30

lo Link encap:Local Loopback
inet addr:127.0.0.1 Mask:255.0.0.0
inet6 addr: ::1/128 Scope:Host
UP LOOPBACK RUNNING MTU:3924 Metric:1
RX packets:43 errors:0 dropped:0 overruns:0 frame:0
TX packets:43 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:0

ippp0中的本機地址(inet addr)是61.142.84.71,PPP遠程服務器地址(P-t-P)是202.105.161.206,代替了原來指定的0.0.0.0,說明動態IP地址是起作用的。
route
得到類似下面的信息:

Kernel IP routing table
Destination Gateway Genmask Flags Metric Ref Use Iface
gate.thalia.com * 255.255.255.255 UH 0 0 0 eth0
210.96.100.0 * 255.255.255.0 U 0 0 0 eth0
127.0.0.0 * 255.0.0.0 U 0 0 0 lo
202.0.0.0 * 255.0.0.0 U 0 0 0 ippp0
default 202.105.161.206 0.0.0.0 UG 0 0 0 ippp0

default對應的gateway是202.105.161.206,代替了原來的"*",再看清楚點,它正好是ippp0的遠程服務器地址。
怎麼知道ISDN的狀態呢?
imontty
得到類似下面的信息:

ISDN channel status:
Channel Usage Type Number
----------------------------------------------------------------------
HiSax Out Net 163
HiSax Off

HiSax1是連出去了(Out),撥打號碼是163。
看到歸看到,還得實際上去一把才知道行不行。
ping 168.160.224.103 (新浪網sina.com.cn)
通的。
ping sina.com.cn
不行了。域名解析的問題,找到/etc/resolv.conf文件,修改如下:

nameserver 127.0.0.1

指明域名服務器為127.0.0.1(“虛”的loopback),實際上經由路由表中的default條目,轉發到遠程服務器上,暗渡陳倉了。
再ping sina.com.cn,唔,OK了。
要掛斷,下命令:
isdnctrl hangup ippp0
如果想要干淨地恢復原狀,繼續下面的動作,和剛才的撥號配置正好一一相反。
kill ipppd
停止ipppd服務。(看別人寫的,我試的時候卻殺不掉,不知是不是因為ipppd是在後台運行的緣故。)
route del default
去掉路由表中增加的條目。
ifconfig ippp0 down
isdnctrl delif ippp0
關停並刪除ippp0 Interface。
modprobe -r hisax
卸出驅動程序。(我試的時候,有時也卸不掉。)

5、 形成shell文件
逐行命令操作全部通過啦,下面把它們寫成shell文件。
/etc/ppp/isdn-start文件內容如下:

# Dyna address
echo 1 > /proc/sys/net/ipv4/ip_dynaddr

# Load module
modprobe hisax type=36 protocol=2

# Add and config ISDN interface
isdnctrl addif ippp0
isdnctrl addphone ippp0 out 163
isdnctrl eaz ippp0 3382460
isdnctrl l2_prot ippp0 hdlc
isdnctrl l3_prot ippp0 trans
isdnctrl encap ippp0 syncppp

isdnctrl dialmode ippp0 manual
isdnctrl dialmax ippp0 3
isdnctrl huptimeout ippp0 600

ifconfig ippp0 0.0.0.0 pointopoint 0.0.0.0 netmask 0.0.0.0

# Add to routing table
route add default ippp0

# Run ipppd
ipppd user zzh \
noipdefault \
ipcp-accept-local \
ipcp-accept-remote \
defaultroute \
mru 1500 \
mtu 1500 \
/dev/ippp0 &

# Dial
isdnctrl dial ippp0

/etc/ppp/isdn-stop文件內容如下:

# Hangup
isdnctrl hangup ippp0

# Stop ipppd
kill ipppd

# Remove from routing table
route del default

# Del ISDN interface
ifconfig ippp0 down
isdnctrl delif ippp0

# Unload module
modprobe -r hisax

讓它們成為可執行文件:
chmod a+x /etc/ppp/isdn-start
chomd a+x /etc/ppp/isdn-stop
以後事情就簡單了。要撥號上網,下命令/etc/ppp/isdn-start;要下線掛斷,下命令/etc/ppp/isdn-stop。

6、 下一步:共享ISDN上網
我這台Linux機器是在一個局域網上的,現在這台機器可以上網了,怎麼讓局域網內的其它Win98, Win2000機器通過這台機器也能上網呢?其中一個簡單的方案就是使用IP Masquerade(IP偽裝)技術。我也做到了,操作過程寫在我的另一篇文章《用Linux+IPChains代替Windows+WinGate》中。

參考資料:
Matt Welsh, Matthias Kalle Dalheimer, Lar Kaufman著,Linux權威指南,洪峰 譯,中國電力出版社,2000


張中華([email protected]),2000.12.02,http://zzh-cn.com


--------------------------------------------------------------------------------

相關文件下載

ISDN撥號啟動:/etc/ppp/isdn-start
ISDN掛斷下線:/etc/ppp/isdn-stop
PAP認證的用戶和口令:/etc/ppp/pap-secrets
域名解析:/etc/resolv.conf


Copyright © Linux教程網 All Rights Reserved