From cad9c23b276768ad0fe6e543395b20372652553e Mon Sep 17 00:00:00 2001 From: Linus Torvalds Date: Fri, 23 Nov 2007 15:10:07 -0500 Subject: [PATCH] Import 1.3.14 --- Makefile | 2 +- drivers/block/Makefile | 16 +- drivers/block/README.aztcd | 37 ++-- drivers/block/README.ide | 7 +- drivers/block/aztcd.c | 296 +++++++++++++++++++---------- drivers/block/cdu31a.c | 357 +++++++++++++++++++++-------------- drivers/block/cm206.c | 2 +- drivers/block/floppy.c | 113 ++++++----- drivers/block/genhd.c | 91 ++++----- drivers/block/ide.c | 73 +++++-- drivers/block/sbpcd.c | 6 +- drivers/block/sjcd.c | 4 +- drivers/char/lp.c | 20 -- drivers/char/psaux.c | 64 ++++++- drivers/char/vt.c | 2 +- drivers/net/atp.c | 6 +- drivers/net/eql.c | 4 +- drivers/net/ibmtr.c | 6 +- drivers/net/wavelan.c | 2 +- drivers/sound/Readme.cards | 31 ++- drivers/sound/ad1848_mixer.h | 2 +- drivers/sound/mad16.c | 17 +- drivers/sound/os.h | 2 +- drivers/sound/pas2_card.c | 5 +- drivers/sound/sb_dsp.c | 4 +- drivers/sound/sequencer.c | 2 +- drivers/sound/sound_switch.c | 4 +- drivers/sound/soundvers.h | 2 +- include/asm-i386/bitops.h | 6 +- include/linux/ax25.h | 2 + include/linux/aztcd.h | 24 ++- include/linux/cdrom.h | 4 + include/linux/genhd.h | 3 +- include/linux/netrom.h | 1 + include/linux/optcd.h | 4 +- include/linux/soundcard.h | 1 + include/net/ax25.h | 38 ++-- include/net/netrom.h | 10 +- kernel/itimer.c | 6 +- kernel/sched.c | 7 +- mm/filemap.c | 1 + net/802/p8022.c | 13 +- net/802/p8023.c | 8 +- net/802/psnap.c | 6 +- net/802/tr.c | 2 +- net/appletalk/aarp.c | 10 +- net/appletalk/ddp.c | 2 +- net/ax25/af_ax25.c | 97 +++++++--- net/ax25/ax25_in.c | 195 ++++++++++++++----- net/ax25/ax25_out.c | 110 ++++++++--- net/ax25/ax25_route.c | 2 +- net/ax25/ax25_subr.c | 126 +++++++++---- net/ax25/ax25_timer.c | 45 +++-- net/ethernet/pe2.c | 8 +- net/ipv4/arp.c | 6 +- net/ipv4/igmp.c | 2 +- net/ipv4/ip.c | 6 +- net/ipv4/ip_fw.c | 12 +- net/ipv4/proc.c | 2 +- net/ipv4/tcp.c | 8 +- net/ipv4/timer.c | 4 +- net/ipx/af_ipx.c | 35 +++- net/netrom/af_netrom.c | 60 +++++- net/netrom/nr_dev.c | 8 +- net/netrom/nr_in.c | 57 ++++-- net/netrom/nr_out.c | 69 ++++++- net/netrom/nr_route.c | 12 ++ net/netrom/nr_subr.c | 25 ++- net/netrom/nr_timer.c | 10 +- 69 files changed, 1477 insertions(+), 747 deletions(-) diff --git a/Makefile b/Makefile index 981c77b080c3..0d926106c92c 100644 --- a/Makefile +++ b/Makefile @@ -1,6 +1,6 @@ VERSION = 1 PATCHLEVEL = 3 -SUBLEVEL = 13 +SUBLEVEL = 14 ARCH = i386 diff --git a/drivers/block/Makefile b/drivers/block/Makefile index b4aa41a4edc4..434de423afee 100644 --- a/drivers/block/Makefile +++ b/drivers/block/Makefile @@ -30,9 +30,18 @@ else BLOCK_MODULE_OBJS := $(MODULES) floppy.o endif +ifdef CONFIG_AZTCD +OBJS := $(OBJS) aztcd.o +SRCS := $(SRCS) aztcd.c +else +BLOCK_MODULE_OBJS := $(BLOCK_MODULE_OBJS) aztcd.o +endif #CONFIG_AZTCD + ifdef CONFIG_CDU31A OBJS := $(OBJS) cdu31a.o SRCS := $(SRCS) cdu31a.c +else +BLOCK_MODULE_OBJS := $(BLOCK_MODULE_OBJS) cdu31a.o endif #CONFIG_CDU31A ifdef CONFIG_MCD @@ -71,13 +80,6 @@ OBJS := $(OBJS) sbpcd4.o SRCS := $(SRCS) sbpcd4.c endif #CONFIG_SBPCD4 -ifdef CONFIG_AZTCD -OBJS := $(OBJS) aztcd.o -SRCS := $(SRCS) aztcd.c -else -BLOCK_MODULE_OBJS := $(BLOCK_MODULE_OBJS) aztcd.o -endif #CONFIG_AZTCD - ifdef CONFIG_CDU535 OBJS := $(OBJS) sonycd535.o SRCS := $(SRCS) sonycd535.c diff --git a/drivers/block/README.aztcd b/drivers/block/README.aztcd index 48876877e2cd..19c2022a89ac 100644 --- a/drivers/block/README.aztcd +++ b/drivers/block/README.aztcd @@ -1,7 +1,8 @@ +$Id: README.aztcd,v 1.50 1995/07/29 20:33:35 root Exp root $ Readme-File README.aztcd for Aztech CD-ROM CDA268-01A, ORCHID CD-3110, OKANO/WEARNES CDD110 CD-ROM Driver - Version 1.4 and newer + Version 1.5 and newer (for other drives see 6.-8.) NOTE: THIS DRIVER WILL WORK WITH THE CD-ROM DRIVES LISTED, WHICH HAVE @@ -487,7 +488,7 @@ should try before, how to restore from a backup copy)! Werner Zimmermann Fachhochschule fuer Technik Esslingen (EMail: zimmerma@rz.fht-esslingen.de) -Mar 24, 1995 +July 26, 1995 --------------------------------------------------------------------------- APPENDIX: Source code of cdplay.c @@ -496,7 +497,7 @@ APPENDIX: Source code of cdplay.c Copyright 1994, 1995 Werner Zimmermann (zimmerma@rz.fht-esslingen.de) -This program originally was written to test the audio functions of the +This programm originally was written to test the audio functions of the AZTECH.CDROM-driver, but it should work with every CD-ROM drive. Before using it, you should set a symlink from /dev/cdrom to your real CDROM device. @@ -510,6 +511,7 @@ History: V0.1 W.Zimmermann: First release. Nov. 8, 1994 V0.5 W.Zimmermann: clean 'scanf' commands without compiler warnings Jan. 6, 1995 V0.6 W.Zimmermann: volume control (still experimental). Jan. 24, 1995 + V0.7 W.Zimmermann: read raw modified. July 26, 95 */ #include @@ -522,7 +524,7 @@ History: V0.1 W.Zimmermann: First release. Nov. 8, 1994 #include void help(void) -{ printf("Available Commands: STOP s EJECT e QUIT q\n"); +{ printf("Available Commands: STOP s EJECT/CLOSE e QUIT q\n"); printf(" PLAY TRACK t PAUSE p RESUME r\n"); printf(" NEXT TRACK n REPEAT LAST l HELP h\n"); printf(" SUB CHANNEL c TRACK INFO i PLAY AT a\n"); @@ -539,11 +541,11 @@ int main(void) struct cdrom_tocentry entry; struct cdrom_msf msf; union { struct cdrom_msf msf; - unsigned char buf[2336]; + unsigned char buf[CD_FRAMESIZE_RAW]; } azt; struct cdrom_volctrl volctrl; - printf("\nMini-Audio CD-Player V0.6 (C) 1994,1995 W.Zimmermann\n"); + printf("\nMini-Audio CD-Player V0.7 (C) 1994,1995 W.Zimmermann\n"); handle=open("/dev/cdrom",O_RDWR); ioctl(handle,CDROMRESUME); @@ -559,7 +561,7 @@ int main(void) switch (command) { case 'e': cmd=CDROMEJECT; ioctl(handle,cmd); - break; + break; case 'p': if (!ini) { printf("Command not allowed - play track first\n"); } @@ -578,10 +580,8 @@ int main(void) break; case 's': cmd=CDROMPAUSE; if (ioctl(handle,cmd)) printf("Drive error or already stopped\n"); - ini=0; cmd=CDROMSTOP; if (ioctl(handle,cmd)) printf("Drive error\n"); - ini=0; break; case 't': cmd=CDROMREADTOCHDR; if (ioctl(handle,cmd,&tocHdr)) printf("Drive Error\n"); @@ -675,7 +675,7 @@ int main(void) } break; case 'a': cmd=CDROMPLAYMSF; - printf("Address (min:sec:frame) "); + printf("Adress (min:sec:frame) "); scanf("%d:%d:%d",&arg1,&arg2,&arg3); msf.cdmsf_min0 =arg1; msf.cdmsf_sec0 =arg2; @@ -686,12 +686,12 @@ int main(void) msf.cdmsf_sec1=00; msf.cdmsf_frame1=00; if (ioctl(handle,cmd,&msf)) - { printf("Drive error or invalid address\n"); + { printf("Drive error or invalid adress\n"); } break; #ifdef AZT_PRIVATE_IOCTLS /*not supported by every CDROM driver*/ - case 'd': cmd=CDROMREADMODE1; - printf("Address (min:sec:frame) "); + case 'd': cmd=CDROMREADCOOKED; + printf("Adress (min:sec:frame) "); scanf("%d:%d:%d",&arg1,&arg2,&arg3); azt.msf.cdmsf_min0 =arg1; azt.msf.cdmsf_sec0 =arg2; @@ -699,7 +699,7 @@ int main(void) if (azt.msf.cdmsf_sec0 > 59) azt.msf.cdmsf_sec0 =59; if (azt.msf.cdmsf_frame0> 74) azt.msf.cdmsf_frame0=74; if (ioctl(handle,cmd,&azt.msf)) - { printf("Drive error, invalid address or unsupported command\n"); + { printf("Drive error, invalid adress or unsupported command\n"); } k=0; getchar(); @@ -723,8 +723,8 @@ int main(void) } } break; - case 'w': cmd=CDROMREADMODE2; - printf("Address (min:sec:frame) "); + case 'w': cmd=CDROMREADRAW; + printf("Adress (min:sec:frame) "); scanf("%d:%d:%d",&arg1,&arg2,&arg3); azt.msf.cdmsf_min0 =arg1; azt.msf.cdmsf_sec0 =arg2; @@ -732,10 +732,10 @@ int main(void) if (azt.msf.cdmsf_sec0 > 59) azt.msf.cdmsf_sec0 =59; if (azt.msf.cdmsf_frame0> 74) azt.msf.cdmsf_frame0=74; if (ioctl(handle,cmd,&azt)) - { printf("Drive error, invalid address or unsupported command\n"); + { printf("Drive error, invalid adress or unsupported command\n"); } k=0; - for (i=0;i<146;i++) + for (i=0;i<147;i++) { printf("%4d:",i*16); for (j=0;j<16;j++) { printf("%2x ",azt.buf[i*16+j]); @@ -779,4 +779,3 @@ int main(void) } return 0; } - diff --git a/drivers/block/README.ide b/drivers/block/README.ide index 2e180214659d..2ae29f03fe7f 100644 --- a/drivers/block/README.ide +++ b/drivers/block/README.ide @@ -27,10 +27,11 @@ Major features of ide.c & ide-cd.c: - use kernel command line option: hda=dtc2278 - run-time selectable 32bit interface support (using hdparm-2.3) -NEW! - support for DiskManager 6.0x "Dynamic Disk Overlay" (experimental) NEW! - support for drives with a stuck WRERR_STAT bit NEW! - support for removeable devices +NEW! - transparent support for DiskManager 6.0x and "Dynamic Disk Overlay" + - works with Linux fdisk, LILO, loadlin, bootln, etc.. *** @@ -267,7 +268,7 @@ software" refers to DOS, the BIOS, and LILO, as described previously. Western Digital ships a "DiskManager 6.03" diskette with all of their big hard drives. Use BIOS translation instead of this if possible, as it is a more generally compatible method of achieving the same results (DOS access -to the entire disk). However, if you must use DiskManager, it should now -work with Linux 1.3.x in most cases. Let me know if you still have trouble. +to the entire disk). However, if you must use DiskManager, it now works +with Linux 1.3.x in most cases. Let me know if you still have trouble. mlord@bnr.ca diff --git a/drivers/block/aztcd.c b/drivers/block/aztcd.c index 394676bd4ed2..50e53c120753 100644 --- a/drivers/block/aztcd.c +++ b/drivers/block/aztcd.c @@ -1,5 +1,5 @@ -#define AZT_VERSION "1.40" -/* $Id: aztcd.c,v 1.40 1995/07/15 20:35:15 root Exp root $ +#define AZT_VERSION "1.50" +/* $Id: aztcd.c,v 1.50 1995/07/28 16:43:59 root Exp root $ linux/drivers/block/aztcd.c - AztechCD268 CDROM driver Copyright (C) 1994,1995 Werner Zimmermann (zimmerma@rz.fht-esslingen.de) @@ -120,6 +120,10 @@ by Heiko Schlittermann. Not tested, as I do not have a multi- session CD. If you can test it, please contact me. Werner Zimmermann, July 15, 95 + V1.50 Implementation of ioctl CDROMRESET, continued multisession, began + XA, but still untested. Heavy modifications to drive status de- + tection. + Werner Zimmermann, July 25, 95 NOTE: Points marked with ??? are questionable ! */ @@ -160,8 +164,8 @@ #include -#define SET_TIMER(func, jifs) delay_timer.expires = jifs; \ - delay_timer.function = (void *) func; \ +#define SET_TIMER(func, jifs) delay_timer.expires = jiffies + (jifs); \ + delay_timer.function = (void *) (func); \ add_timer(&delay_timer); #define CLEAR_TIMER del_timer(&delay_timer); @@ -189,20 +193,21 @@ static int aztPresent = 0; #define AFL_STATUSorDATA (AFL_STATUS | AFL_DATA) #define AZT_BUF_SIZ 16 +#define CD_XA_HEAD_SUBHEAD CD_XA_HEAD+8 static volatile int azt_transfer_is_active=0; -static char azt_buf[2048*AZT_BUF_SIZ]; /*buffer for block size conversion*/ +static char azt_buf[CD_FRAMESIZE_RAW*AZT_BUF_SIZ];/*buffer for block size conversion*/ #if AZT_PRIVATE_IOCTLS -static char buf[2336]; /*separate buffer for the ioctls*/ +static char buf[CD_FRAMESIZE_RAW]; /*separate buffer for the ioctls*/ #endif static volatile int azt_buf_bn[AZT_BUF_SIZ], azt_next_bn; static volatile int azt_buf_in, azt_buf_out = -1; static volatile int azt_error=0; static int azt_open_count=0; -enum azt_state_e { - AZT_S_IDLE, /* 0 */ +enum azt_state_e +{ AZT_S_IDLE, /* 0 */ AZT_S_START, /* 1 */ AZT_S_MODE, /* 2 */ AZT_S_READ, /* 3 */ @@ -215,9 +220,14 @@ static volatile enum azt_state_e azt_state = AZT_S_IDLE; static volatile enum azt_state_e azt_state_old = AZT_S_STOP; static volatile int azt_st_old = 0; #endif +enum azt_read_modes +{ AZT_MODE_0, /*read mode for audio disks, not supported by Aztech firmware*/ + AZT_MODE_1, /*read mode for normal CD-ROMs*/ + AZT_MODE_2 /*read mode for XA CD-ROMs*/ +}; +static volatile enum azt_read_modes azt_read_mode = AZT_MODE_1; static int azt_mode = -1; -static int ACMD_DATA_READ= ACMD_PLAY_READ; static volatile int azt_read_count = 1; #define READ_TIMEOUT 3000 @@ -458,6 +468,39 @@ static int sendAztCmd(int cmd, struct azt_Play_msf *params) RETURNM("sendAztCmd",-1); } +/* Send a Set Disk Type command + does not seem to work with Aztech drives, behavior is completely indepen- + dent on which mode is set ??? +*/ +static int aztSetDiskType(int type) +{ unsigned char data; + int retry; + +#ifdef AZT_DEBUG + printk("aztcd: set disk type command: type= %i\n",type); +#endif + for (retry=0;retry=AZT_RETRY_ATTEMPTS) + { printk("### Error 2 aztcd: aztSetDiskType %x\n ",type); + azt_error=0xA5; + } + RETURNM("aztSetDiskType",-1); +} + /* * Checking if the media has been changed not yet implemented @@ -503,15 +546,14 @@ static int getAztStatus(void) } if (((st&AST_MODE_BITS)!=AST_BUSY) && (aztAudioStatus == CDROM_AUDIO_PLAY)) - /* XXX might be an error? look at q-channel? */ - aztAudioStatus = CDROM_AUDIO_COMPLETED; + /* XXX might be an error? look at q-channel? */ + aztAudioStatus = CDROM_AUDIO_COMPLETED; - if (st & AST_DSK_CHG) - { - aztDiskChanged = 1; - aztTocUpToDate = 0; - aztAudioStatus = CDROM_AUDIO_NO_STATUS; - } + if ((st & AST_DSK_CHG)||(st & AST_NOT_READY)) + { aztDiskChanged = 1; + aztTocUpToDate = 0; + aztAudioStatus = CDROM_AUDIO_NO_STATUS; + } return st; } @@ -543,10 +585,11 @@ static int aztcd_ioctl(struct inode *ip, struct file *fp, unsigned int cmd, unsi #ifdef AZT_DEBUG printk("aztcd: starting aztcd_ioctl - Command:%x Time: %li\n",cmd, jiffies); + printk("aztcd Status %x\n", getAztStatus()); #endif if (!ip) RETURNM("aztcd_ioctl 1",-EINVAL); if (getAztStatus()<0) RETURNM("aztcd_ioctl 2", -EIO); - if (!aztTocUpToDate) + if ((!aztTocUpToDate)||(aztDiskChanged)) { if ((i=aztUpdateToc())<0) RETURNM("aztcd_ioctl 3", i); /* error reading TOC */ } @@ -607,12 +650,7 @@ static int aztcd_ioctl(struct inode *ip, struct file *fp, unsigned int cmd, unsi ms.addr.lba = azt_msf2hsg(&DiskInfo.lastTrack); else return -EINVAL; - if (DiskInfo.type == CD_XA) - { ms.xa_flag = 0x01; /*XA-Disk*/ - } - else - { ms.xa_flag = 0x00; - } + ms.xa_flag = DiskInfo.xa; st = verify_area(VERIFY_WRITE, (void*) arg, sizeof(struct cdrom_multisession)); if (st) return st; memcpy_tofs((void*) arg, &ms, sizeof(struct cdrom_multisession)); @@ -704,7 +742,7 @@ azt_Play.end.min, azt_Play.end.sec, azt_Play.end.frame); st = verify_area(VERIFY_WRITE, (void *) arg, sizeof entry); if (st) return st; memcpy_fromfs(&entry, (void *) arg, sizeof entry); - if (!aztTocUpToDate) aztGetDiskInfo(); + if ((!aztTocUpToDate)||aztDiskChanged) aztUpdateToc(); if (entry.cdte_track == CDROM_LEADOUT) tocPtr = &Toc[DiskInfo.last + 1]; /* ??? */ else if (entry.cdte_track > DiskInfo.last @@ -800,13 +838,20 @@ azt_Play.end.min, azt_Play.end.sec, azt_Play.end.frame); case CDROMEJECT_SW: azt_auto_eject = (char) arg; break; - case CDROMREADMODE1: /*read data in mode 1 (2048 Bytes)*/ - case CDROMREADMODE2: /*read data in mode 2 (2336 Bytes)*/ + case CDROMRESET: + outb(ACMD_SOFT_RESET,CMD_PORT); /*send reset*/ + STEN_LOW; + if (inb(DATA_PORT)!=AFL_OP_OK) /*OP_OK?*/ + { printk("aztcd: AZTECH CD-ROM drive does not respond\n"); + } + break; /*Take care, the following code is not compatible with other CD-ROM drivers, use it at your own risk with cdplay.c. Set AZT_PRIVATE_IOCTLS to 0 in aztcd.h, if you do not want to use it! */ #if AZT_PRIVATE_IOCTLS + case CDROMREADCOOKED: /*read data in mode 1 (2048 Bytes)*/ + case CDROMREADRAW: /*read data in mode 2 (2336 Bytes)*/ { st = verify_area(VERIFY_READ, (void *) arg, sizeof msf); if (st) return st; st = verify_area(VERIFY_WRITE, (void *) arg, sizeof buf); @@ -825,21 +870,28 @@ azt_Play.end.min, azt_Play.end.sec, azt_Play.end.frame); azt_Play.end.min = msf.cdmsf_min1; azt_Play.end.sec = msf.cdmsf_sec1; azt_Play.end.frame = msf.cdmsf_frame1; - if (cmd==CDROMREADMODE1) - { sendAztCmd(ACMD_DATA_READ, &azt_Play); + if (cmd==CDROMREADCOOKED) + { sendAztCmd(ACMD_PLAY_READ, &azt_Play); DTEN_LOW; - insb(DATA_PORT,buf,2048); - memcpy_tofs((void *) arg, &buf, 2048); + insb(DATA_PORT,buf,CD_FRAMESIZE); + memcpy_tofs((void *) arg, &buf, CD_FRAMESIZE); } - else /*CDROMREADMODE2*/ - { sendAztCmd(ACMD_DATA_READ_RAW, &azt_Play); + else /*CDROMREADRAW*/ + { sendAztCmd(ACMD_PLAY_READ_RAW, &azt_Play); DTEN_LOW; - insb(DATA_PORT,buf,2336); - memcpy_tofs((void *) arg, &buf, 2336); + insb(DATA_PORT,buf,CD_FRAMESIZE_RAW); + memcpy_tofs((void *) arg, &buf, CD_FRAMESIZE_RAW); } } -#endif /*end of incompatible code*/ - break; + break; +#endif /*end of incompatible code*/ + case CDROMREADMODE0: /*set read data in mode 0, does not work with my drive*/ + printk ("aztcd Status %x\n", getAztStatus()); + return aztSetDiskType(AZT_MODE_0); + case CDROMREADMODE1: /*set read data in mode 1*/ + return aztSetDiskType(AZT_MODE_1); + case CDROMREADMODE2: /*set read data in mode 2*/ + return aztSetDiskType(AZT_MODE_2); default: return -EINVAL; } @@ -895,6 +947,11 @@ static void do_aztcd_request(void) #ifdef AZT_TEST printk(" do_aztcd_request(%ld+%ld) Time:%li\n", CURRENT -> sector, CURRENT -> nr_sectors,jiffies); #endif + if (DiskInfo.audio) + { printk("aztcd: Error, tried to mount an Audio CD\n"); + end_request(0); + return; + } azt_transfer_is_active = 1; while (CURRENT_VALID) { if (CURRENT->bh) { @@ -907,7 +964,7 @@ static void do_aztcd_request(void) } else { azt_buf_out = -1; /* Want to read a block not in buffer */ if (azt_state == AZT_S_IDLE) { - if (!aztTocUpToDate) { + if ((!aztTocUpToDate)||aztDiskChanged) { if (aztUpdateToc() < 0) { while (CURRENT_VALID) end_request(0); @@ -927,7 +984,6 @@ static void do_aztcd_request(void) azt_next_bn, azt_buf_in, azt_buf_out, azt_buf_bn[azt_buf_in]); printk(" do_aztcd_request ends Time:%li\n",jiffies); #endif - } static void azt_poll(void) @@ -944,10 +1000,10 @@ static void azt_poll(void) azt_invalidate_buffers(); #ifdef WARN_IF_READ_FAILURE if (AztTries == 5) - printk("aztcd: read of block %d failed - maybe audio disk?\n", azt_next_bn); + printk("aztcd: Read of Block %d Failed - Maybe Audio Disk?\n", azt_next_bn); #endif if (!AztTries--) { - printk("aztcd: read of block %d failed, maybe audio disk? Giving up\n", azt_next_bn); + printk("aztcd: Read of Block %d Failed, Maybe Audio Disk? Giving up\n", azt_next_bn); if (azt_transfer_is_active) { AztTries = 0; loop_ctl = 0; @@ -996,10 +1052,12 @@ static void azt_poll(void) #endif if (!skip) { if ((st = aztStatus()) != -1) { - if (st & AST_DSK_CHG) { + if ((st & AST_DSK_CHG)||(st & AST_NOT_READY)) { aztDiskChanged = 1; aztTocUpToDate = 0; azt_invalidate_buffers(); + end_request(0); + printk("aztcd: Disk Changed or Not Ready 1 - Unmount Disk!\n"); } } else break; } @@ -1008,6 +1066,8 @@ static void azt_poll(void) if ((st & AST_DOOR_OPEN)||(st & AST_NOT_READY)) { aztDiskChanged = 1; aztTocUpToDate = 0; + printk("aztcd: Disk Changed or Not Ready 2 - Unmount Disk!\n"); + end_request(0); printk((st & AST_DOOR_OPEN) ? "aztcd: door open\n" : "aztcd: disk removed\n"); if (azt_transfer_is_active) { azt_state = AZT_S_START; @@ -1042,10 +1102,12 @@ static void azt_poll(void) #endif if (!skip) { if ((st = aztStatus()) != -1) { - if (st & AST_DSK_CHG) { + if ((st & AST_DSK_CHG)||(st & AST_NOT_READY)) { aztDiskChanged = 1; aztTocUpToDate = 0; azt_invalidate_buffers(); + printk("aztcd: Disk Changed or Not Ready 3 - Unmount Disk!\n"); + end_request(0); } } else break; } @@ -1081,7 +1143,12 @@ static void azt_poll(void) printk("azt_next_bn:%x azt_buf_in:%x azt_buf_out:%x azt_buf_bn:%x\n", \ azt_next_bn, azt_buf_in, azt_buf_out, azt_buf_bn[azt_buf_in]); #endif - sendAztCmd(ACMD_DATA_READ, &msf); + if (azt_read_mode==AZT_MODE_2) + { sendAztCmd(ACMD_PLAY_READ_RAW, &msf); /*XA disks in raw mode*/ + } + else + { sendAztCmd(ACMD_PLAY_READ, &msf); /*others in cooked mode*/ + } azt_state = AZT_S_DATA; AztTimeout = READ_TIMEOUT; } else { @@ -1111,13 +1178,9 @@ static void azt_poll(void) azt_st_old=st; printk("---AFL_DATA st:%x\n",st); } -#endif -#ifdef WARN_IF_READ_FAILURE - if (AztTries == 5) - printk("aztcd: read of block %d failed - maybe audio disk?\n", azt_next_bn); #endif if (!AztTries--) { - printk("aztcd: read of block %d failed, maybe audio disk ? Giving up\n", azt_next_bn); + printk("aztcd: Read of Block %d Failed, Maybe Audio Disk ? Giving up\n", azt_next_bn); if (azt_transfer_is_active) { AztTries = 0; break; @@ -1175,7 +1238,20 @@ static void azt_poll(void) end_request(1); /*should we have here (1) or (0)? */ } else - { insb(DATA_PORT, azt_buf + 2048 * azt_buf_in, 2048); + { if (azt_read_mode==AZT_MODE_2) + { if (DiskInfo.xa) /*With XA disks skip head and tail*/ + { unsigned char tmp_buf[CD_XA_TAIL]; + insb(DATA_PORT, tmp_buf , CD_XA_HEAD_SUBHEAD); + insb(DATA_PORT, azt_buf + CD_FRAMESIZE * azt_buf_in, CD_FRAMESIZE); + insb(DATA_PORT, tmp_buf , CD_XA_TAIL); + } + else + { insb(DATA_PORT, azt_buf + CD_FRAMESIZE_RAW * azt_buf_in, CD_FRAMESIZE_RAW); + } + } + else + { insb(DATA_PORT, azt_buf + CD_FRAMESIZE * azt_buf_in, CD_FRAMESIZE); + } azt_read_count--; #ifdef AZT_TEST3 printk("AZT_S_DATA; ---I've read data- read_count: %d\n",azt_read_count); @@ -1227,9 +1303,10 @@ static void azt_poll(void) while (azt_read_count!=0) { int i; if ( !(inb(STATUS_PORT) & AFL_DATA) ) { - for (i=0; i<2048; i++) { - inb(DATA_PORT); - } + if (azt_read_mode==AZT_MODE_2) + for (i=0; i must set read command to read raw --> to be done ??? +*/ if (aztSetDiskType(DiskInfo.xa ? AZT_MODE_2 : AZT_MODE_1)) return -EIO; + if (DiskInfo.xa) printk("aztcd: XA support not yet tested - please mail 'zimmerma@rz.fht-esslingen.de'\n"); + + /* audio detection was already done in aztGetToc */ + if (DiskInfo.audio) + { printk(("aztcd: Audio-CD found\n")); + } + else + { printk("aztcd: %s%s CD-ROM found\n", + DiskInfo.xa ? "XA " : "", + DiskInfo.multi ? "Multi Session" : "Single Session"); + } + } ++azt_open_count; MOD_INC_USE_COUNT; aztLockDoor(); + + #ifdef AZT_DEBUG printk("aztcd: exiting aztcd_open\n"); #endif @@ -1418,9 +1509,9 @@ int init_module(void) return -EIO; #endif } - printk("Aztech CD-ROM Init: Aztech, Orchid, Okano, Wearnes CD-ROM Driver\n"); - printk("Aztech CD-ROM Init: (C) 1994,1995 Werner Zimmermann\n"); - printk("Aztech CD-ROM Init: DriverVersion=%s BaseAddress=0x%x \n",AZT_VERSION,azt_port); + printk("aztcd: Aztech, Orchid, Okano, Wearnes CD-ROM Driver\n"); + printk("aztcd: (C) 1994,1995 Werner Zimmermann\n"); + printk("aztcd: DriverVersion=%s BaseAddress=0x%x \n",AZT_VERSION,azt_port); if (check_region(azt_port, 4)) { printk("aztcd: conflict, I/O port (%X) already used\n", @@ -1508,25 +1599,25 @@ int init_module(void) } if (count>30) max_count=30; /*print max.30 chars of the version string*/ else max_count=count; - printk("Aztech CD-ROM Init: FirmwareVersion="); + printk("aztcd: FirmwareVersion="); for (count=1;count 0 ? 0 : -1; diff --git a/drivers/block/cdu31a.c b/drivers/block/cdu31a.c index 7c43dee9b530..9c3402c1eff0 100644 --- a/drivers/block/cdu31a.c +++ b/drivers/block/cdu31a.c @@ -160,6 +160,17 @@ * 4, but I think that is a mistake. */ +#include +#include + +#ifdef MODULE +# include +# include +# ifndef CONFIG_MODVERSIONS + char kernel_version[]= UTS_RELEASE; +# endif +#endif + #include #include #include @@ -237,7 +248,7 @@ static unsigned int sony_blocks_left = 0; /* Number of 512 byte blocks left /* The base I/O address of the Sony Interface. This is a variable (not a #define) so it can be easily changed via some future ioctl() */ -static unsigned short sony_cd_base_io = 0; +static unsigned short cdu31a_port = 0; /* * The following are I/O addresses of the various registers for the drive. The @@ -267,15 +278,15 @@ static unsigned int sony_usage = 0; /* How many processes have the static int sony_pas_init = 0; /* Initialize the Pro-Audio Spectrum card? */ -static struct s_sony_session_toc *sony_toc; /* Points to the +static struct s_sony_session_toc sony_toc; /* Holds the table of contents. */ static int sony_toc_read = 0; /* Has the TOC been read for the drive? */ -static struct s_sony_subcode * volatile last_sony_subcode; /* Points to the last - subcode address read */ +static struct s_sony_subcode last_sony_subcode; /* Points to the last + subcode address read */ static volatile int sony_inuse = 0; /* Is the drive in use? Only one operation at a time allowed */ @@ -305,7 +316,7 @@ static unsigned volatile char cur_pos_msf[3] = { 0, 0, 0 }; static unsigned volatile char final_pos_msf[3] = { 0, 0, 0 }; /* What IRQ is the drive using? 0 if none. */ -static int irq_used = 0; +static int cdu31a_irq = 0; /* The interrupt handler will wake this queue up when it gets an interrupts. */ @@ -321,7 +332,7 @@ static char disk_changed; /* Variable for using the readahead buffer. The readahead buffer is used for raw sector reads and for blocksizes that are smaller than 2048 bytes. */ -static char *readahead_buffer = NULL; /* Used for 1024 byte blocksize. */ +static char readahead_buffer[CD_FRAMESIZE_RAW]; static int readahead_dataleft = 0; static int readahead_bad = 0; @@ -330,6 +341,11 @@ static int readahead_bad = 0; the drive from flashing for very long. */ static struct timer_list cdu31a_abort_timer; +/* Marks if the timeout has started an abort read. This is used + on entry to the drive to tell the code to read out the status + from the abort read. */ +static int abort_read_started = 0; + /* * This routine returns 1 if the disk has been changed since the last @@ -387,7 +403,7 @@ sony_sleep(void) { unsigned long flags; - if (irq_used <= 0) + if (cdu31a_irq <= 0) { current->state = TASK_INTERRUPTIBLE; current->timeout = jiffies; @@ -799,13 +815,14 @@ do_sony_cd_cmd(unsigned char cmd, { recursive_call = 1; } - restore_flags(flags); num_retries = 0; retry_cd_operation: while (handle_sony_cd_attention()) ; + + sti(); retry_count = jiffies + SONY_JIFFIES_TIMEOUT; while ((retry_count > jiffies) && (is_busy())) @@ -851,6 +868,8 @@ retry_cd_operation: sony_inuse = 0; wake_up_interruptible(&sony_wait); } + + restore_flags(flags); } @@ -868,9 +887,26 @@ handle_sony_cd_attention(void) { unsigned char atten_code; static int num_consecutive_attentions = 0; + volatile int val; - if (is_attention()) + if (abort_read_started) + { + while (is_result_reg_not_empty()) + { + val = read_result_register(); + } + clear_data_ready(); + clear_result_ready(); + /* Clear out the data */ + while (is_data_requested()) + { + val = read_data_register(); + } + abort_read_started = 0; + return(1); + } + else if (is_attention()) { if (num_consecutive_attentions > CDU31A_MAX_CONSECUTIVE_ATTENTIONS) { @@ -1018,9 +1054,9 @@ start_request(unsigned int sector, * If the full read-ahead would go beyond the end of the media, trim * it back to read just till the end of the media. */ - else if ((sector + nsect) >= sony_toc->lead_out_start_lba) + else if ((sector + nsect) >= sony_toc.lead_out_start_lba) { - read_size = sony_toc->lead_out_start_lba - sector; + read_size = sony_toc.lead_out_start_lba - sector; } /* Read the full readahead amount. */ else @@ -1106,7 +1142,22 @@ abort_read(void) static void handle_abort_timeout(unsigned long data) { - abort_read(); + /* If it is in use, ignore it. */ + if (!sony_inuse) + { + /* We can't use abort_read(), because it will sleep + or schedule in the timer interrupt. Just start + the operation, finish it on the next access to + the drive. */ + clear_result_ready(); + clear_param_reg(); + write_cmd(SONY_ABORT_CMD); + + sony_blocks_left = 0; + readahead_dataleft = 0; + readahead_bad = 0; + abort_read_started = 1; + } } /* Actually get data and status from the drive. */ @@ -1411,12 +1462,13 @@ do_cdu31a_request(void) } sony_inuse = 1; has_cd_task = current; - sti(); /* Get drive status before doing anything. */ while (handle_sony_cd_attention()) ; + sti(); + /* If the timer is running, cancel it. */ if (cdu31a_abort_timer.next != NULL) { @@ -1478,7 +1530,7 @@ cdu31a_request_startover: if (block < 80) { /* Offset the request into the session. */ - block += (sony_toc->start_track_lba * 4); + block += (sony_toc.start_track_lba * 4); } switch(CURRENT->cmd) @@ -1489,20 +1541,20 @@ cdu31a_request_startover: * the media, return an error. */ #if 0 - if ((block / 4) < sony_toc->start_track_lba) + if ((block / 4) < sony_toc.start_track_lba) { printk("CDU31A: Request before beginning of media\n"); end_request(0); goto cdu31a_request_startover; } #endif - if ((block / 4) >= sony_toc->lead_out_start_lba) + if ((block / 4) >= sony_toc.lead_out_start_lba) { printk("CDU31A: Request past end of media\n"); end_request(0); goto cdu31a_request_startover; } - if (((block + nblock) / 4) >= sony_toc->lead_out_start_lba) + if (((block + nblock) / 4) >= sony_toc.lead_out_start_lba) { printk("CDU31A: Request past end of media\n"); end_request(0); @@ -1599,7 +1651,7 @@ end_do_cdu31a_request: #else /* Start a timer to time out after a while to disable the read. */ - cdu31a_abort_timer.expires = 200; /* Wait 2 seconds */ + cdu31a_abort_timer.expires = jiffies + 2*HZ; /* Wait 2 seconds */ add_timer(&cdu31a_abort_timer); #endif @@ -1694,9 +1746,9 @@ sony_get_toc(void) do_sony_cd_cmd(SONY_REQ_TOC_DATA_SPEC_CMD, parms, 1, - (unsigned char *) sony_toc, + (unsigned char *) &sony_toc, &res_size); - if ((res_size < 2) || ((sony_toc->exec_status[0] & 0xf0) == 0x20)) + if ((res_size < 2) || ((sony_toc.exec_status[0] & 0xf0) == 0x20)) { /* An error reading the TOC. Return without sony_toc_read set. */ @@ -1707,57 +1759,57 @@ sony_get_toc(void) /* For points that do not exist, move the data over them to the right location. */ - if (sony_toc->pointb0 != 0xb0) + if (sony_toc.pointb0 != 0xb0) { - mcovlp(((char *) sony_toc) + 27, - ((char *) sony_toc) + 18, + mcovlp(((char *) &sony_toc) + 27, + ((char *) &sony_toc) + 18, res_size - 18); res_size += 9; } - if (sony_toc->pointb1 != 0xb1) + if (sony_toc.pointb1 != 0xb1) { - mcovlp(((char *) sony_toc) + 36, - ((char *) sony_toc) + 27, + mcovlp(((char *) &sony_toc) + 36, + ((char *) &sony_toc) + 27, res_size - 27); res_size += 9; } - if (sony_toc->pointb2 != 0xb2) + if (sony_toc.pointb2 != 0xb2) { - mcovlp(((char *) sony_toc) + 45, - ((char *) sony_toc) + 36, + mcovlp(((char *) &sony_toc) + 45, + ((char *) &sony_toc) + 36, res_size - 36); res_size += 9; } - if (sony_toc->pointb3 != 0xb3) + if (sony_toc.pointb3 != 0xb3) { - mcovlp(((char *) sony_toc) + 54, - ((char *) sony_toc) + 45, + mcovlp(((char *) &sony_toc) + 54, + ((char *) &sony_toc) + 45, res_size - 45); res_size += 9; } - if (sony_toc->pointb4 != 0xb4) + if (sony_toc.pointb4 != 0xb4) { - mcovlp(((char *) sony_toc) + 63, - ((char *) sony_toc) + 54, + mcovlp(((char *) &sony_toc) + 63, + ((char *) &sony_toc) + 54, res_size - 54); res_size += 9; } - if (sony_toc->pointc0 != 0xc0) + if (sony_toc.pointc0 != 0xc0) { - mcovlp(((char *) sony_toc) + 72, - ((char *) sony_toc) + 63, + mcovlp(((char *) &sony_toc) + 72, + ((char *) &sony_toc) + 63, res_size - 63); res_size += 9; } - sony_toc->start_track_lba = msf_to_log(sony_toc->tracks[0].track_start_msf); - sony_toc->lead_out_start_lba = msf_to_log(sony_toc->lead_out_start_msf); + sony_toc.start_track_lba = msf_to_log(sony_toc.tracks[0].track_start_msf); + sony_toc.lead_out_start_lba = msf_to_log(sony_toc.lead_out_start_msf); #if DEBUG printk("Disk session %d, start track: %d, stop track: %d\n", session, - sony_toc->start_track_lba, - sony_toc->lead_out_start_lba); + sony_toc.start_track_lba, + sony_toc.lead_out_start_lba); #endif } #if DEBUG @@ -1776,10 +1828,10 @@ find_track(int track) int num_tracks; - num_tracks = sony_toc->last_track_num - sony_toc->first_track_num + 1; + num_tracks = sony_toc.last_track_num - sony_toc.first_track_num + 1; for (i = 0; i < num_tracks; i++) { - if (sony_toc->tracks[i].track == track) + if (sony_toc.tracks[i].track == track) { return i; } @@ -1801,12 +1853,12 @@ read_subcode(void) do_sony_cd_cmd(SONY_REQ_SUBCODE_ADDRESS_CMD, NULL, 0, - (unsigned char *) last_sony_subcode, + (unsigned char *) &last_sony_subcode, &res_size); - if ((res_size < 2) || ((last_sony_subcode->exec_status[0] & 0xf0) == 0x20)) + if ((res_size < 2) || ((last_sony_subcode.exec_status[0] & 0xf0) == 0x20)) { printk("Sony CDROM error 0x%2.2x (read_subcode)\n", - last_sony_subcode->exec_status[1]); + last_sony_subcode.exec_status[1]); return -EIO; } @@ -1868,24 +1920,24 @@ sony_get_subchnl_info(long arg) } schi.cdsc_audiostatus = sony_audio_status; - schi.cdsc_adr = last_sony_subcode->address; - schi.cdsc_ctrl = last_sony_subcode->control; - schi.cdsc_trk = bcd_to_int(last_sony_subcode->track_num); - schi.cdsc_ind = bcd_to_int(last_sony_subcode->index_num); + schi.cdsc_adr = last_sony_subcode.address; + schi.cdsc_ctrl = last_sony_subcode.control; + schi.cdsc_trk = bcd_to_int(last_sony_subcode.track_num); + schi.cdsc_ind = bcd_to_int(last_sony_subcode.index_num); if (schi.cdsc_format == CDROM_MSF) { - schi.cdsc_absaddr.msf.minute = bcd_to_int(last_sony_subcode->abs_msf[0]); - schi.cdsc_absaddr.msf.second = bcd_to_int(last_sony_subcode->abs_msf[1]); - schi.cdsc_absaddr.msf.frame = bcd_to_int(last_sony_subcode->abs_msf[2]); + schi.cdsc_absaddr.msf.minute = bcd_to_int(last_sony_subcode.abs_msf[0]); + schi.cdsc_absaddr.msf.second = bcd_to_int(last_sony_subcode.abs_msf[1]); + schi.cdsc_absaddr.msf.frame = bcd_to_int(last_sony_subcode.abs_msf[2]); - schi.cdsc_reladdr.msf.minute = bcd_to_int(last_sony_subcode->rel_msf[0]); - schi.cdsc_reladdr.msf.second = bcd_to_int(last_sony_subcode->rel_msf[1]); - schi.cdsc_reladdr.msf.frame = bcd_to_int(last_sony_subcode->rel_msf[2]); + schi.cdsc_reladdr.msf.minute = bcd_to_int(last_sony_subcode.rel_msf[0]); + schi.cdsc_reladdr.msf.second = bcd_to_int(last_sony_subcode.rel_msf[1]); + schi.cdsc_reladdr.msf.frame = bcd_to_int(last_sony_subcode.rel_msf[2]); } else if (schi.cdsc_format == CDROM_LBA) { - schi.cdsc_absaddr.lba = msf_to_log(last_sony_subcode->abs_msf); - schi.cdsc_reladdr.lba = msf_to_log(last_sony_subcode->rel_msf); + schi.cdsc_absaddr.lba = msf_to_log(last_sony_subcode.abs_msf); + schi.cdsc_reladdr.lba = msf_to_log(last_sony_subcode.rel_msf); } memcpy_tofs((char *) arg, &schi, sizeof(schi)); @@ -2217,12 +2269,13 @@ exit_read_audio: return(retval); } -/* - * The big ugly ioctl handler. - */ - -static int do_sony_cd_cmd_chk(char *name, unsigned char cmd, unsigned char *params, unsigned int num_params, - unsigned char *result_buffer, unsigned int *result_size) +static int +do_sony_cd_cmd_chk(char *name, + unsigned char cmd, + unsigned char *params, + unsigned int num_params, + unsigned char *result_buffer, + unsigned int *result_size) { do_sony_cd_cmd(cmd, params, num_params, result_buffer, result_size); if ((*result_size < 2) || ((result_buffer[0] & 0xf0) == 0x20)) @@ -2233,6 +2286,9 @@ static int do_sony_cd_cmd_chk(char *name, unsigned char cmd, unsigned char *para return 0; } +/* + * The big ugly ioctl handler. + */ static int scd_ioctl(struct inode *inode, struct file *file, unsigned int cmd, @@ -2274,9 +2330,9 @@ static int scd_ioctl(struct inode *inode, { return -EIO; } - cur_pos_msf[0] = last_sony_subcode->abs_msf[0]; - cur_pos_msf[1] = last_sony_subcode->abs_msf[1]; - cur_pos_msf[2] = last_sony_subcode->abs_msf[2]; + cur_pos_msf[0] = last_sony_subcode.abs_msf[0]; + cur_pos_msf[1] = last_sony_subcode.abs_msf[1]; + cur_pos_msf[2] = last_sony_subcode.abs_msf[2]; sony_audio_status = CDROM_AUDIO_PAUSED; return 0; break; @@ -2340,8 +2396,8 @@ static int scd_ioctl(struct inode *inode, i=verify_area(VERIFY_WRITE, hdr, sizeof(*hdr)); if(i<0) return i; - loc_hdr.cdth_trk0 = bcd_to_int(sony_toc->first_track_num); - loc_hdr.cdth_trk1 = bcd_to_int(sony_toc->last_track_num); + loc_hdr.cdth_trk0 = bcd_to_int(sony_toc.first_track_num); + loc_hdr.cdth_trk1 = bcd_to_int(sony_toc.last_track_num); memcpy_tofs(hdr, &loc_hdr, sizeof(*hdr)); } return 0; @@ -2372,9 +2428,9 @@ static int scd_ioctl(struct inode *inode, /* Lead out is handled separately since it is special. */ if (loc_entry.cdte_track == CDROM_LEADOUT) { - loc_entry.cdte_adr = sony_toc->address2; - loc_entry.cdte_ctrl = sony_toc->control2; - msf_val = sony_toc->lead_out_start_msf; + loc_entry.cdte_adr = sony_toc.address2; + loc_entry.cdte_ctrl = sony_toc.control2; + msf_val = sony_toc.lead_out_start_msf; } else { @@ -2384,9 +2440,9 @@ static int scd_ioctl(struct inode *inode, return -EINVAL; } - loc_entry.cdte_adr = sony_toc->tracks[track_idx].address; - loc_entry.cdte_ctrl = sony_toc->tracks[track_idx].control; - msf_val = sony_toc->tracks[track_idx].track_start_msf; + loc_entry.cdte_adr = sony_toc.tracks[track_idx].address; + loc_entry.cdte_ctrl = sony_toc.tracks[track_idx].control; + msf_val = sony_toc.tracks[track_idx].track_start_msf; } /* Logical buffer address or MSF format requested? */ @@ -2421,8 +2477,8 @@ static int scd_ioctl(struct inode *inode, return i; memcpy_fromfs(&ti, (char *) arg, sizeof(ti)); - if ( (ti.cdti_trk0 < sony_toc->first_track_num) - || (ti.cdti_trk0 > sony_toc->last_track_num) + if ( (ti.cdti_trk0 < sony_toc.first_track_num) + || (ti.cdti_trk0 > sony_toc.last_track_num) || (ti.cdti_trk1 < ti.cdti_trk0)) { return -EINVAL; @@ -2433,17 +2489,17 @@ static int scd_ioctl(struct inode *inode, { return -EINVAL; } - params[1] = sony_toc->tracks[track_idx].track_start_msf[0]; - params[2] = sony_toc->tracks[track_idx].track_start_msf[1]; - params[3] = sony_toc->tracks[track_idx].track_start_msf[2]; + params[1] = sony_toc.tracks[track_idx].track_start_msf[0]; + params[2] = sony_toc.tracks[track_idx].track_start_msf[1]; + params[3] = sony_toc.tracks[track_idx].track_start_msf[2]; /* * If we want to stop after the last track, use the lead-out * MSF to do that. */ - if (ti.cdti_trk1 >= bcd_to_int(sony_toc->last_track_num)) + if (ti.cdti_trk1 >= bcd_to_int(sony_toc.last_track_num)) { - log_to_msf(msf_to_log(sony_toc->lead_out_start_msf)-1, + log_to_msf(msf_to_log(sony_toc.lead_out_start_msf)-1, &(params[4])); } else @@ -2453,7 +2509,7 @@ static int scd_ioctl(struct inode *inode, { return -EINVAL; } - log_to_msf(msf_to_log(sony_toc->tracks[track_idx].track_start_msf)-1, + log_to_msf(msf_to_log(sony_toc.tracks[track_idx].track_start_msf)-1, &(params[4])); } params[0] = 0x03; @@ -2525,8 +2581,8 @@ static int scd_ioctl(struct inode *inode, if (ra.addr_format == CDROM_LBA) { - if ( (ra.addr.lba >= sony_toc->lead_out_start_lba) - || (ra.addr.lba + ra.nframes >= sony_toc->lead_out_start_lba)) + if ( (ra.addr.lba >= sony_toc.lead_out_start_lba) + || (ra.addr.lba + ra.nframes >= sony_toc.lead_out_start_lba)) { return -EINVAL; } @@ -2543,8 +2599,8 @@ static int scd_ioctl(struct inode *inode, ra.addr.lba = ( (ra.addr.msf.minute * 4500) + (ra.addr.msf.second * 75) + ra.addr.msf.frame); - if ( (ra.addr.lba >= sony_toc->lead_out_start_lba) - || (ra.addr.lba + ra.nframes >= sony_toc->lead_out_start_lba)) + if ( (ra.addr.lba >= sony_toc.lead_out_start_lba) + || (ra.addr.lba + ra.nframes >= sony_toc.lead_out_start_lba)) { return -EINVAL; } @@ -2638,7 +2694,7 @@ respinup_on_open: /* For XA on the CDU31A only, we have to do special reads. The CDU33A handles XA automagically. */ - if ( (sony_toc->disk_type == SONY_XA_DISK_TYPE) + if ( (sony_toc.disk_type == SONY_XA_DISK_TYPE) && (!is_double_speed)) { params[0] = SONY_SD_DECODE_PARAM; @@ -2743,17 +2799,17 @@ get_drive_configuration(unsigned short base_io, /* Set the base address */ - sony_cd_base_io = base_io; + cdu31a_port = base_io; /* Set up all the register locations */ - sony_cd_cmd_reg = sony_cd_base_io + SONY_CMD_REG_OFFSET; - sony_cd_param_reg = sony_cd_base_io + SONY_PARAM_REG_OFFSET; - sony_cd_write_reg = sony_cd_base_io + SONY_WRITE_REG_OFFSET; - sony_cd_control_reg = sony_cd_base_io + SONY_CONTROL_REG_OFFSET; - sony_cd_status_reg = sony_cd_base_io + SONY_STATUS_REG_OFFSET; - sony_cd_result_reg = sony_cd_base_io + SONY_RESULT_REG_OFFSET; - sony_cd_read_reg = sony_cd_base_io + SONY_READ_REG_OFFSET; - sony_cd_fifost_reg = sony_cd_base_io + SONY_FIFOST_REG_OFFSET; + sony_cd_cmd_reg = cdu31a_port + SONY_CMD_REG_OFFSET; + sony_cd_param_reg = cdu31a_port + SONY_PARAM_REG_OFFSET; + sony_cd_write_reg = cdu31a_port + SONY_WRITE_REG_OFFSET; + sony_cd_control_reg = cdu31a_port + SONY_CONTROL_REG_OFFSET; + sony_cd_status_reg = cdu31a_port + SONY_STATUS_REG_OFFSET; + sony_cd_result_reg = cdu31a_port + SONY_RESULT_REG_OFFSET; + sony_cd_read_reg = cdu31a_port + SONY_READ_REG_OFFSET; + sony_cd_fifost_reg = cdu31a_port + SONY_FIFOST_REG_OFFSET; /* * Check to see if anything exists at the status register location. @@ -2806,11 +2862,11 @@ cdu31a_setup(char *strings, { if (ints[0] > 0) { - sony_cd_base_io = ints[1]; + cdu31a_port = ints[1]; } if (ints[0] > 1) { - irq_used = ints[2]; + cdu31a_irq = ints[2]; } if ((strings != NULL) && (*strings != '\0')) { @@ -2830,8 +2886,13 @@ static int cdu31a_block_size; /* * Initialize the driver. */ +#ifndef MODULE unsigned long cdu31a_init(unsigned long mem_start, unsigned long mem_end) +#else +int +init_module(void) +#endif { struct s_sony_drive_config drive_config; unsigned int res_size; @@ -2856,15 +2917,15 @@ cdu31a_init(unsigned long mem_start, unsigned long mem_end) drive_found = 0; /* Setting the base I/O address to 0xffff will disable it. */ - if (sony_cd_base_io == 0xffff) + if (cdu31a_port == 0xffff) { } - else if (sony_cd_base_io != 0) + else if (cdu31a_port != 0) { - tmp_irq = irq_used; /* Need IRQ 0 because we can't sleep here. */ - irq_used = 0; + tmp_irq = cdu31a_irq; /* Need IRQ 0 because we can't sleep here. */ + cdu31a_irq = 0; - get_drive_configuration(sony_cd_base_io, + get_drive_configuration(cdu31a_port, drive_config.exec_status, &res_size); if ((res_size > 2) && ((drive_config.exec_status[0] & 0xf0) == 0x00)) @@ -2872,11 +2933,11 @@ cdu31a_init(unsigned long mem_start, unsigned long mem_end) drive_found = 1; } - irq_used = tmp_irq; + cdu31a_irq = tmp_irq; } else { - irq_used = 0; + cdu31a_irq = 0; i = 0; while ( (cdu31a_addresses[i].base != 0) && (!drive_found)) @@ -2891,7 +2952,7 @@ cdu31a_init(unsigned long mem_start, unsigned long mem_end) if ((res_size > 2) && ((drive_config.exec_status[0] & 0xf0) == 0x00)) { drive_found = 1; - irq_used = cdu31a_addresses[i].int_num; + cdu31a_irq = cdu31a_addresses[i].int_num; } else { @@ -2902,12 +2963,16 @@ cdu31a_init(unsigned long mem_start, unsigned long mem_end) if (drive_found) { - request_region(sony_cd_base_io, 4,"cdu31a"); + request_region(cdu31a_port, 4,"cdu31a"); if (register_blkdev(MAJOR_NR,"cdu31a",&scd_fops)) { printk("Unable to get major %d for CDU-31a\n", MAJOR_NR); +#ifdef MODULE + return -EIO; +#else return mem_start; +#endif } if (SONY_HWC_DOUBLE_SPEED(drive_config)) @@ -2915,35 +2980,19 @@ cdu31a_init(unsigned long mem_start, unsigned long mem_end) is_double_speed = 1; } - /* A negative irq_used will attempt an autoirq. */ - if (irq_used < 0) - { - autoirq_setup(0); - enable_interrupts(); - reset_drive(); - tmp_irq = autoirq_report(10); - disable_interrupts(); - - irq_used = 0; - set_drive_params(); - irq_used = tmp_irq; - } - else - { - tmp_irq = irq_used; /* Need IRQ 0 because we can't sleep here. */ - irq_used = 0; + tmp_irq = cdu31a_irq; /* Need IRQ 0 because we can't sleep here. */ + cdu31a_irq = 0; - set_drive_params(); + set_drive_params(); - irq_used = tmp_irq; - } + cdu31a_irq = tmp_irq; - if (irq_used > 0) + if (cdu31a_irq > 0) { - if (request_irq(irq_used, cdu31a_interrupt, SA_INTERRUPT, "cdu31a")) + if (request_irq(cdu31a_irq, cdu31a_interrupt, SA_INTERRUPT, "cdu31a")) { - printk("Unable to grab IRQ%d for the CDU31A driver\n", irq_used); - irq_used = 0; + printk("Unable to grab IRQ%d for the CDU31A driver\n", cdu31a_irq); + cdu31a_irq = 0; } } @@ -2977,9 +3026,9 @@ cdu31a_init(unsigned long mem_start, unsigned long mem_end) { printk(", double speed"); } - if (irq_used > 0) + if (cdu31a_irq > 0) { - printk(", irq %d", irq_used); + printk(", irq %d", cdu31a_irq); } printk("\n"); @@ -2989,13 +3038,6 @@ cdu31a_init(unsigned long mem_start, unsigned long mem_end) /* use 'mount -o block=2048' */ blksize_size[MAJOR_NR] = &cdu31a_block_size; - last_sony_subcode = (struct s_sony_subcode *) mem_start; - mem_start += sizeof(*last_sony_subcode); - readahead_buffer = (unsigned char *) mem_start; - mem_start += CD_FRAMESIZE_RAW; - sony_toc = (struct s_sony_session_toc *) mem_start; - mem_start += sizeof(struct s_sony_session_toc); - cdu31a_abort_timer.next = NULL; cdu31a_abort_timer.prev = NULL; cdu31a_abort_timer.function = handle_abort_timeout; @@ -3004,5 +3046,36 @@ cdu31a_init(unsigned long mem_start, unsigned long mem_end) disk_changed = 1; +#ifdef MODULE + if (drive_found) + { + return(0); + } + else + { + return -EIO; + } +#else return mem_start; +#endif } + +#ifdef MODULE +void +cleanup_module(void) +{ + if (sony_usage != 0) + { + printk("cdu31a module in use - can't remove it.\n"); + return; + } + + if ((unregister_blkdev(MAJOR_NR, "cdu31a") == -EINVAL)) + { + printk("Can't unregister cdu31a\n"); + return; + } + release_region(cdu31a_port,4); + printk("cdu31a module released.\n"); +} +#endif MODULE diff --git a/drivers/block/cm206.c b/drivers/block/cm206.c index 73402e3e49ff..e5f7a50c0166 100644 --- a/drivers/block/cm206.c +++ b/drivers/block/cm206.c @@ -302,7 +302,7 @@ void cm206_timeout(unsigned long who) int sleep_or_timeout(struct wait_queue ** wait, int timeout) { cd->timer.data=(unsigned long) wait; - cd->timer.expires = timeout; + cd->timer.expires = jiffies + timeout; add_timer(&cd->timer); interruptible_sleep_on(wait); del_timer(&cd->timer); diff --git a/drivers/block/floppy.c b/drivers/block/floppy.c index 72c561949fab..4fb930639c49 100644 --- a/drivers/block/floppy.c +++ b/drivers/block/floppy.c @@ -599,10 +599,10 @@ static void reschedule_timeout(int drive, char *message, int marg) drive = current_drive; del_timer(&fd_timeout); if (drive < 0 || drive > N_DRIVE) { - fd_timeout.expires = 2000; + fd_timeout.expires = jiffies + 20*HZ; drive=0; } else - fd_timeout.expires = UDP->timeout; + fd_timeout.expires = jiffies + UDP->timeout; add_timer(&fd_timeout); if (UDP->flags & FD_DEBUG){ DPRINT("reschedule timeout "); @@ -671,7 +671,7 @@ static int disk_change(int drive) if (UDP->flags & FD_BROKEN_DCL) return UTESTF(FD_DISK_CHANGED); if( (inb_p(FD_DIR) ^ UDP->flags) & 0x80){ - USETF(FD_VERIFY); /* verify write protection */ + USETF(FD_VERIFY); /* verify write protection */ if(UDRS->maxblock){ /* mark it changed */ USETF(FD_DISK_CHANGED); @@ -714,9 +714,9 @@ static int set_dor(int fdc, char mask, char data) if(is_selected(olddor, unit) && !is_selected(newdor,unit)){ drive = REVDRIVE(fdc,unit); #ifdef DCL_DEBUG - if (UDP->flags & FD_DEBUG){ - DPRINT("calling disk change from set_dor\n"); - } + if (UDP->flags & FD_DEBUG){ + DPRINT("calling disk change from set_dor\n"); + } #endif disk_change(drive); } @@ -858,7 +858,7 @@ static void floppy_off(unsigned int drive) delta = jiffies - UDRS->first_read_date + HZ - UDP->spindown_offset; delta = (( delta * UDP->rps) % HZ ) / UDP->rps; - motor_off_timer[drive].expires = UDP->spindown - delta; + motor_off_timer[drive].expires = jiffies + UDP->spindown - delta; } add_timer(motor_off_timer+drive); } @@ -908,7 +908,7 @@ static void fd_watchdog(void) } else { del_timer(&fd_timer); fd_timer.function = (timeout_fn) fd_watchdog; - fd_timer.expires = 10; + fd_timer.expires = jiffies + 10; add_timer(&fd_timer); } } @@ -932,7 +932,7 @@ static int wait_for_completion(int delay, timeout_fn function) if ( jiffies < delay ){ del_timer(&fd_timer); fd_timer.function = function; - fd_timer.expires = delay - jiffies; + fd_timer.expires = delay; add_timer(&fd_timer); return 1; } @@ -1730,7 +1730,7 @@ void show_floppy(void) printk("fd_timer.function=%p\n", fd_timer.function); if(fd_timeout.prev){ printk("timer_table=%p\n",fd_timeout.function); - printk("expires=%ld\n",fd_timeout.expires); + printk("expires=%ld\n",fd_timeout.expires-jiffies); printk("now=%ld\n",jiffies); } printk("cont=%p\n", cont); @@ -2730,7 +2730,8 @@ static struct cont_t poll_cont={ generic_failure, generic_done }; -static int poll_drive(int interruptible, int flag){ +static int poll_drive(int interruptible, int flag) +{ int ret; /* no auto-sense, just clear dcl */ raw_cmd.flags= flag; @@ -3311,7 +3312,7 @@ static int check_floppy_change(dev_t dev) return 0; } - if (UTESTF(FD_DISK_CHANGED)) + if (UTESTF(FD_DISK_CHANGED) || UTESTF(FD_VERIFY)) return 1; if(UDRS->last_checked + UDP->checkfreq < jiffies){ @@ -3319,8 +3320,9 @@ static int check_floppy_change(dev_t dev) poll_drive(0,0); process_fd_request(); } - + if(UTESTF(FD_DISK_CHANGED) || + UTESTF(FD_VERIFY) || test_bit(drive, &fake_change) || (!TYPE(dev) && !current_type[drive])) return 1; @@ -3338,9 +3340,12 @@ static int floppy_revalidate(dev_t dev) int drive=DRIVE(dev); int cf; - if(UTESTF(FD_DISK_CHANGED) || test_bit(drive, &fake_change) || NO_GEOM){ + if(UTESTF(FD_DISK_CHANGED) || + UTESTF(FD_VERIFY) || + test_bit(drive, &fake_change) || + NO_GEOM){ lock_fdc(drive,0); - cf = UTESTF(FD_DISK_CHANGED); + cf = UTESTF(FD_DISK_CHANGED) || UTESTF(FD_VERIFY); if(! (cf || test_bit(drive, &fake_change) || NO_GEOM)){ process_fd_request(); /*already done by another thread*/ return 0; @@ -3556,7 +3561,7 @@ void floppy_setup(char *str, int *ints) return; } } - DPRINT1("unknown floppy option %s\n", str); + DPRINT1("unknown floppy option [%s]\n", str); DPRINT("allowed options are:"); for(i=0; i< ARRAY_SIZE(config_params); i++) printk(" %s",config_params[i].name); @@ -3759,44 +3764,51 @@ static void floppy_release_irq_and_dma(void) extern char *get_options(char *str, int *ints); -#if 0 -/* assuming that insmod is compiled as a.out binary using a shared - C library ... */ -int ENVIRON = 0x60090b34; - -static void -mod_setup(char *name, - void (*setup)(char *, int *)) { - char **environ,*env,*ptr,c,i; - char line[100]; +static void mod_setup(char *pattern, void (*setup)(char *, int *)) +{ + int i; + char c; + int j; + int match; + char buffer[100]; int ints[11]; - - environ = (char **) get_fs_long( ENVIRON ); - - while((env = (char *)get_fs_long(environ))){ - for(i=0; imm->env_start; + i< current->mm->env_end; + i ++){ + c= get_fs_byte(i); + if(match){ + if(j==99) + c='\0'; + buffer[j] = c; + if(!c || c == ' ' || c == '\t'){ + if(j){ + buffer[j] = '\0'; + setup(get_options(buffer,ints),ints); + } + j=0; + } else + j++; + if(!c) break; - if(i == strlen(name)){ - ptr=line; - while(ptr < line+99){ - c = (char)get_fs_byte(env++); - if ( c== ' ' || !c ){ - *ptr='\0'; - if(ptr!=line) - setup(get_options(line,ints), - ints); - ptr=line; - if (!c) - break; - } else - *ptr++ = c; - } + continue; + } + if( (!j && !c) || + ( j && c == pattern[j-1])) + j++; + else + j=0; + if(j==length){ + match=1; + j=0; } - environ++; } } -#endif + #ifdef __cplusplus extern "C" { @@ -3806,8 +3818,7 @@ int init_module(void) int ret; printk("inserting floppy driver for %s\n", kernel_version); - /*mod_setup("floppy=", floppy_setup);*/ - /* Can't do that any more, insmod is now ELF */ + mod_setup("floppy=", floppy_setup); ret = floppy_init(); return 0; diff --git a/drivers/block/genhd.c b/drivers/block/genhd.c index 00124b71fc4c..db310d43d406 100644 --- a/drivers/block/genhd.c +++ b/drivers/block/genhd.c @@ -12,13 +12,16 @@ /* * Support for DiskManager v6.0x added by Mark Lord (mlord@bnr.ca) - * with hints from uwe@eas.iis.fhg.de (us3@irz.inf.tu-dresden.de). + * with information provided by OnTrack. This now works for linux fdisk + * and LILO, as well as loadlin and bootln. Note that disks other than + * /dev/hda *must* have a "DOS" type 0x51 partition in the first slot (hda1). */ #include #include #include #include +#include struct gendisk *gendisk_head = NULL; @@ -110,17 +113,14 @@ done: static int msdos_partition(struct gendisk *hd, unsigned int dev, unsigned long first_sector) { - int i, minor = current_minor, found_dm6 = 0; + int i, minor = current_minor, tested_for_dm6 = 0; struct buffer_head *bh; struct partition *p; int mask = (1 << hd->minor_shift) - 1; -#ifdef CONFIG_BLK_DEV_IDE - extern void ide_xlate_1024(dev_t); -#endif read_mbr: if (!(bh = bread(dev,0,1024))) { - printk("unable to read partition table\n"); + printk(" unable to read partition table\n"); return -1; } if (*(unsigned short *) (0x1fe + bh->b_data) != 0xAA55) { @@ -129,47 +129,50 @@ read_mbr: } p = (struct partition *) (0x1be + bh->b_data); - /* - * Check for Disk Manager v6.0x "Dynamic Disk Overlay" (DDO) - */ - if (p->sys_ind == DM6_PARTITION && !found_dm6++) - { - printk(" [DM6:DDO]"); - /* - * Everything is offset by one track (p->end_sector sectors), - * and a translated geometry is used to reduce the number - * of apparent cylinders to 1024 or less. - * - * For complete compatibility with linux fdisk, we do: - * 1. tell the driver to offset *everything* by one track, - * 2. reduce the apparent disk capacity by one track, - * 3. adjust the geometry reported by HDIO_GETGEO (for fdisk), - * (does nothing if not an IDE drive, but that's okay). - * 4. invalidate our in-memory copy of block zero, - * 5. restart the partition table hunt from scratch. - */ - first_sector += p->end_sector; - hd->part[MINOR(dev)].start_sect += p->end_sector; - hd->part[MINOR(dev)].nr_sects -= p->end_sector; #ifdef CONFIG_BLK_DEV_IDE - ide_xlate_1024(dev); /* harmless if not an IDE drive */ -#endif - bh->b_dirt = 0; /* prevent re-use of this block */ - bh->b_uptodate = 0; - bh->b_req = 0; - brelse(bh); - goto read_mbr; - } - /* - * Check for Disk Manager v6.0x DDO on a secondary drive (?) + * Check for Disk Manager v6.0x with geometry translation */ - if (p->sys_ind == DM6_AUXPARTITION) { - printk(" [DM6]"); -#ifdef CONFIG_BLK_DEV_IDE - ide_xlate_1024(dev); /* harmless if not an IDE drive */ -#endif + if (!tested_for_dm6++) { /* only check for DM6 *once* */ + extern int ide_xlate_1024(dev_t, int, char *); + /* check for DM6 with Dynamic Drive Overlay (DDO) */ + if (p->sys_ind == DM6_PARTITION) { + /* + * Everything on the disk is offset by 63 sectors, + * including a "new" MBR with its own partition table, + * and the remainder of the disk must be accessed using + * a translated geometry that reduces the number of + * apparent cylinders to less than 1024 if possible. + * + * ide_xlate_1024() will take care of the necessary + * adjustments to fool fdisk/LILO and partition check. + */ + if (ide_xlate_1024(dev,1," [DM6:DDO]")) { + bh->b_dirt = 0; /* force re-read of MBR block */ + bh->b_uptodate = 0; + bh->b_req = 0; + brelse(bh); + goto read_mbr; /* start over with new MBR */ + } + } else { + /* look for DM6 signature in MBR, courtesy of OnTrack */ + unsigned int sig = *(unsigned short *)(bh->b_data + 2); + if (sig <= 0x1ae + && *(unsigned short *)(bh->b_data + sig) == 0x55AA + && (1 & *(unsigned char *)(bh->b_data + sig + 2)) ) + { + (void)ide_xlate_1024(dev,0," [DM6:MBR]"); + } else { + /* look for DM6 AUX partition type in slot 1 */ + if (p->sys_ind == DM6_AUX1PARTITION + || p->sys_ind == DM6_AUX3PARTITION) + { + (void)ide_xlate_1024(dev,0," [DM6:AUX]"); + } + } + } } +#endif /* CONFIG_BLK_DEV_IDE */ current_minor += 4; /* first "extra" minor (for extended partitions) */ for (i=1 ; i<=4 ; minor++,i++,p++) { @@ -303,7 +306,7 @@ static void check_partition(struct gendisk *hd, unsigned int dev) if (osf_partition(hd, dev, first_sector)) return; #endif - printk("unknown partition table\n"); + printk(" unknown partition table\n"); } /* This function is used to re-read partition tables for removable disks. diff --git a/drivers/block/ide.c b/drivers/block/ide.c index b4a03561ff8a..467b75f824cc 100644 --- a/drivers/block/ide.c +++ b/drivers/block/ide.c @@ -1,5 +1,5 @@ /* - * linux/drivers/block/ide.c Version 4.00 Jul 10, 1995 + * linux/drivers/block/ide.c Version 4.11 Jul 29, 1995 * * Copyright (C) 1994, 1995 Linus Torvalds & authors (see below) */ @@ -91,6 +91,10 @@ * add transparent support for DiskManager-6.0x "Dynamic * Disk Overlay" (DDO), most of this in in genhd.c * eliminate "multiple mode turned off" message at boot + * Version 4.10 fix bug in ioctl for "hdparm -c3" + * fix DM6:DDO support -- now works with LILO, fdisk, ... + * don't treat some naughty WD drives as removeable + * Version 4.11 updated DM6 support using info provided by OnTrack * * To do: * - add support for alternative IDE port addresses @@ -278,6 +282,8 @@ static uint probe_dtc2278 = 0; * For fast indexing, sizeof(ide_dev_t) = 32 = power_of_2; * Everything is carefully aligned on appropriate boundaries, * and several fields are placed for optimal (gcc) access. + * + * Ugh. Actually, we're two bytes over (34 bytes).. gotta fix this someday. */ typedef enum {disk, cdrom} dev_type; @@ -322,6 +328,7 @@ typedef struct { const char *name; struct hd_driveid *id; struct wait_queue *wqueue; + byte sect0, removeable; } ide_dev_t; /* @@ -1153,7 +1160,7 @@ repeat: end_request(0, HWIF); goto repeat; } - block += ide_hd[HWIF][minor].start_sect; + block += ide_hd[HWIF][minor].start_sect + dev->sect0; #if (DISK_RECOVERY_TIME > 0) while ((read_timer() - ide_lastreq[HWIF]) < DISK_RECOVERY_TIME); #endif @@ -1334,9 +1341,11 @@ static ide_dev_t *get_info_ptr (int i_rdev) if (drive < MAX_DRIVES) { switch (MAJOR(i_rdev)) { +#ifndef CONFIG_BLK_DEV_HD case IDE0_MAJOR: dev = &ide_dev[0][drive]; if (dev->present) return dev; break; +#endif /* CONFIG_BLK_DEV_HD */ case IDE1_MAJOR: dev = &ide_dev[1][drive]; if (dev->present) return dev; break; @@ -1358,12 +1367,12 @@ static int ide_open(struct inode * inode, struct file * filp) sleep_on(&dev->wqueue); dev->usage++; restore_flags(flags); - if (dev->id && (dev->id->config & (1<<7))) /* for removeable disks */ - check_disk_change(inode->i_rdev); #ifdef CONFIG_BLK_DEV_IDECD if (dev->type == cdrom) return cdrom_open (inode, filp, dev); #endif /* CONFIG_BLK_DEV_IDECD */ + if (dev->removeable) /* for disks */ + check_disk_change(inode->i_rdev); return 0; } @@ -1567,9 +1576,12 @@ static int ide_ioctl (struct inode *inode, struct file *file, case HDIO_SET_KEEPSETTINGS: case HDIO_SET_UNMASKINTR: case HDIO_SET_NOWERR: + if (arg > 1) + return -EINVAL; case HDIO_SET_CHIPSET: - if (!suser()) return -EACCES; - if ((arg > 1) || (MINOR(inode->i_rdev) & PARTN_MASK)) + if (!suser()) + return -EACCES; + if ((MINOR(inode->i_rdev) & PARTN_MASK)) return -EINVAL; save_flags(flags); cli(); @@ -1654,7 +1666,7 @@ static int ide_check_media_change (dev_t full_dev) if (dev->type == cdrom) return cdrom_check_media_change (dev); #endif /* CONFIG_BLK_DEV_IDECD */ - if (dev->id && (dev->id->config & (1<<7))) /* for removeable disks */ + if (dev->removeable) /* for disks */ return 1; /* always assume it was changed */ return 0; } @@ -1763,12 +1775,19 @@ static void do_identify (ide_dev_t *dev, byte cmd) printk(" UNKNOWN device\n"); dev->type = cdrom; /* until we do it "correctly" above */ dev->present = 1; + dev->removeable = 1; #else printk(unsupported); #endif /* CONFIG_BLK_DEV_IDECD */ return; } + /* check for removeable disks (eg. SYQUEST), ignore 'WD' drives */ + if (id->config & (1<<7)) { /* removeable disk ? */ + if (id->model[0] != 'W' || id->model[1] != 'D') + dev->removeable = 1; + } + dev->type = disk; /* Extract geometry if we did not already have one for the drive */ if (!dev->present) { @@ -2159,20 +2178,36 @@ void hdd_setup(char *str, int *ints) ide_setup (str, ints); } - -void ide_xlate_1024 (dev_t full_dev) +int ide_xlate_1024 (dev_t full_dev, int need_offset, char *msg) { ide_dev_t *dev; + byte head_vals[] = {4, 8, 16, 32, 64, 128, 255, 0}, *heads = head_vals; + unsigned long capacity; - if ((dev = get_info_ptr(full_dev)) != NULL) { - dev->bios_cyl -= 1; /* keeps fdisk sane */ - while (dev->bios_cyl > 1024) { - if (dev->bios_head > 32) - return; - dev->bios_head *= 2; - dev->bios_cyl /= 2; - } - } + if ((dev = get_info_ptr(full_dev)) == NULL && dev->id == NULL) + return 0; + + dev->cyl = dev->bios_cyl = dev->id->cyls; + dev->head = dev->bios_head = dev->id->heads; + dev->sect = dev->bios_sect = dev->id->sectors; + dev->special.b.set_geometry = 1; + + capacity = dev->bios_cyl * dev->bios_head * dev->bios_sect / 63; + dev->bios_sect = 63; + do { + dev->bios_head = *heads; + dev->bios_cyl = capacity / dev->bios_head; + } while (dev->bios_cyl >= 1024 && *++heads); + if (need_offset) { + dev->sect0 = 63; + capacity -= 1; + dev->bios_cyl = capacity / dev->bios_head; + } + capacity = dev->bios_cyl * dev->bios_head * dev->bios_sect; + ide_capacity[DEV_HWIF][dev->select.b.drive] = capacity; + ide_hd[DEV_HWIF][MINOR(full_dev)].nr_sects = capacity; + printk("%s [+%d,%d/%d/%d]", msg, dev->sect0, dev->bios_cyl, dev->bios_head, dev->bios_sect); + return 1; } #ifndef CONFIG_BLK_DEV_HD @@ -2243,6 +2278,8 @@ static void init_ide_data (byte hwif) dev->special.b.recalibrate = 1; dev->special.b.set_geometry = 1; dev->keep_settings = 0; + dev->sect0 = 0; + dev->removeable = 0; ide_hd[hwif][drive<name = ide_devname[hwif][drive]; if (!dev->bad_wstat) diff --git a/drivers/block/sbpcd.c b/drivers/block/sbpcd.c index 9365d7f984a0..87d5743f9ac2 100644 --- a/drivers/block/sbpcd.c +++ b/drivers/block/sbpcd.c @@ -757,7 +757,7 @@ static void sbp_sleep(u_int time) if (current == task[0]) { del_timer(&delay_timer); - delay_timer.expires=time; + delay_timer.expires=jiffies+time; timed_out_delay=0; add_timer(&delay_timer); while (!timed_out_delay) ; @@ -2945,7 +2945,7 @@ static void check_datarate(void) #if 1 del_timer(&delay_timer); #endif - delay_timer.expires=110; + delay_timer.expires=jiffies+110; timed_out_delay=0; add_timer(&delay_timer); msg(DBG_TIM,"delay timer started (110).\n"); @@ -4579,7 +4579,7 @@ static int sbp_data(void) SBPCD_CLI; del_timer(&data_timer); - data_timer.expires=max_latency; + data_timer.expires=jiffies+max_latency; timed_out_data=0; add_timer(&data_timer); while (!timed_out_data) diff --git a/drivers/block/sjcd.c b/drivers/block/sjcd.c index edfba42d968a..1be79d1bcc05 100644 --- a/drivers/block/sjcd.c +++ b/drivers/block/sjcd.c @@ -191,8 +191,8 @@ static struct sjcd_stat statistic; */ static struct timer_list sjcd_delay_timer = { NULL, NULL, 0, 0, NULL }; -#define SJCD_SET_TIMER( func, jiffies ) \ - ( sjcd_delay_timer.expires = jiffies, \ +#define SJCD_SET_TIMER( func, tmout ) \ + ( sjcd_delay_timer.expires = jiffies+tmout, \ sjcd_delay_timer.function = ( void * )func, \ add_timer( &sjcd_delay_timer ) ) diff --git a/drivers/char/lp.c b/drivers/char/lp.c index 2c2fd14481c1..0fbf1fe2e076 100644 --- a/drivers/char/lp.c +++ b/drivers/char/lp.c @@ -51,15 +51,6 @@ struct lp_struct lp_table[] = { (status & (LP_PBUSY|LP_POUTPA|LP_PSELECD|LP_PERRORP)) == \ (LP_PBUSY|LP_PSELECD|LP_PERRORP) -/* Allow old versions of tunelp to continue to work */ -#define OLD_LPCHAR 0x0001 -#define OLD_LPTIME 0x0002 -#define OLD_LPABORT 0x0004 -#define OLD_LPSETIRQ 0x0005 -#define OLD_LPGETIRQ 0x0006 -#define OLD_LPWAIT 0x0008 -#define OLD_IOCTL_MAX 8 - /* * All my debugging code assumes that you debug with only one printer at * a time. RWWH @@ -406,19 +397,13 @@ static int lp_ioctl(struct inode *inode, struct file *file, return -ENODEV; if ((LP_F(minor) & LP_EXIST) == 0) return -ENODEV; - if (cmd <= OLD_IOCTL_MAX) - printk(KERN_NOTICE "lp%d: warning: obsolete ioctl %#x (perhaps you need a new tunelp)\n", - minor, cmd); switch ( cmd ) { - case OLD_LPTIME: case LPTIME: LP_TIME(minor) = arg; break; - case OLD_LPCHAR: case LPCHAR: LP_CHAR(minor) = arg; break; - case OLD_LPABORT: case LPABORT: if (arg) LP_F(minor) |= LP_ABORT; @@ -437,11 +422,9 @@ static int lp_ioctl(struct inode *inode, struct file *file, else LP_F(minor) &= ~LP_CAREFUL; break; - case OLD_LPWAIT: case LPWAIT: LP_WAIT(minor) = arg; break; - case OLD_LPSETIRQ: case LPSETIRQ: { int oldirq; int newirq = arg; @@ -485,9 +468,6 @@ static int lp_ioctl(struct inode *inode, struct file *file, lp_reset(minor); break; } - case OLD_LPGETIRQ: - retval = LP_IRQ(minor); - break; case LPGETIRQ: retval = verify_area(VERIFY_WRITE, (void *) arg, sizeof(int)); diff --git a/drivers/char/psaux.c b/drivers/char/psaux.c index 2f0594ea1854..56eb5c89ef4d 100644 --- a/drivers/char/psaux.c +++ b/drivers/char/psaux.c @@ -12,13 +12,15 @@ * Changed to prevent keyboard lockups on AST Power Exec. * 28Jul93 Brad Bosch - brad@lachman.com * - * Modified by Johan Myreen (jempandora.pp.fi) 04Aug93 + * Modified by Johan Myreen (jem@pandora.pp.fi) 04Aug93 * to include support for QuickPort mouse. * * Changed references to "QuickPort" with "82C710" since "QuickPort" * is not what this driver is all about -- QuickPort is just a * connector type, and this driver is for the mouse port on the Chips * & Technologies 82C710 interface chip. 15Nov93 jem@pandora.pp.fi + * + * Added support for SIGIO. 28Jul95 jem@pandora.pp.fi */ /* Uncomment the following line if your mouse needs initialization. */ @@ -30,6 +32,7 @@ #include #include #include +#include #include #include @@ -95,6 +98,7 @@ struct aux_queue { unsigned long head; unsigned long tail; struct wait_queue *proc_list; + struct fasync_struct *fasync; unsigned char buf[AUX_BUF_SIZE]; }; @@ -104,6 +108,7 @@ static int aux_busy = 0; static int aux_present = 0; static int poll_aux_status(void); static int poll_aux_status_nosleep(void); +static int fasync_aux(struct inode *inode, struct file *filp, int on); #ifdef CONFIG_82C710_MOUSE static int qp_present = 0; @@ -122,9 +127,9 @@ static int probe_qp(void); static void aux_write_dev(int val) { - poll_aux_status_nosleep(); + poll_aux_status(); outb_p(AUX_MAGIC_WRITE,AUX_COMMAND); /* write magic cookie */ - poll_aux_status_nosleep(); + poll_aux_status(); outb_p(val,AUX_OUTPUT_PORT); /* write data */ } @@ -137,7 +142,10 @@ static int aux_write_ack(int val) { int retries = 0; - aux_write_dev(val); /* write the value to the device */ + poll_aux_status_nosleep(); + outb_p(AUX_MAGIC_WRITE,AUX_COMMAND); + poll_aux_status_nosleep(); + outb_p(val,AUX_OUTPUT_PORT); poll_aux_status_nosleep(); if ((inb(AUX_STATUS) & AUX_OBUF_FULL) == AUX_OBUF_FULL) @@ -199,6 +207,8 @@ static void aux_interrupt(int cpl, struct pt_regs * regs) } queue->head = head; aux_ready = 1; + if (queue->fasync) + kill_fasync(queue->fasync, SIGIO); wake_up_interruptible(&queue->proc_list); } @@ -220,6 +230,8 @@ static void qp_interrupt(int cpl, struct pt_regs * regs) } queue->head = head; aux_ready = 1; + if (queue->fasync) + kill_fasync(queue->fasync, SIGIO); wake_up_interruptible(&queue->proc_list); } #endif @@ -227,14 +239,12 @@ static void qp_interrupt(int cpl, struct pt_regs * regs) static void release_aux(struct inode * inode, struct file * file) { -#ifndef __alpha__ - aux_write_dev(AUX_DISABLE_DEV); /* disable aux device */ -#endif aux_write_cmd(AUX_INTS_OFF); /* disable controller ints */ poll_aux_status(); outb_p(AUX_DISABLE,AUX_COMMAND); /* Disable Aux device */ poll_aux_status(); free_irq(AUX_IRQ); + fasync_aux(inode, file, 0); aux_busy = 0; } @@ -250,10 +260,43 @@ static void release_qp(struct inode * inode, struct file * file) if (!poll_qp_status()) printk("Warning: Mouse device busy in release_qp()\n"); free_irq(QP_IRQ); + fasync_aux(inode, file, 0); qp_busy = 0; } #endif +static int fasync_aux(struct inode *inode, struct file *filp, int on) +{ + struct fasync_struct *fa, *prev; + + for (fa = queue->fasync, prev = 0; fa; prev= fa, fa = fa->fa_next) { + if (fa->fa_file == filp) + break; + } + + if (on) { + if (fa) + return 0; + fa = (struct fasync_struct *)kmalloc(sizeof(struct fasync_struct), GFP_KERNEL); + if (!fa) + return -ENOMEM; + fa->magic = FASYNC_MAGIC; + fa->fa_file = filp; + fa->fa_next = queue->fasync; + queue->fasync = fa; + } + else { + if (!fa) + return 0; + if (prev) + prev->fa_next = fa->fa_next; + else + queue->fasync = fa->fa_next; + kfree_s(fa, sizeof(struct fasync_struct)); + } + return 0; +} + /* * Install interrupt handler. * Enable auxiliary device. @@ -426,6 +469,8 @@ struct file_operations psaux_fops = { NULL, /* mmap */ open_aux, release_aux, + NULL, + fasync_aux }; @@ -470,7 +515,10 @@ unsigned long psaux_init(unsigned long kmem_start) poll_aux_status_nosleep(); #endif /* INITIALIZE_DEVICE */ outb_p(AUX_DISABLE,AUX_COMMAND); /* Disable Aux device */ - aux_write_cmd(AUX_INTS_OFF); /* disable controller ints */ + poll_aux_status_nosleep(); + outb_p(AUX_CMD_WRITE,AUX_COMMAND); + poll_aux_status_nosleep(); /* Disable interrupts */ + outb_p(AUX_INTS_OFF, AUX_OUTPUT_PORT); /* on the controller */ } return kmem_start; } diff --git a/drivers/char/vt.c b/drivers/char/vt.c index d231b977072c..36e91bcc3a60 100644 --- a/drivers/char/vt.c +++ b/drivers/char/vt.c @@ -169,7 +169,7 @@ kd_mksound(unsigned int count, unsigned int ticks) outb((count >> 8) & 0xff, 0x42); if (ticks) { - sound_timer.expires = ticks; + sound_timer.expires = jiffies+ticks; add_timer(&sound_timer); } } else diff --git a/drivers/net/atp.c b/drivers/net/atp.c index 7fdbaea4c0bf..322d74657398 100644 --- a/drivers/net/atp.c +++ b/drivers/net/atp.c @@ -248,7 +248,7 @@ static int atp_probe1(struct device *dev, short ioaddr) #ifdef TIMED_CHECKER del_timer(&atp_timer); - atp_timer.expires = TIMED_CHECKER; + atp_timer.expires = jiffies + TIMED_CHECKER; atp_timed_dev = dev; add_timer(&atp_timer); #endif @@ -585,7 +585,7 @@ net_interrupt(int irq, struct pt_regs * regs) write_reg_byte(ioaddr, PAR0 + i, dev->dev_addr[i]); #ifdef TIMED_CHECKER del_timer(&atp_timer); - atp_timer.expires = TIMED_CHECKER; + atp_timer.expires = jiffies + TIMED_CHECKER; add_timer(&atp_timer); #endif } @@ -635,7 +635,7 @@ static void atp_timed_checker(unsigned long ignored) #endif } del_timer(&atp_timer); - atp_timer.expires = TIMED_CHECKER; + atp_timer.expires = jiffies + TIMED_CHECKER; add_timer(&atp_timer); } #endif diff --git a/drivers/net/eql.c b/drivers/net/eql.c index a2760478c8bc..229949578d20 100644 --- a/drivers/net/eql.c +++ b/drivers/net/eql.c @@ -222,7 +222,7 @@ eql_init(struct device *dev) init_timer (&eql->timer); eql->timer.data = (unsigned long) dev->priv; - eql->timer.expires = EQL_DEFAULT_RESCHED_IVAL; + eql->timer.expires = jiffies+EQL_DEFAULT_RESCHED_IVAL; eql->timer.function = &eql_timer; eql->timer_on = 0; @@ -1160,7 +1160,7 @@ eql_timer(unsigned long param) if (eql->timer_on != 0) { - eql->timer.expires = EQL_DEFAULT_RESCHED_IVAL; + eql->timer.expires = jiffies+EQL_DEFAULT_RESCHED_IVAL; add_timer (&eql->timer); } } diff --git a/drivers/net/ibmtr.c b/drivers/net/ibmtr.c index e0d4723380b5..b9ff59cba3df 100644 --- a/drivers/net/ibmtr.c +++ b/drivers/net/ibmtr.c @@ -627,7 +627,7 @@ static void tok_interrupt (int irq, struct pt_regs *regs) DPRINTK("open failed: ret_code = %02X, retrying\n",open_response->ret_code); } if(ti->open_status!=FAILURE) { - tr_timer.expires=TR_RETRY_INTERVAL; + tr_timer.expires=jiffies+TR_RETRY_INTERVAL; tr_timer.data=(unsigned long)dev; tr_timer.next=tr_timer.prev=NULL; add_timer(&tr_timer); @@ -642,7 +642,7 @@ static void tok_interrupt (int irq, struct pt_regs *regs) struct dlc_open_sap *open_sap=(struct dlc_open_sap *)ti->srb; if(open_sap->ret_code) { DPRINTK("open_sap failed: ret_code = %02X,retrying\n",open_sap->ret_code); - tr_timer.expires=TR_RETRY_INTERVAL; + tr_timer.expires=jiffies+TR_RETRY_INTERVAL; tr_timer.data=(unsigned long)dev; tr_timer.next=tr_timer.prev=NULL; add_timer(&tr_timer); @@ -724,7 +724,7 @@ skip_reset: if(ring_status & (SIGNAL_LOSS + LOBE_FAULT)) { DPRINTK("Signal loss/Lobe fault\n"); DPRINTK("We try to reopen the adapter.\n"); - tr_timer.expires=TR_RETRY_INTERVAL; + tr_timer.expires=jiffies+TR_RETRY_INTERVAL; tr_timer.data=(unsigned long)dev; tr_timer.next=tr_timer.prev=NULL; add_timer(&tr_timer); diff --git a/drivers/net/wavelan.c b/drivers/net/wavelan.c index e18c765e160b..4b82bc133ed2 100644 --- a/drivers/net/wavelan.c +++ b/drivers/net/wavelan.c @@ -1824,7 +1824,7 @@ wavelan_watchdog(unsigned long a) return; } - lp->watchdog.expires = WATCHDOG_JIFFIES; + lp->watchdog.expires = jiffies+WATCHDOG_JIFFIES; add_timer(&lp->watchdog); if (jiffies - dev->trans_start < WATCHDOG_JIFFIES) diff --git a/drivers/sound/Readme.cards b/drivers/sound/Readme.cards index c362d924a29d..c4b57d77ddfd 100644 --- a/drivers/sound/Readme.cards +++ b/drivers/sound/Readme.cards @@ -461,6 +461,13 @@ Adding the second or third MPU interfaces must be done manually by editing sound/local.h (after running the config program). Add defines for MPU2_BASE & MPU2_IRQ (and MPU3_BASE & MPU3_IRQ) to the file. +CAUTION! + +The default I/O base of Adaptec AHA-1542 SCSI controller is 0x330 which +is also the default of the MPU401 driver. Don't configure the sound driver to +use 0x330 as the MPU401 base if you have a AHA1542. The kernel will not boot +if you make this mistake. + PSS --- @@ -598,6 +605,9 @@ There are some other OPTi chips which may be used in soundcards such as 82C930 and MAC32. These chips are not supported by VoxWare yet. Please contact me if you have a soundcard which uses these chips. +Some MAD16 based cards may cause feedback, whistle or terrible noise if the +line3 mixer channel is turned too high. + MV Jazz (ProSonic) ------------------ @@ -628,7 +638,8 @@ code to be loaded to the microcontroller. The file is usually called MIDI0001.BIN and it's located in the DOS/Windows driver directory. The file may also be called as TSUNAMI.BIN or something else (older cards?). -The OPL4 synth will be riunaccessible without loading the microcontroller code. +The OPL4 synth will be inaccessible without loading the microcontroller code. +Also remember to enable MPU401 support if you want to use the OPL4 mode. NOTE! Don't answer 'y' when the driver asks about SM Games support (the next question after the MIDI0001.BIN name). However @@ -673,7 +684,23 @@ models are based on the MAD16 chip which is supported by VoxWare. Audio Excel DSP16 ----------------- -See aedsp16.c. +See comments in aedsp16.c. + + +PCMCIA cards +------------ + +Sorry, can't help. Some cards may work and some don't. + +TI TM4000M notebooks +-------------------- + +These computers have a built in sound support based on the Jazz chipset. +Look at the instructions for MV Jazz (above). It's also important to note +that there is something wrong with the mouse port and sound at least on +some TM models. Don't enable the "C&T 82C710 mouse port support" when +configuring Linux. Having it enabled is likely to cause mysterious problems +and kernel failures when sound is used. Others? ------- diff --git a/drivers/sound/ad1848_mixer.h b/drivers/sound/ad1848_mixer.h index f223c091d357..4f32b4a8b712 100644 --- a/drivers/sound/ad1848_mixer.h +++ b/drivers/sound/ad1848_mixer.h @@ -123,7 +123,7 @@ static unsigned short default_mixer_levels[SOUND_MIXER_NRDEVICES] = 0x4b4b, /* Output gain */ 0x4b4b, /* Line1 */ 0x4b4b, /* Line2 */ - 0x4b4b /* Line3 */ + 0x3232 /* Line3 (usually line in)*/ }; #define LEFT_CHN 0 diff --git a/drivers/sound/mad16.c b/drivers/sound/mad16.c index 2f367440a4db..2da02f415fda 100644 --- a/drivers/sound/mad16.c +++ b/drivers/sound/mad16.c @@ -232,10 +232,23 @@ probe_mad16 (struct address_info *hw_config) if (!detect_mad16 ()) return 0; - printk ("mad16.c: A 82C929 detected???\n"); + printk ("mad16.c: 82C929 detected???\n"); } else - printk ("mad16.c: A 82C928 or Mozart detected???\n"); + { + unsigned char model; + + if (((model=mad_read (MC3_PORT)) & 0x03) == 0x03) + { + printk ("mad16.c: Mozart detected???\n"); + board_type = MOZART; + } + else + { + printk ("mad16.c: 82C928 detected???\n"); + board_type = C928; + } + } for (i = 0xf8d; i <= 0xf93; i++) DDB (printk ("port %03x = %03x\n", i, mad_read (i))); diff --git a/drivers/sound/os.h b/drivers/sound/os.h index c749cdb6f9a9..de52747acba5 100644 --- a/drivers/sound/os.h +++ b/drivers/sound/os.h @@ -155,7 +155,7 @@ struct snd_wait { */ #define ACTIVATE_TIMER(name, proc, time) \ - {name.expires = time; \ + {name.expires = jiffies+(time); \ add_timer (&name);} #define INB inb diff --git a/drivers/sound/pas2_card.c b/drivers/sound/pas2_card.c index 5dcefcf9a825..294d71180ceb 100644 --- a/drivers/sound/pas2_card.c +++ b/drivers/sound/pas2_card.c @@ -252,11 +252,14 @@ config_pas_hw (struct address_info *hw_config) * rate * of * 17.897 kHz */ - +#if 1 + pas_write (8, PRESCALE_DIVIDER); +#else if (pas_model == PAS_16 || pas_model == PAS_16D) pas_write (8, PRESCALE_DIVIDER); else pas_write (0, PRESCALE_DIVIDER); +#endif mix_write (P_M_MV508_ADDRESS | 5, PARALLEL_MIXER); mix_write (5, PARALLEL_MIXER); diff --git a/drivers/sound/sb_dsp.c b/drivers/sound/sb_dsp.c index 2124080b168b..8b1fe8b4d40a 100644 --- a/drivers/sound/sb_dsp.c +++ b/drivers/sound/sb_dsp.c @@ -854,10 +854,10 @@ sb_dsp_reset (int dev) #ifndef MPU_BASE /* take default values if not specified */ -#define MPU_BASE 0x330 +#define MPU_BASE 0 #endif #ifndef MPU_IRQ -#define MPU_IRQ 9 +#define MPU_IRQ 0 #endif unsigned int diff --git a/drivers/sound/sequencer.c b/drivers/sound/sequencer.c index 53c87fa6a4c1..9b76dd98dd55 100644 --- a/drivers/sound/sequencer.c +++ b/drivers/sound/sequencer.c @@ -1818,7 +1818,7 @@ note_to_freq (int note_num) 369998, 391998, 415306, 440000, 466162, 493880 }; -#define BASE_OCTAVE 5 +#define BASE_OCTAVE 4 octave = note_num / 12; note = note_num % 12; diff --git a/drivers/sound/sound_switch.c b/drivers/sound/sound_switch.c index 2b9233fa3532..e7c78dd28822 100644 --- a/drivers/sound/sound_switch.c +++ b/drivers/sound/sound_switch.c @@ -58,8 +58,8 @@ put_status (char *s) { int l; - for (l = 0; l < 256, s[l]; l++); /* - * l=strlen(s); + for (l = 0; l < 256 && s[l]; l++); /* + * l=strnlen(s,256); */ if (status_len + l >= 4000) diff --git a/drivers/sound/soundvers.h b/drivers/sound/soundvers.h index 9660869f50eb..f486f9a197b5 100644 --- a/drivers/sound/soundvers.h +++ b/drivers/sound/soundvers.h @@ -1 +1 @@ -#define SOUND_VERSION_STRING "3.0-950710" +#define SOUND_VERSION_STRING "3.0-950728" diff --git a/include/asm-i386/bitops.h b/include/asm-i386/bitops.h index 06ae3edac2e4..8f9f58ff3aac 100644 --- a/include/asm-i386/bitops.h +++ b/include/asm-i386/bitops.h @@ -66,7 +66,7 @@ extern __inline__ int test_bit(int nr, void * addr) /* * Find-bit routines.. */ -extern inline int find_first_zero_bit(void * addr, unsigned size) +extern __inline__ int find_first_zero_bit(void * addr, unsigned size) { int res; @@ -90,7 +90,7 @@ extern inline int find_first_zero_bit(void * addr, unsigned size) return res; } -extern inline int find_next_zero_bit (void * addr, int size, int offset) +extern __inline__ int find_next_zero_bit (void * addr, int size, int offset) { unsigned long * p = ((unsigned long *) addr) + (offset >> 5); int set = 0, bit = offset & 31, res; @@ -122,7 +122,7 @@ extern inline int find_next_zero_bit (void * addr, int size, int offset) * ffz = Find First Zero in word. Undefined if no zero exists, * so code should check against ~0UL first.. */ -extern inline unsigned long ffz(unsigned long word) +extern __inline__ unsigned long ffz(unsigned long word) { __asm__("bsfl %1,%0" :"=r" (word) diff --git a/include/linux/ax25.h b/include/linux/ax25.h index 2df331eca5b2..6f7f4a5090f2 100644 --- a/include/linux/ax25.h +++ b/include/linux/ax25.h @@ -30,11 +30,13 @@ struct full_sockaddr_ax25 #define AX25_T3 4 #define AX25_T2 5 #define AX25_BACKOFF 6 +#define AX25_EXTSEQ 7 #define SIOCAX25GETUID (SIOCPROTOPRIVATE) #define SIOCAX25ADDUID (SIOCPROTOPRIVATE+1) #define SIOCAX25DELUID (SIOCPROTOPRIVATE+2) #define SIOCAX25NOUID (SIOCPROTOPRIVATE+3) +#define SIOCAX25DIGCTL (SIOCPROTOPRIVATE+4) #define AX25_NOUID_DEFAULT 0 #define AX25_NOUID_BLOCK 1 diff --git a/include/linux/aztcd.h b/include/linux/aztcd.h index a9de593f4acc..b9738d0fab2a 100644 --- a/include/linux/aztcd.h +++ b/include/linux/aztcd.h @@ -1,4 +1,4 @@ -/* $Id: aztcd.h,v 1.40 1995/07/15 20:35:01 root Exp root $ +/* $Id: aztcd.h,v 1.50 1995/07/29 20:31:32 root Exp $ * * Definitions for a AztechCD268 CD-ROM interface * Copyright (C) 1994, 1995 Werner Zimmermann @@ -45,7 +45,7 @@ /*Set this to 1, if you want multisession support. Be warned, this function has not been tested !!!*/ -#define AZT_MULTISESSION 0 +#define AZT_MULTISESSION 1 /*Set this to 1, if you want to use incompatible ioctls for reading in raw and cooked mode */ @@ -76,10 +76,11 @@ not been tested !!!*/ #endif /* status bits */ -#define AST_CMD_CHECK 0x80 /* command error */ -#define AST_DSK_CHG 0x20 /* disk removed or changed */ -#define AST_NOT_READY 0x02 /* no disk in the drive */ -#define AST_DOOR_OPEN 0x40 /* door is open */ +#define AST_CMD_CHECK 0x80 /* 1 = command error */ +#define AST_DOOR_OPEN 0x40 /* 1 = door is open */ +#define AST_NOT_READY 0x20 /* 1 = no disk in the drive */ +#define AST_DSK_CHG 0x02 /* 1 = disk removed or changed */ +#define AST_MODE 0x01 /* 0=MODE1, 1=MODE2 */ #define AST_MODE_BITS 0x1C /* Mode Bits */ #define AST_INITIAL 0x0C /* initial, only valid ... */ #define AST_BUSY 0x04 /* now playing, only valid @@ -97,7 +98,7 @@ not been tested !!!*/ /* commands */ #define ACMD_SOFT_RESET 0x10 /* reset drive */ #define ACMD_PLAY_READ 0x20 /* read data track in cooked mode */ -#define ACMD_DATA_READ_RAW 0x21 /* reading in raw mode*/ +#define ACMD_PLAY_READ_RAW 0x21 /* reading in raw mode*/ #define ACMD_SEEK_TO_LEADIN 0x31 /* seek to leadin track*/ #define ACMD_GET_ERROR 0x40 /* get error code */ #define ACMD_GET_STATUS 0x41 /* get status */ @@ -111,14 +112,10 @@ not been tested !!!*/ #define ACMD_PLAY_AUDIO 0x90 /* play audio track */ #define ACMD_SET_VOLUME 0x93 /* set audio level */ #define ACMD_GET_VERSION 0xA0 /* get firmware version */ -#define ACMD_SET_MODE 0xA1 /* set drive mode */ +#define ACMD_SET_DISK_TYPE 0xA1 /* set disk data mode */ #define MAX_TRACKS 104 -#define CD_DATA 0x01 -#define CD_AUDIO 0x02 -#define CD_XA (CD_DATA|CD_AUDIO) - struct msf { unsigned char min; unsigned char sec; @@ -137,7 +134,8 @@ struct azt_DiskInfo { struct msf firstTrack; unsigned char multi; struct msf lastTrack; - unsigned char type; + unsigned char xa; + unsigned char audio; }; struct azt_Toc { diff --git a/include/linux/cdrom.h b/include/linux/cdrom.h index 31b5c06a53a5..9bb89dd86371 100644 --- a/include/linux/cdrom.h +++ b/include/linux/cdrom.h @@ -424,4 +424,8 @@ struct cdrom_multisession #define CDROMVOLREAD 0x5313 /* let the drive tell its volume setting */ /* (struct cdrom_volctrl) */ +#define CDROMREADMODE0 0x5314 /*read data in audio mode*/ +#define CDROMREADRAW 0x5315 /*read data in raw mode*/ +#define CDROMREADCOOKED 0x5316 /*read data in cooked mode*/ + #endif _LINUX_CDROM_H diff --git a/include/linux/genhd.h b/include/linux/genhd.h index 353cc1c61e37..18c2d2e8a595 100644 --- a/include/linux/genhd.h +++ b/include/linux/genhd.h @@ -18,7 +18,8 @@ #define EXTENDED_PARTITION 5 #define DM6_PARTITION 0x54 /* has DDO: use xlated geom & offset */ -#define DM6_AUXPARTITION 0x51 /* no DDO: use xlated geom */ +#define DM6_AUX1PARTITION 0x51 /* no DDO: use xlated geom */ +#define DM6_AUX3PARTITION 0x53 /* no DDO: use xlated geom */ struct partition { unsigned char boot_ind; /* 0x80 - active */ diff --git a/include/linux/netrom.h b/include/linux/netrom.h index 80947074d6d9..0d591ab4e628 100644 --- a/include/linux/netrom.h +++ b/include/linux/netrom.h @@ -8,6 +8,7 @@ #define SIOCNRGETPARMS (SIOCPROTOPRIVATE+0) #define SIOCNRSETPARMS (SIOCPROTOPRIVATE+1) #define SIOCNRDECOBS (SIOCPROTOPRIVATE+2) +#define SIOCNRRTCTL (SIOCPROTOPRIVATE+3) struct nr_route_struct { #define NETROM_NEIGH 0 diff --git a/include/linux/optcd.h b/include/linux/optcd.h index 3b9814c4bdb5..20ef07189a62 100644 --- a/include/linux/optcd.h +++ b/include/linux/optcd.h @@ -135,8 +135,8 @@ #define RESET_WAIT 1000 #define SET_TIMER(func, jifs) \ - delay_timer.expires = jifs; \ - delay_timer.function = (void *) func; \ + delay_timer.expires = jiffies+(jifs); \ + delay_timer.function = (void *) (func); \ add_timer(&delay_timer); #define CLEAR_TIMER del_timer(&delay_timer) diff --git a/include/linux/soundcard.h b/include/linux/soundcard.h index cf6f07d185de..3f12061c1c2a 100644 --- a/include/linux/soundcard.h +++ b/include/linux/soundcard.h @@ -117,6 +117,7 @@ #define SNDCTL_SEQ_NRMIDIS _IOR ('Q',11, int) #define SNDCTL_MIDI_INFO _IOWR('Q',12, struct midi_info) #define SNDCTL_SEQ_THRESHOLD _IOW ('Q',13, int) +#define SNDCTL_SEQ_TRESHOLD SNDCTL_SEQ_THRESHOLD /* there was once a typo */ #define SNDCTL_SYNTH_MEMAVL _IOWR('Q',14, int) /* in=dev#, out=memsize */ #define SNDCTL_FM_4OP_ENABLE _IOW ('Q',15, int) /* in=dev# */ #define SNDCTL_PMGR_ACCESS _IOWR('Q',16, struct patmgr_info) diff --git a/include/net/ax25.h b/include/net/ax25.h index c34079864377..83558f44bca1 100644 --- a/include/net/ax25.h +++ b/include/net/ax25.h @@ -19,12 +19,17 @@ #define AX25_P_ARP 0xCD #define AX25_P_TEXT 0xF0 #define AX25_P_NETROM 0xCF +#define AX25_P_SEGMENT 0x08 -#define LAPB_UI 0x03 -#define LAPB_C 0x80 -#define LAPB_E 0x01 +#define SEG_REM 0x7F +#define SEG_FIRST 0x80 -#define SSID_SPARE 0x60 /* Unused bits (DAMA bit and spare must be 1) */ +#define LAPB_UI 0x03 +#define LAPB_C 0x80 +#define LAPB_E 0x01 + +#define SSSID_SPARE 0x60 /* Unused bits in SSID for standard AX.25 */ +#define ESSID_SPARE 0x20 /* Unused bits in SSID for extended AX.25 */ #define AX25_REPEATED 0x80 @@ -74,11 +79,13 @@ #define UA 0x63 /* Unnumbered acknowledge */ #define FRMR 0x87 /* Frame reject */ #define UI 0x03 /* Unnumbered information */ -#define PF 0x10 /* Poll/final bit */ +#define PF 0x10 /* Poll/final bit for standard AX.25 */ +#define EPF 0x01 /* Poll/final bit for extended AX.25 */ #define ILLEGAL 0x100 /* Impossible to be a real frame type */ -#define MMASK 7 /* Mask for modulo-8 sequence numbers */ +#define POLLOFF 0 +#define POLLON 1 /* AX25 L2 C-bit */ @@ -99,8 +106,8 @@ #define DEFAULT_T3 (300 * PR_SLOWHZ) /* Idle supervision - 300 seconds */ #define DEFAULT_N2 10 /* Number of retries */ #define DEFAULT_WINDOW 2 /* Default window size */ -#define MODULUS 8 -#define MAX_WINDOW_SIZE 7 /* Maximum window allowable */ +#define MODULUS 8 /* Standard AX.25 modulus */ +#define EMODULUS 128 /* Extended AX.25 modulus */ typedef struct ax25_uid_assoc { struct ax25_uid_assoc *next; @@ -119,15 +126,18 @@ typedef struct ax25_cb { struct ax25_cb *next; ax25_address source_addr, dest_addr; struct device *device; - unsigned char state; + unsigned char state, modulus; unsigned short vs, vr, va; unsigned char condition, backoff; unsigned char n2, n2count; unsigned short t1, t2, t3, rtt; unsigned short t1timer, t2timer, t3timer; + unsigned short fragno, fraglen; ax25_digi *digipeat; struct sk_buff_head write_queue; + struct sk_buff_head reseq_queue; struct sk_buff_head ack_queue; + struct sk_buff_head frag_queue; unsigned char window; struct timer_list timer; struct sock *sk; /* Backlink to socket */ @@ -154,7 +164,7 @@ extern void ax25_queue_xmit(struct sk_buff *, struct device *, int); extern int ax25_process_rx_frame(ax25_cb *, struct sk_buff *, int); /* ax25_out.c */ -extern int ax25_output(ax25_cb *, struct sk_buff *); +extern void ax25_output(ax25_cb *, struct sk_buff *); extern void ax25_kick(ax25_cb *); extern void ax25_transmit_buffer(ax25_cb *, struct sk_buff *, int); extern void ax25_nr_error_recovery(ax25_cb *); @@ -174,17 +184,17 @@ extern void ax25_ip_mode_set(ax25_address *, struct device *, char); extern char ax25_ip_mode_get(ax25_address *, struct device *); /* ax25_subr.c */ -extern void ax25_clear_tx_queue(ax25_cb *); +extern void ax25_clear_queues(ax25_cb *); extern void ax25_frames_acked(ax25_cb *, unsigned short); extern int ax25_validate_nr(ax25_cb *, unsigned short); -extern int ax25_decode(unsigned char *); -extern void ax25_send_control(ax25_cb *, int, int); +extern int ax25_decode(ax25_cb *, struct sk_buff *, int *, int *, int *); +extern void ax25_send_control(ax25_cb *, int, int, int); extern unsigned short ax25_calculate_t1(ax25_cb *); extern void ax25_calculate_rtt(ax25_cb *); extern unsigned char *ax25_parse_addr(unsigned char *, int, ax25_address *, ax25_address *, ax25_digi *, int *); extern int build_ax25_addr(unsigned char *, ax25_address *, ax25_address *, - ax25_digi *, int); + ax25_digi *, int, int); extern int size_ax25_addr(ax25_digi *); extern void ax25_digi_invert(ax25_digi *, ax25_digi *); extern void ax25_return_dm(struct device *, ax25_address *, ax25_address *, ax25_digi *); diff --git a/include/net/netrom.h b/include/net/netrom.h index dbcd2332e6d1..d122a0443189 100644 --- a/include/net/netrom.h +++ b/include/net/netrom.h @@ -45,6 +45,7 @@ typedef struct { ax25_address user_addr, source_addr, dest_addr; + struct device *device; unsigned char my_index, my_id; unsigned char your_index, your_id; unsigned char state, bpqext; @@ -53,7 +54,10 @@ typedef struct { unsigned char n2, n2count; unsigned short t1, t2, rtt; unsigned short t1timer, t2timer, t4timer; - struct sk_buff_head ack_queue, reseq_queue; + unsigned short fraglen; + struct sk_buff_head ack_queue; + struct sk_buff_head reseq_queue; + struct sk_buff_head frag_queue; struct sock *sk; /* Backlink to socket */ } nr_cb; @@ -99,7 +103,7 @@ extern int nr_init(struct device *); extern int nr_process_rx_frame(struct sock *, struct sk_buff *); /* nr_out.c */ -extern int nr_output(struct sock *, struct sk_buff *); +extern void nr_output(struct sock *, struct sk_buff *); extern void nr_send_nak_frame(struct sock *); extern void nr_kick(struct sock *); extern void nr_transmit_buffer(struct sock *, struct sk_buff *); @@ -119,7 +123,7 @@ extern int nr_nodes_get_info(char *, char **, off_t, int); extern int nr_neigh_get_info(char *, char **, off_t, int); /* nr_subr.c */ -extern void nr_clear_tx_queue(struct sock *); +extern void nr_clear_queues(struct sock *); extern void nr_frames_acked(struct sock *, unsigned short); extern void nr_requeue_frames(struct sock *); extern int nr_validate_nr(struct sock *, unsigned short); diff --git a/kernel/itimer.c b/kernel/itimer.c index 214a8b537bfa..2db33077a1ea 100644 --- a/kernel/itimer.c +++ b/kernel/itimer.c @@ -38,7 +38,7 @@ static int _getitimer(int which, struct itimerval *value) interval = current->it_real_incr; val = 0; if (del_timer(¤t->real_timer)) { - val = current->real_timer.expires; + val = current->real_timer.expires-jiffies; add_timer(¤t->real_timer); if (val <= 0) val = interval; @@ -83,7 +83,7 @@ void it_real_fn(unsigned long __data) send_sig(SIGALRM, p, 1); if (p->it_real_incr) { - p->real_timer.expires = p->it_real_incr; + p->real_timer.expires = jiffies+p->it_real_incr; add_timer(&p->real_timer); } } @@ -101,7 +101,7 @@ int _setitimer(int which, struct itimerval *value, struct itimerval *ovalue) case ITIMER_REAL: del_timer(¤t->real_timer); if (j) { - current->real_timer.expires = j; + current->real_timer.expires = jiffies+j; add_timer(¤t->real_timer); } current->it_real_value = j; diff --git a/kernel/sched.c b/kernel/sched.c index ad56be84f0bd..b56f140247ac 100644 --- a/kernel/sched.c +++ b/kernel/sched.c @@ -183,7 +183,7 @@ asmlinkage void schedule(void) if (intr_count) { printk("Aiee: scheduling in interrupt\n"); - intr_count = 0; + return; } run_task_queue(&tq_scheduler); @@ -233,7 +233,7 @@ asmlinkage void schedule(void) kstat.context_swtch++; if (timeout) { init_timer(&timer); - timer.expires = timeout - jiffies; + timer.expires = timeout; timer.data = (unsigned long) current; timer.function = process_timeout; add_timer(&timer); @@ -369,7 +369,6 @@ void add_timer(struct timer_list * timer) } #endif p = &timer_head; - timer->expires += jiffies; save_flags(flags); cli(); do { @@ -397,7 +396,6 @@ int del_timer(struct timer_list * timer) timer->prev->next = timer->next; timer->next = timer->prev = NULL; restore_flags(flags); - timer->expires -= jiffies; return 1; } } @@ -414,7 +412,6 @@ int del_timer(struct timer_list * timer) timer->prev->next = timer->next; timer->next = timer->prev = NULL; restore_flags(flags); - timer->expires -= jiffies; return 1; } restore_flags(flags); diff --git a/mm/filemap.c b/mm/filemap.c index 347485b11b38..9ec211cf74f8 100644 --- a/mm/filemap.c +++ b/mm/filemap.c @@ -81,6 +81,7 @@ static void filemap_sync_page(struct vm_area_struct * vma, return; } inode = vma->vm_inode; + offset += vma->vm_offset; multi_bmap(inode, offset, nr, inode->i_sb->s_blocksize_bits); bwrite_page(page, inode->i_dev, nr, inode->i_sb->s_blocksize); } diff --git a/net/802/p8022.c b/net/802/p8022.c index 5a668bd37b8c..61ba9c2e363f 100644 --- a/net/802/p8022.c +++ b/net/802/p8022.c @@ -48,20 +48,13 @@ p8022_datalink_header(struct datalink_proto *dl, struct sk_buff *skb, unsigned char *dest_node) { struct device *dev = skb->dev; - unsigned long len = skb->len; - unsigned long hard_len = dev->hard_header_len; unsigned char *rawp; - dev->hard_header(skb, dev, len - hard_len, - dest_node, NULL, len - hard_len); rawp = skb_push(skb,3); - *rawp = dl->type[0]; - rawp++; - *rawp = dl->type[0]; - rawp++; + *rawp++ = dl->type[0]; + *rawp++ = dl->type[0]; *rawp = 0x03; /* UI */ - rawp++; - skb->h.raw = rawp; + dev->hard_header(skb, dev, ETH_P_802_3, dest_node, NULL, skb->len); } static struct packet_type p8022_packet_type = diff --git a/net/802/p8023.c b/net/802/p8023.c index de9e75b086fa..4015fb7e49e0 100644 --- a/net/802/p8023.c +++ b/net/802/p8023.c @@ -9,12 +9,8 @@ p8023_datalink_header(struct datalink_proto *dl, struct sk_buff *skb, unsigned char *dest_node) { struct device *dev = skb->dev; - unsigned long len = skb->len; - unsigned long hard_len = dev->hard_header_len; - - dev->hard_header(skb, dev, len - hard_len, - dest_node, NULL, len - hard_len); - skb->h.raw = skb->data + hard_len; + + dev->hard_header(skb, dev, ETH_P_802_3, dest_node, NULL, skb->len); } struct datalink_proto * diff --git a/net/802/psnap.c b/net/802/psnap.c index 6b1ab429d159..619c05c94333 100644 --- a/net/802/psnap.c +++ b/net/802/psnap.c @@ -74,11 +74,7 @@ int snap_rcv(struct sk_buff *skb, struct device *dev, struct packet_type *pt) static void snap_datalink_header(struct datalink_proto *dl, struct sk_buff *skb, unsigned char *dest_node) { - unsigned char *rawp; - - rawp = skb_push(skb,5); - memcpy(rawp,dl->type,5); - skb->h.raw = rawp+5; + memcpy(skb_push(skb,5),dl->type,5); snap_dl->datalink_header(snap_dl, skb, dest_node); } diff --git a/net/802/tr.c b/net/802/tr.c index 3cd9f3444e21..b17ac538a3d2 100644 --- a/net/802/tr.c +++ b/net/802/tr.c @@ -236,7 +236,7 @@ static void rif_check_expire(unsigned long dummy) { restore_flags(flags); del_timer(&rif_timer); - rif_timer.expires=RIF_CHECK_INTERVAL; + rif_timer.expires=jiffies+RIF_CHECK_INTERVAL; add_timer(&rif_timer); } diff --git a/net/appletalk/aarp.c b/net/appletalk/aarp.c index da94beb70ff7..8f9bafed8ca0 100644 --- a/net/appletalk/aarp.c +++ b/net/appletalk/aarp.c @@ -362,9 +362,9 @@ static void aarp_expire_timeout(unsigned long unused) } del_timer(&aarp_timer); if(unresolved_count==0) - aarp_timer.expires=AARP_EXPIRY_TIME; + aarp_timer.expires=jiffies+AARP_EXPIRY_TIME; else - aarp_timer.expires=AARP_TICK_TIME; + aarp_timer.expires=jiffies+AARP_TICK_TIME; add_timer(&aarp_timer); } @@ -523,7 +523,7 @@ int aarp_send_ddp(struct device *dev,struct sk_buff *skb, struct at_addr *sa, vo if(unresolved_count==1) { del_timer(&aarp_timer); - aarp_timer.expires=AARP_TICK_TIME; + aarp_timer.expires=jiffies+AARP_TICK_TIME; add_timer(&aarp_timer); } /* @@ -667,7 +667,7 @@ static int aarp_rcv(struct sk_buff *skb, struct device *dev, struct packet_type if(unresolved_count==0) { del_timer(&aarp_timer); - aarp_timer.expires=AARP_EXPIRY_TIME; + aarp_timer.expires=jiffies+AARP_EXPIRY_TIME; add_timer(&aarp_timer); } break; @@ -718,7 +718,7 @@ void aarp_proto_init(void) init_timer(&aarp_timer); aarp_timer.function=aarp_expire_timeout; aarp_timer.data=0; - aarp_timer.expires=AARP_EXPIRY_TIME; + aarp_timer.expires=jiffies+AARP_EXPIRY_TIME; add_timer(&aarp_timer); register_netdevice_notifier(&aarp_notifier); } diff --git a/net/appletalk/ddp.c b/net/appletalk/ddp.c index 1b309e4717b1..5b602aed4829 100644 --- a/net/appletalk/ddp.c +++ b/net/appletalk/ddp.c @@ -199,7 +199,7 @@ static void atalk_destroy_socket(atalk_socket *sk) * Someone is using our buffers still.. defer */ init_timer(&sk->timer); - sk->timer.expires=10*HZ; + sk->timer.expires=jiffies+10*HZ; sk->timer.function=atalk_destroy_timer; sk->timer.data = (unsigned long)sk; add_timer(&sk->timer); diff --git a/net/ax25/af_ax25.c b/net/ax25/af_ax25.c index 2a522a4a1ec6..3fc2959d603e 100644 --- a/net/ax25/af_ax25.c +++ b/net/ax25/af_ax25.c @@ -1,5 +1,5 @@ /* - * AX.25 release 029 + * AX.25 release 030 * * This is ALPHA test software. This code may break your machine, randomly fail to work with new * releases, misbehave and/or generally screw up. It might even work. @@ -58,7 +58,9 @@ * Alan(GW4PTS) Missed suser() on axassociate checks * AX.25 030 Alan(GW4PTS) Added variable length headers. * Jonathan(G4KLX) Added BPQ Ethernet interface. - * Steven(GW7RRM) + * Steven(GW7RRM) Added digi-peating control ioctl. + * Added extended AX.25 support. + * Added AX.25 frame segmentation. * * To do: * Support use as digipeater, including an on/off ioctl @@ -98,6 +100,8 @@ #include #include +static int ax25_digi_on = 1; + #define CONFIG_AX25_XDIGI /* Cross port (band) digi stuff */ /**********************************************************************************************************************\ @@ -197,6 +201,7 @@ static void ax25_kill_by_device(struct device *dev) for (s = ax25_list; s != NULL; s = s->next) { if (s->device == dev) { + s->state = AX25_STATE_0; s->device = NULL; if (s->sk != NULL) { s->sk->state = TCP_CLOSE; @@ -388,7 +393,7 @@ void ax25_destroy_socket(ax25_cb *ax25) /* Not static as its used by the timer * del_timer(&ax25->timer); ax25_remove_socket(ax25); - ax25_clear_tx_queue(ax25); /* Flush the send queue */ + ax25_clear_queues(ax25); /* Flush the queues */ if (ax25->sk != NULL) { while ((skb = skb_dequeue(&ax25->sk->receive_queue)) != NULL) { @@ -410,7 +415,7 @@ void ax25_destroy_socket(ax25_cb *ax25) /* Not static as its used by the timer * if (ax25->sk != NULL) { if (ax25->sk->wmem_alloc || ax25->sk->rmem_alloc) { /* Defer: outstanding buffers */ init_timer(&ax25->timer); - ax25->timer.expires = 10 * HZ; + ax25->timer.expires = jiffies + 10 * HZ; ax25->timer.function = ax25_destroy_timer; ax25->timer.data = (unsigned long)ax25; add_timer(&ax25->timer); @@ -502,7 +507,9 @@ static ax25_cb *ax25_create_cb(void) return NULL; skb_queue_head_init(&ax25->write_queue); + skb_queue_head_init(&ax25->frag_queue); skb_queue_head_init(&ax25->ack_queue); + skb_queue_head_init(&ax25->reseq_queue); init_timer(&ax25->timer); @@ -512,6 +519,9 @@ static ax25_cb *ax25_create_cb(void) ax25->n2 = DEFAULT_N2; ax25->t3 = DEFAULT_T3; + ax25->modulus = MODULUS; + ax25->fragno = 0; + ax25->fraglen = 0; ax25->backoff = 1; ax25->condition = 0x00; ax25->t1timer = 0; @@ -656,8 +666,13 @@ static int ax25_setsockopt(struct socket *sock, int level, int optname, switch (optname) { case AX25_WINDOW: - if (opt < 1 || opt > 7) - return -EINVAL; + if (sk->ax25->modulus == MODULUS) { + if (opt < 1 || opt > 7) + return -EINVAL; + } else { + if (opt < 1 || opt > 63) + return -EINVAL; + } sk->ax25->window = opt; return 0; @@ -689,6 +704,10 @@ static int ax25_setsockopt(struct socket *sock, int level, int optname, sk->ax25->backoff = opt ? 1 : 0; return 0; + case AX25_EXTSEQ: + sk->ax25->modulus = opt ? EMODULUS : MODULUS; + return 0; + default: return -ENOPROTOOPT; } @@ -734,6 +753,10 @@ static int ax25_getsockopt(struct socket *sock, int level, int optname, val = sk->ax25->backoff; break; + case AX25_EXTSEQ: + val = (sk->ax25->modulus == EMODULUS); + return 0; + default: return -ENOPROTOOPT; } @@ -907,6 +930,7 @@ static struct sock *ax25_make_new(struct sock *osk, struct device *dev) sk->write_space = def_callback1; sk->error_report = def_callback1; + ax25->modulus = osk->ax25->modulus; ax25->backoff = osk->ax25->backoff; ax25->rtt = osk->ax25->rtt; ax25->t1 = osk->ax25->t1; @@ -955,7 +979,7 @@ static int ax25_release(struct socket *sock, struct socket *peer) break; case AX25_STATE_1: - ax25_send_control(sk->ax25, DISC | PF, C_COMMAND); + ax25_send_control(sk->ax25, DISC, POLLON, C_COMMAND); sk->ax25->state = AX25_STATE_0; sk->dead = 1; sk->state_change(sk); @@ -963,7 +987,7 @@ static int ax25_release(struct socket *sock, struct socket *peer) break; case AX25_STATE_2: - ax25_send_control(sk->ax25, DM | PF, C_RESPONSE); + ax25_send_control(sk->ax25, DM, POLLON, C_RESPONSE); sk->ax25->state = AX25_STATE_0; sk->dead = 1; sk->state_change(sk); @@ -972,9 +996,9 @@ static int ax25_release(struct socket *sock, struct socket *peer) case AX25_STATE_3: case AX25_STATE_4: - ax25_clear_tx_queue(sk->ax25); + ax25_clear_queues(sk->ax25); sk->ax25->n2count = 0; - ax25_send_control(sk->ax25, DISC | PF, C_COMMAND); + ax25_send_control(sk->ax25, DISC, POLLON, C_COMMAND); sk->ax25->t3timer = 0; sk->ax25->t1timer = sk->ax25->t1 = ax25_calculate_t1(sk->ax25); sk->ax25->state = AX25_STATE_2; @@ -1306,9 +1330,13 @@ static int ax25_rcv(struct sk_buff *skb, struct device *dev, ax25_address *dev_a dev = dev_scan; } #endif - build_ax25_addr(skb->data, &src, &dest, &dp, type); + build_ax25_addr(skb->data, &src, &dest, &dp, type, MODULUS); skb->arp = 1; - ax25_queue_xmit(skb, dev, SOPRI_NORMAL); + if (ax25_digi_on) { + ax25_queue_xmit(skb, dev, SOPRI_NORMAL); + } else { + kfree_skb(skb, FREE_READ); + } } else { kfree_skb(skb, FREE_READ); } @@ -1398,12 +1426,12 @@ static int ax25_rcv(struct sk_buff *skb, struct device *dev, ax25_address *dev_a return 0; } - if ((*skb->data & 0xEF) != SABM) { + if ((*skb->data & ~PF) != SABM && (*skb->data & ~PF) != SABME) { /* * Never reply to a DM. Also ignore any connects for * addresses that are not our interfaces and not a socket. */ - if ((*skb->data & 0xEF) != DM && mine) + if ((*skb->data & ~PF) != DM && mine) ax25_return_dm(dev, &src, &dest, &dp); kfree_skb(skb, FREE_READ); @@ -1471,9 +1499,15 @@ static int ax25_rcv(struct sk_buff *skb, struct device *dev, ax25_address *dev_a ax25_digi_invert(&dp, ax25->digipeat); } + if ((*skb->data & ~PF) == SABME) { + ax25->modulus = EMODULUS; + } else { + ax25->modulus = MODULUS; + } + ax25->device = dev; - ax25_send_control(ax25, UA | PF, C_RESPONSE); + ax25_send_control(ax25, UA, POLLON, C_RESPONSE); ax25->t3timer = ax25->t3; ax25->state = AX25_STATE_3; @@ -1524,10 +1558,10 @@ static int bpq_rcv(struct sk_buff *skb, struct device *dev, struct packet_type * return 0; } - len = skb->data[14] + skb->data[15] * 256 - 5; + len = skb->data[0] + skb->data[1] * 256 - 5; - skb_pull(skb, AX25_BPQ_HEADER_LEN); /* Remove the BPQ Header */ - skb_trim(skb, len); /* Set the length of the data */ + skb_pull(skb, 2); /* Remove the length bytes */ + skb_trim(skb, len); /* Set the length of the data */ return ax25_rcv(skb, dev, &port_call, ptype); } @@ -1618,7 +1652,7 @@ static int ax25_sendto(struct socket *sock, void *ubuf, int len, int noblock, printk("AX.25: sendto: building packet.\n"); /* Assume the worst case */ - size = len + 2 + size_ax25_addr(dp) + AX25_BPQ_HEADER_LEN; + size = len + 3 + size_ax25_addr(dp) + AX25_BPQ_HEADER_LEN; if ((skb = sock_alloc_send_skb(sk, size, 0, &err)) == NULL) return err; @@ -1662,7 +1696,7 @@ static int ax25_sendto(struct socket *sock, void *ubuf, int len, int noblock, } /* Build an AX.25 header */ - asmptr += (lv = build_ax25_addr(asmptr, &sk->ax25->source_addr, &sax.sax25_call, dp, C_COMMAND)); + asmptr += (lv = build_ax25_addr(asmptr, &sk->ax25->source_addr, &sax.sax25_call, dp, C_COMMAND, MODULUS)); if (sk->debug) printk("Built header (%d bytes)\n",lv); @@ -1716,7 +1750,7 @@ static int ax25_recvfrom(struct socket *sock, void *ubuf, int size, int noblock, if (sk->type == SOCK_SEQPACKET) { if (sk->state != TCP_ESTABLISHED) return -ENOTCONN; - bias = 2; + bias = 1; } /* Now we can treat all alike */ @@ -1843,6 +1877,15 @@ static int ax25_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg) ax25_uid_policy = amount; return 0; + case SIOCAX25DIGCTL: + if ((err = verify_area(VERIFY_READ, (void *)arg, sizeof(int))) != 0) + return err; + if (!suser()) + return -EPERM; + amount = get_fs_long((void *)arg); + ax25_digi_on = amount ? 1 : 0; + return 0; + case SIOCGIFADDR: case SIOCSIFADDR: case SIOCGIFDSTADDR: @@ -1874,7 +1917,7 @@ int ax25_get_info(char *buffer, char **start, off_t offset, int length) cli(); - len += sprintf(buffer, "dest_addr src_addr dev st vs vr va t1 t2 t3 n2 rtt wnd Snd-Q Rcv-Q\n"); + len += sprintf(buffer, "dest_addr src_addr dev st vs vr va t1 t2 t3 n2 rtt wnd Snd-Q Rcv-Q\n"); for (ax25 = ax25_list; ax25 != NULL; ax25 = ax25->next) { if ((dev = ax25->device) == NULL) @@ -1884,7 +1927,7 @@ int ax25_get_info(char *buffer, char **start, off_t offset, int length) len += sprintf(buffer + len, "%-9s ", ax2asc(&ax25->dest_addr)); - len += sprintf(buffer + len, "%-9s %-4s %2d %2d %2d %2d %3d/%03d %2d/%02d %3d/%03d %2d/%02d %3d %3d", + len += sprintf(buffer + len, "%-9s %-4s %2d %3d %3d %3d %3d/%03d %2d/%02d %3d/%03d %2d/%02d %3d %3d", ax2asc(&ax25->source_addr), devname, ax25->state, ax25->vs, ax25->vr, ax25->va, @@ -2050,7 +2093,7 @@ int ax25_encapsulate(struct sk_buff *skb, struct device *dev, unsigned short typ buff[6] &= ~LAPB_C; buff[6] &= ~LAPB_E; - buff[6] |= SSID_SPARE; + buff[6] |= SSSID_SPARE; buff += AX25_ADDR_LEN; if (saddr != NULL) @@ -2060,7 +2103,7 @@ int ax25_encapsulate(struct sk_buff *skb, struct device *dev, unsigned short typ buff[6] &= ~LAPB_C; buff[6] |= LAPB_E; - buff[6] |= SSID_SPARE; + buff[6] |= SSSID_SPARE; buff += AX25_ADDR_LEN; *buff++ = LAPB_UI; /* UI */ @@ -2105,11 +2148,11 @@ int ax25_rebuild_header(unsigned char *bp, struct device *dev, unsigned long des bp[7] &= ~LAPB_C; bp[7] &= ~LAPB_E; - bp[7] |= SSID_SPARE; + bp[7] |= SSSID_SPARE; bp[14] &= ~LAPB_C; bp[14] |= LAPB_E; - bp[14] |= SSID_SPARE; + bp[14] |= SSSID_SPARE; return 0; } diff --git a/net/ax25/ax25_in.c b/net/ax25/ax25_in.c index 643735e0ec74..9b8a6307c003 100644 --- a/net/ax25/ax25_in.c +++ b/net/ax25/ax25_in.c @@ -1,5 +1,5 @@ /* - * AX.25 release 029 + * AX.25 release 030 * * This is ALPHA test software. This code may break your machine, randomly fail to work with new * releases, misbehave and/or generally screw up. It might even work. @@ -24,6 +24,8 @@ * the sock structure. * AX.25 029 Alan(GW4PTS) Switched to KA9Q constant names. * Jonathan(G4KLX) Added IP mode registration. + * AX.25 030 Jonathan(G4KLX) Added AX.25 fragment reception. + * Upgraded state machine for SABME. */ #include @@ -53,6 +55,65 @@ #include #endif +static int ax25_rx_iframe(ax25_cb *, struct sk_buff *); + +/* + * Given a fragment, queue it on the fragment queue and if the fragment + * is complete, send it back to ax25_rx_iframe. + */ +static int ax25_rx_fragment(ax25_cb *ax25, struct sk_buff *skb) +{ + struct sk_buff *skbn, *skbo; + + if (ax25->fragno != 0) { + if (!(*skb->data & SEG_FIRST)) { + if ((ax25->fragno - 1) == (*skb->data & SEG_REM)) { + ax25->fragno = *skb->data & SEG_REM; + skb_pull(skb, 1); + ax25->fraglen += skb->len; + skb_queue_tail(&ax25->frag_queue, skb); + + if (ax25->fragno == 0) { + if ((skbn = alloc_skb(AX25_MAX_HEADER_LEN + ax25->fraglen, GFP_ATOMIC)) == NULL) + return 0; + + skbn->free = 1; + skbn->arp = 1; + + if (ax25->sk != NULL) { + skbn->sk = ax25->sk; + ax25->sk->rmem_alloc += skbn->truesize; + } + + skb_reserve(skbn, AX25_MAX_HEADER_LEN); + + while ((skbo = skb_dequeue(&ax25->frag_queue)) != NULL) { + memcpy(skb_put(skbn, skbo->len), skbo->data, skbo->len); + kfree_skb(skbo, FREE_READ); + } + + ax25->fraglen = 0; + + if (ax25_rx_iframe(ax25, skbn) == 0) + kfree_skb(skbn, FREE_READ); + } + + return 1; + } + } + } else { + if (*skb->data & SEG_FIRST) { + ax25->fragno = *skb->data & SEG_REM; + skb_pull(skb, 1); + ax25->fraglen = skb->len; + skb_queue_tail(&ax25->frag_queue, skb); + return 1; + } + } + + return 0; +} + /* * This is where all valid I frames are sent to, to be dispatched to * whichever protocol requires them. @@ -63,18 +124,18 @@ static int ax25_rx_iframe(ax25_cb *ax25, struct sk_buff *skb) skb->h.raw = skb->data; - switch (skb->data[1]) { + switch (*skb->data) { #ifdef CONFIG_NETROM case AX25_P_NETROM: - skb_pull(skb, 2); + skb_pull(skb, 1); /* Remove PID */ queued = nr_route_frame(skb, ax25); break; #endif #ifdef CONFIG_INET case AX25_P_IP: + skb_pull(skb, 1); /* Remove PID */ + skb->h.raw = skb->data; ax25_ip_mode_set(&ax25->dest_addr, ax25->device, 'V'); - skb->h.raw += 2; - skb_push(skb, skb->dev->hard_header_len); ip_rcv(skb, skb->dev, NULL); /* Wrong ptype */ queued = 1; break; @@ -88,7 +149,12 @@ static int ax25_rx_iframe(ax25_cb *ax25, struct sk_buff *skb) } } break; - + + case AX25_P_SEGMENT: + skb_pull(skb, 1); /* Remove PID */ + queued = ax25_rx_fragment(ax25, skb); + break; + default: break; } @@ -101,17 +167,21 @@ static int ax25_rx_iframe(ax25_cb *ax25, struct sk_buff *skb) * The handling of the timer(s) is in file ax25_timer.c. * Handling of state 0 and connection release is in ax25.c. */ -static int ax25_state1_machine(ax25_cb *ax25, struct sk_buff *skb, int frametype, int type) +static int ax25_state1_machine(ax25_cb *ax25, struct sk_buff *skb, int frametype, int pf, int type) { - int pf = skb->data[0] & PF; - switch (frametype) { case SABM: - ax25_send_control(ax25, UA | pf, C_RESPONSE); + ax25->modulus = MODULUS; + ax25_send_control(ax25, UA, pf, C_RESPONSE); + break; + + case SABME: + ax25->modulus = EMODULUS; + ax25_send_control(ax25, UA, pf, C_RESPONSE); break; case DISC: - ax25_send_control(ax25, DM | pf, C_RESPONSE); + ax25_send_control(ax25, DM, pf, C_RESPONSE); break; case UA: @@ -135,14 +205,18 @@ static int ax25_state1_machine(ax25_cb *ax25, struct sk_buff *skb, int frametype case DM: if (pf) { - ax25_clear_tx_queue(ax25); - ax25->state = AX25_STATE_0; - if (ax25->sk != NULL) { - ax25->sk->state = TCP_CLOSE; - ax25->sk->err = ECONNREFUSED; - if (!ax25->sk->dead) - ax25->sk->state_change(ax25->sk); - ax25->sk->dead = 1; + if (ax25->modulus == MODULUS) { + ax25_clear_queues(ax25); + ax25->state = AX25_STATE_0; + if (ax25->sk != NULL) { + ax25->sk->state = TCP_CLOSE; + ax25->sk->err = ECONNREFUSED; + if (!ax25->sk->dead) + ax25->sk->state_change(ax25->sk); + ax25->sk->dead = 1; + } + } else { + ax25->modulus = MODULUS; } } break; @@ -159,17 +233,16 @@ static int ax25_state1_machine(ax25_cb *ax25, struct sk_buff *skb, int frametype * The handling of the timer(s) is in file ax25_timer.c * Handling of state 0 and connection release is in ax25.c. */ -static int ax25_state2_machine(ax25_cb *ax25, struct sk_buff *skb, int frametype, int type) +static int ax25_state2_machine(ax25_cb *ax25, struct sk_buff *skb, int frametype, int pf, int type) { - int pf = skb->data[0] & PF; - switch (frametype) { case SABM: - ax25_send_control(ax25, DM | pf, C_RESPONSE); + case SABME: + ax25_send_control(ax25, DM, pf, C_RESPONSE); break; case DISC: - ax25_send_control(ax25, UA | pf, C_RESPONSE); + ax25_send_control(ax25, UA, pf, C_RESPONSE); break; case UA: @@ -203,7 +276,7 @@ static int ax25_state2_machine(ax25_cb *ax25, struct sk_buff *skb, int frametype case RNR: case RR: if (pf) - ax25_send_control(ax25, DM | PF, C_RESPONSE); + ax25_send_control(ax25, DM, POLLON, C_RESPONSE); break; default: @@ -218,16 +291,25 @@ static int ax25_state2_machine(ax25_cb *ax25, struct sk_buff *skb, int frametype * The handling of the timer(s) is in file ax25_timer.c * Handling of state 0 and connection release is in ax25.c. */ -static int ax25_state3_machine(ax25_cb *ax25, struct sk_buff *skb, int frametype, int type) +static int ax25_state3_machine(ax25_cb *ax25, struct sk_buff *skb, int frametype, int ns, int nr, int pf, int type) { - unsigned short nr = (skb->data[0] >> 5) & 7; - unsigned short ns = (skb->data[0] >> 1) & 7; - int pf = skb->data[0] & PF; int queued = 0; switch (frametype) { case SABM: - ax25_send_control(ax25, UA | pf, C_RESPONSE); + ax25->modulus = MODULUS; + ax25_send_control(ax25, UA, pf, C_RESPONSE); + ax25->condition = 0x00; + ax25->t1timer = 0; + ax25->t3timer = ax25->t3; + ax25->vs = 0; + ax25->va = 0; + ax25->vr = 0; + break; + + case SABME: + ax25->modulus = EMODULUS; + ax25_send_control(ax25, UA, pf, C_RESPONSE); ax25->condition = 0x00; ax25->t1timer = 0; ax25->t3timer = ax25->t3; @@ -237,8 +319,8 @@ static int ax25_state3_machine(ax25_cb *ax25, struct sk_buff *skb, int frametype break; case DISC: - ax25_clear_tx_queue(ax25); - ax25_send_control(ax25, UA | pf, C_RESPONSE); + ax25_clear_queues(ax25); + ax25_send_control(ax25, UA, pf, C_RESPONSE); ax25->t3timer = 0; ax25->state = AX25_STATE_0; if (ax25->sk != NULL) { @@ -256,7 +338,7 @@ static int ax25_state3_machine(ax25_cb *ax25, struct sk_buff *skb, int frametype break; case DM: - ax25_clear_tx_queue(ax25); + ax25_clear_queues(ax25); ax25->t3timer = 0; ax25->state = AX25_STATE_0; if (ax25->sk) { @@ -327,7 +409,7 @@ static int ax25_state3_machine(ax25_cb *ax25, struct sk_buff *skb, int frametype if (pf) ax25_enquiry_response(ax25); break; } - ax25->vr = (ax25->vr + 1) % MODULUS; + ax25->vr = (ax25->vr + 1) % ax25->modulus; ax25->condition &= ~REJECT_CONDITION; if (pf) { ax25_enquiry_response(ax25); @@ -342,7 +424,7 @@ static int ax25_state3_machine(ax25_cb *ax25, struct sk_buff *skb, int frametype if (pf) ax25_enquiry_response(ax25); } else { ax25->condition |= REJECT_CONDITION; - ax25_send_control(ax25, REJ | pf, C_RESPONSE); + ax25_send_control(ax25, REJ, pf, C_RESPONSE); ax25->condition &= ~ACK_PENDING_CONDITION; } } @@ -366,16 +448,27 @@ static int ax25_state3_machine(ax25_cb *ax25, struct sk_buff *skb, int frametype * The handling of the timer(s) is in file ax25_timer.c * Handling of state 0 and connection release is in ax25.c. */ -static int ax25_state4_machine(ax25_cb *ax25, struct sk_buff *skb, int frametype, int type) +static int ax25_state4_machine(ax25_cb *ax25, struct sk_buff *skb, int frametype, int ns, int nr, int pf, int type) { - unsigned short nr = (skb->data[0] >> 5) & 7; - unsigned short ns = (skb->data[0] >> 1) & 7; - int pf = skb->data[0] & PF; int queued = 0; switch (frametype) { case SABM: - ax25_send_control(ax25, UA | pf, C_RESPONSE); + ax25->modulus = MODULUS; + ax25_send_control(ax25, UA, pf, C_RESPONSE); + ax25->condition = 0x00; + ax25->t1timer = 0; + ax25->t3timer = ax25->t3; + ax25->vs = 0; + ax25->va = 0; + ax25->vr = 0; + ax25->state = AX25_STATE_3; + ax25->n2count = 0; + break; + + case SABME: + ax25->modulus = EMODULUS; + ax25_send_control(ax25, UA, pf, C_RESPONSE); ax25->condition = 0x00; ax25->t1timer = 0; ax25->t3timer = ax25->t3; @@ -387,8 +480,8 @@ static int ax25_state4_machine(ax25_cb *ax25, struct sk_buff *skb, int frametype break; case DISC: - ax25_clear_tx_queue(ax25); - ax25_send_control(ax25, UA | pf, C_RESPONSE); + ax25_clear_queues(ax25); + ax25_send_control(ax25, UA, pf, C_RESPONSE); ax25->t3timer = 0; ax25->state = AX25_STATE_0; if (ax25->sk != NULL) { @@ -406,7 +499,7 @@ static int ax25_state4_machine(ax25_cb *ax25, struct sk_buff *skb, int frametype break; case DM: - ax25_clear_tx_queue(ax25); + ax25_clear_queues(ax25); ax25->t3timer = 0; ax25->state = AX25_STATE_0; if (ax25->sk != NULL) { @@ -518,7 +611,7 @@ static int ax25_state4_machine(ax25_cb *ax25, struct sk_buff *skb, int frametype if (pf) ax25_enquiry_response(ax25); break; } - ax25->vr = (ax25->vr + 1) % MODULUS; + ax25->vr = (ax25->vr + 1) % ax25->modulus; ax25->condition &= ~REJECT_CONDITION; if (pf) { ax25_enquiry_response(ax25); @@ -533,7 +626,7 @@ static int ax25_state4_machine(ax25_cb *ax25, struct sk_buff *skb, int frametype if (pf) ax25_enquiry_response(ax25); } else { ax25->condition |= REJECT_CONDITION; - ax25_send_control(ax25, REJ | pf, C_RESPONSE); + ax25_send_control(ax25, REJ, pf, C_RESPONSE); ax25->condition &= ~ACK_PENDING_CONDITION; } } @@ -557,7 +650,7 @@ static int ax25_state4_machine(ax25_cb *ax25, struct sk_buff *skb, int frametype */ int ax25_process_rx_frame(ax25_cb *ax25, struct sk_buff *skb, int type) { - int queued = 0, frametype; + int queued = 0, frametype, ns, nr, pf; if (ax25->state != AX25_STATE_1 && ax25->state != AX25_STATE_2 && ax25->state != AX25_STATE_3 && ax25->state != AX25_STATE_4) { @@ -567,20 +660,20 @@ int ax25_process_rx_frame(ax25_cb *ax25, struct sk_buff *skb, int type) del_timer(&ax25->timer); - frametype = ax25_decode(skb->data); + frametype = ax25_decode(ax25, skb, &ns, &nr, &pf); switch (ax25->state) { case AX25_STATE_1: - queued = ax25_state1_machine(ax25, skb, frametype, type); + queued = ax25_state1_machine(ax25, skb, frametype, pf, type); break; case AX25_STATE_2: - queued = ax25_state2_machine(ax25, skb, frametype, type); + queued = ax25_state2_machine(ax25, skb, frametype, pf, type); break; case AX25_STATE_3: - queued = ax25_state3_machine(ax25, skb, frametype, type); + queued = ax25_state3_machine(ax25, skb, frametype, ns, nr, pf, type); break; case AX25_STATE_4: - queued = ax25_state4_machine(ax25, skb, frametype, type); + queued = ax25_state4_machine(ax25, skb, frametype, ns, nr, pf, type); break; } diff --git a/net/ax25/ax25_out.c b/net/ax25/ax25_out.c index 5fddd53e7cd2..80957be361cc 100644 --- a/net/ax25/ax25_out.c +++ b/net/ax25/ax25_out.c @@ -1,5 +1,5 @@ /* - * AX.25 release 029 + * AX.25 release 030 * * This is ALPHA test software. This code may break your machine, randomly fail to work with new * releases, misbehave and/or generally screw up. It might even work. @@ -22,6 +22,8 @@ * AX.25 028a Jonathan(G4KLX) New state machine based on SDL diagrams. * AX.25 029 Alan(GW4PTS) Switched to KA9Q constant names. * Jonathan(G4KLX) Only poll when window is full. + * AX.25 030 Jonathan(G4KLX) Added fragmentation to ax25_output. + * Added support for extended AX.25. */ #include @@ -47,14 +49,67 @@ #include #include -int ax25_output(ax25_cb *ax25, struct sk_buff *skb) +/* + * All outgoing AX.25 I frames pass via this routine. Therefore this is + * where the fragmentation of frames takes place. + */ +void ax25_output(ax25_cb *ax25, struct sk_buff *skb) { - skb_queue_tail(&ax25->write_queue, skb); /* Throw it on the queue */ + struct sk_buff *skbn; + unsigned char *p; + int err, frontlen, mtu, len, fragno, first = 1; + + mtu = ax25->device->mtu; + + if (skb->len > mtu) { + mtu -= 2; /* Allow for fragment control info */ + + fragno = skb->len / mtu; + if (skb->len % mtu == 0) fragno--; + + frontlen = skb_headroom(skb); /* Address space + CTRL */ + + while (skb->len > 0) { + if (skb->sk != NULL) { + if ((skbn = sock_alloc_send_skb(skb->sk, mtu + 2 + frontlen, 0, &err)) == NULL) + return; + } else { + if ((skbn = alloc_skb(mtu + 2 + frontlen, GFP_ATOMIC)) == NULL) + return; + } + + skbn->sk = skb->sk; + skbn->free = 1; + skbn->arp = 1; + + skb_reserve(skbn, frontlen + 2); + + len = (mtu > skb->len) ? skb->len : mtu; + + memcpy(skb_put(skbn, len), skb->data, len); + skb_pull(skb, len); + + p = skb_push(skbn, 2); + + *p++ = AX25_P_SEGMENT; + + *p = fragno--; + if (first) { + *p |= SEG_FIRST; + first = 0; + } + + skb_queue_tail(&ax25->write_queue, skbn); /* Throw it on the queue */ + } + + skb->free = 1; + kfree_skb(skb, FREE_WRITE); + } else { + skb_queue_tail(&ax25->write_queue, skb); /* Throw it on the queue */ + } if (ax25->state == AX25_STATE_3 || ax25->state == AX25_STATE_4) ax25_kick(ax25); - - return 0; } /* @@ -67,13 +122,22 @@ static void ax25_send_iframe(ax25_cb *ax25, struct sk_buff *skb, int poll_bit) if (skb == NULL) return; - - frame = skb_push(skb, 1); /* KISS + header */ - *frame = I; - *frame |= poll_bit; - *frame |= (ax25->vr << 5); - *frame |= (ax25->vs << 1); + if (ax25->modulus == MODULUS) { + frame = skb_push(skb, 1); + + *frame = I; + *frame |= (poll_bit) ? PF : 0; + *frame |= (ax25->vr << 5); + *frame |= (ax25->vs << 1); + } else { + frame = skb_push(skb, 2); + + frame[0] = I; + frame[0] |= (ax25->vs << 1); + frame[1] = (poll_bit) ? EPF : 0; + frame[1] |= (ax25->vr << 1); + } ax25_transmit_buffer(ax25, skb, C_COMMAND); } @@ -87,7 +151,7 @@ void ax25_kick(ax25_cb *ax25) del_timer(&ax25->timer); start = (skb_peek(&ax25->ack_queue) == NULL) ? ax25->va : ax25->vs; - end = (ax25->va + ax25->window) % MODULUS; + end = (ax25->va + ax25->window) % ax25->modulus; if (!(ax25->condition & PEER_RX_BUSY_CONDITION) && start != end && @@ -111,7 +175,7 @@ void ax25_kick(ax25_cb *ax25) return; } - next = (ax25->vs + 1) % MODULUS; + next = (ax25->vs + 1) % ax25->modulus; #ifdef notdef last = (next == end) || skb_peek(&ax25->write_queue) == NULL; #else @@ -120,7 +184,7 @@ void ax25_kick(ax25_cb *ax25) /* * Transmit the frame copy. */ - ax25_send_iframe(ax25, skbn, (last) ? PF : 0); + ax25_send_iframe(ax25, skbn, (last) ? POLLON : POLLOFF); ax25->vs = next; @@ -167,7 +231,7 @@ void ax25_transmit_buffer(ax25_cb *ax25, struct sk_buff *skb, int type) } ptr = skb_push(skb, size_ax25_addr(ax25->digipeat)); - build_ax25_addr(ptr, &ax25->source_addr, &ax25->dest_addr, ax25->digipeat, type); + build_ax25_addr(ptr, &ax25->source_addr, &ax25->dest_addr, ax25->digipeat, type, ax25->modulus); skb->arp = 1; @@ -189,8 +253,12 @@ void ax25_establish_data_link(ax25_cb *ax25) ax25->condition = 0x00; ax25->n2count = 0; - ax25_send_control(ax25, SABM | PF, C_COMMAND); - + if (ax25->modulus == MODULUS) { + ax25_send_control(ax25, SABM, POLLON, C_COMMAND); + } else { + ax25_send_control(ax25, SABME, POLLON, C_COMMAND); + } + ax25->t3timer = 0; ax25->t2timer = 0; ax25->t1timer = ax25->t1 = ax25_calculate_t1(ax25); @@ -199,9 +267,9 @@ void ax25_establish_data_link(ax25_cb *ax25) void ax25_transmit_enquiry(ax25_cb *ax25) { if (ax25->condition & OWN_RX_BUSY_CONDITION) - ax25_send_control(ax25, RNR | PF, C_COMMAND); + ax25_send_control(ax25, RNR, POLLON, C_COMMAND); else - ax25_send_control(ax25, RR | PF, C_COMMAND); + ax25_send_control(ax25, RR, POLLON, C_COMMAND); ax25->condition &= ~ACK_PENDING_CONDITION; @@ -211,9 +279,9 @@ void ax25_transmit_enquiry(ax25_cb *ax25) void ax25_enquiry_response(ax25_cb *ax25) { if (ax25->condition & OWN_RX_BUSY_CONDITION) - ax25_send_control(ax25, RNR | PF, C_RESPONSE); + ax25_send_control(ax25, RNR, POLLON, C_RESPONSE); else - ax25_send_control(ax25, RR | PF, C_RESPONSE); + ax25_send_control(ax25, RR, POLLON, C_RESPONSE); ax25->condition &= ~ACK_PENDING_CONDITION; } diff --git a/net/ax25/ax25_route.c b/net/ax25/ax25_route.c index 839f11fa9462..dd90bebd50bc 100644 --- a/net/ax25/ax25_route.c +++ b/net/ax25/ax25_route.c @@ -1,5 +1,5 @@ /* - * AX.25 release 029 + * AX.25 release 030 * * This is ALPHA test software. This code may break your machine, randomly fail to work with new * releases, misbehave and/or generally screw up. It might even work. diff --git a/net/ax25/ax25_subr.c b/net/ax25/ax25_subr.c index cbcbe5898af0..b8fc02d7a600 100644 --- a/net/ax25/ax25_subr.c +++ b/net/ax25/ax25_subr.c @@ -1,5 +1,5 @@ /* - * AX.25 release 029 + * AX.25 release 030 * * This is ALPHA test software. This code may break your machine, randomly fail to work with new * releases, misbehave and/or generally screw up. It might even work. @@ -21,6 +21,8 @@ * History * AX.25 029 Alan(GW4PTS) Switched to KA9Q constant names. Removed * old BSD code. + * AX.25 030 Jonathan(G4KLX) Added support for extended AX.25. + * Added fragmentation support. */ #include @@ -49,9 +51,9 @@ /* #define NO_BACKOFF */ /* - * This routine purges the input queue of frames. + * This routine purges all the queues of frames. */ -void ax25_clear_tx_queue(ax25_cb *ax25) +void ax25_clear_queues(ax25_cb *ax25) { struct sk_buff *skb; @@ -64,6 +66,14 @@ void ax25_clear_tx_queue(ax25_cb *ax25) skb->free = 1; kfree_skb(skb, FREE_WRITE); } + + while ((skb = skb_dequeue(&ax25->reseq_queue)) != NULL) { + kfree_skb(skb, FREE_READ); + } + + while ((skb = skb_dequeue(&ax25->frag_queue)) != NULL) { + kfree_skb(skb, FREE_READ); + } } /* @@ -83,7 +93,7 @@ void ax25_frames_acked(ax25_cb *ax25, unsigned short nr) skb = skb_dequeue(&ax25->ack_queue); skb->free = 1; kfree_skb(skb, FREE_WRITE); - ax25->va = (ax25->va + 1) % MODULUS; + ax25->va = (ax25->va + 1) % ax25->modulus; } } @@ -111,7 +121,7 @@ int ax25_validate_nr(ax25_cb *ax25, unsigned short nr) while (vc != ax25->vs) { if (nr == vc) return 1; - vc = (vc + 1) % MODULUS; + vc = (vc + 1) % ax25->modulus; } if (nr == ax25->vs) return 1; @@ -119,16 +129,51 @@ int ax25_validate_nr(ax25_cb *ax25, unsigned short nr) return 0; } -int ax25_decode(unsigned char *frame) +/* + * This routine is the centralised routine for parsing the control + * information for the different frame formats. + */ +int ax25_decode(ax25_cb *ax25, struct sk_buff *skb, int *ns, int *nr, int *pf) { + unsigned char *frame; int frametype = ILLEGAL; - if ((frame[0] & S) == 0) - frametype = I; /* I frame - carries NR/NS/PF */ - else if ((frame[0] & U) == 1) /* S frame - take out PF/NR */ - frametype = frame[0] & 0x0F; - else if ((frame[0] & U) == 3) /* U frame - take out PF */ - frametype = frame[0] & ~PF; + frame = skb->data; + *ns = *nr = *pf = 0; + + if (ax25->modulus == MODULUS) { + if ((frame[0] & S) == 0) { + frametype = I; /* I frame - carries NR/NS/PF */ + *ns = (frame[0] >> 1) & 0x07; + *nr = (frame[0] >> 5) & 0x07; + *pf = frame[0] & PF; + } else if ((frame[0] & U) == 1) { /* S frame - take out PF/NR */ + frametype = frame[0] & 0x0F; + *nr = (frame[0] >> 5) & 0x07; + *pf = frame[0] & PF; + } else if ((frame[0] & U) == 3) { /* U frame - take out PF */ + frametype = frame[0] & ~PF; + *pf = frame[0] & PF; + } + skb_pull(skb, 1); + } else { + if ((frame[0] & S) == 0) { + frametype = I; /* I frame - carries NR/NS/PF */ + *ns = (frame[0] >> 1) & 0x7F; + *nr = (frame[1] >> 1) & 0x7F; + *pf = frame[1] & EPF; + skb_pull(skb, 2); + } else if ((frame[0] & U) == 1) { /* S frame - take out PF/NR */ + frametype = frame[0] & 0x0F; + *nr = (frame[1] >> 1) & 0x7F; + *pf = frame[1] & EPF; + skb_pull(skb, 2); + } else if ((frame[0] & U) == 3) { /* U frame - take out PF */ + frametype = frame[0] & ~PF; + *pf = frame[0] & PF; + skb_pull(skb, 1); + } + } return frametype; } @@ -138,7 +183,7 @@ int ax25_decode(unsigned char *frame) * command or response for the remote machine ( eg. RR, UA etc. ). * Only supervisory or unnumbered frames are processed. */ -void ax25_send_control(ax25_cb *ax25, int frametype, int type) +void ax25_send_control(ax25_cb *ax25, int frametype, int poll_bit, int type) { struct sk_buff *skb; unsigned char *dptr; @@ -147,7 +192,7 @@ void ax25_send_control(ax25_cb *ax25, int frametype, int type) if ((dev = ax25->device) == NULL) return; /* Route died */ - if ((skb = alloc_skb(AX25_BPQ_HEADER_LEN + size_ax25_addr(ax25->digipeat) + 1, GFP_ATOMIC)) == NULL) + if ((skb = alloc_skb(AX25_BPQ_HEADER_LEN + size_ax25_addr(ax25->digipeat) + 2, GFP_ATOMIC)) == NULL) return; skb_reserve(skb, AX25_BPQ_HEADER_LEN + size_ax25_addr(ax25->digipeat)); @@ -158,12 +203,24 @@ void ax25_send_control(ax25_cb *ax25, int frametype, int type) } /* Assume a response - address structure for DTE */ - dptr = skb_put(skb, 1); - - if ((frametype & U) == S) /* S frames carry NR */ - frametype |= (ax25->vr << 5); - - *dptr = frametype; + if (ax25->modulus == MODULUS) { + dptr = skb_put(skb, 1); + *dptr = frametype; + *dptr |= (poll_bit) ? PF : 0; + if ((frametype & U) == S) /* S frames carry NR */ + *dptr |= (ax25->vr << 5); + } else { + if ((frametype & U) == U) { + dptr = skb_put(skb, 1); + *dptr = frametype; + *dptr |= (poll_bit) ? PF : 0; + } else { + dptr = skb_put(skb, 2); + dptr[0] = frametype; + dptr[1] = (ax25->vr << 1); + dptr[1] |= (poll_bit) ? EPF : 0; + } + } skb->free = 1; @@ -201,7 +258,7 @@ void ax25_return_dm(struct device *dev, ax25_address *src, ax25_address *dest, a */ dptr = skb_push(skb, size_ax25_addr(digi)); - dptr += build_ax25_addr(dptr, dest, src, &retdigi, C_RESPONSE); + dptr += build_ax25_addr(dptr, dest, src, &retdigi, C_RESPONSE, MODULUS); skb->arp = 1; skb->free = 1; @@ -217,10 +274,13 @@ unsigned short ax25_calculate_t1(ax25_cb *ax25) #ifndef NO_BACKOFF int n, t = 2; - if (ax25->backoff) + if (ax25->backoff) { for (n = 0; n < ax25->n2count; n++) t *= 2; + if (t > 8) t = 8; + } + return t * ax25->rtt; #else return 2 * ax25->rtt; @@ -249,7 +309,6 @@ void ax25_calculate_rtt(ax25_cb *ax25) * Given an AX.25 address pull of to, from, digi list, command/response and the start of data * */ - unsigned char *ax25_parse_addr(unsigned char *buf, int len, ax25_address *src, ax25_address *dest, ax25_digi *digi, int *flags) { int d = 0; @@ -302,28 +361,32 @@ unsigned char *ax25_parse_addr(unsigned char *buf, int len, ax25_address *src, a /* * Assemble an AX.25 header from the bits */ - -int build_ax25_addr(unsigned char *buf, ax25_address *src, ax25_address *dest, ax25_digi *d, int flag) +int build_ax25_addr(unsigned char *buf, ax25_address *src, ax25_address *dest, ax25_digi *d, int flag, int modulus) { int len = 0; int ct = 0; memcpy(buf, dest, AX25_ADDR_LEN); - - if (flag != C_COMMAND && flag != C_RESPONSE) - printk("build_ax25_addr: Bogus flag %d\n!", flag); buf[6] &= ~(LAPB_E | LAPB_C); - buf[6] |= SSID_SPARE; + buf[6] |= SSSID_SPARE; if (flag == C_COMMAND) buf[6] |= LAPB_C; buf += AX25_ADDR_LEN; len += AX25_ADDR_LEN; + memcpy(buf, src, AX25_ADDR_LEN); buf[6] &= ~(LAPB_E | LAPB_C); - buf[6] |= SSID_SPARE; + buf[6] &= ~SSSID_SPARE; + + if (modulus == MODULUS) { + buf[6] |= SSSID_SPARE; + } else { + buf[6] |= ESSID_SPARE; + } if (flag == C_RESPONSE) buf[6] |= LAPB_C; + /* * Fast path the normal digiless path */ @@ -342,7 +405,7 @@ int build_ax25_addr(unsigned char *buf, ax25_address *src, ax25_address *dest, a else buf[6] &= ~AX25_REPEATED; buf[6] &= ~LAPB_E; - buf[6] |= SSID_SPARE; + buf[6] |= SSSID_SPARE; buf += AX25_ADDR_LEN; len += AX25_ADDR_LEN; @@ -365,7 +428,6 @@ int size_ax25_addr(ax25_digi *dp) /* * Reverse Digipeat List. May not pass both parameters as same struct */ - void ax25_digi_invert(ax25_digi *in, ax25_digi *out) { int ct = 0; diff --git a/net/ax25/ax25_timer.c b/net/ax25/ax25_timer.c index daa3bd6575cf..bf1f4695a16d 100644 --- a/net/ax25/ax25_timer.c +++ b/net/ax25/ax25_timer.c @@ -1,5 +1,5 @@ /* - * AX.25 release 029 + * AX.25 release 030 * * This is ALPHA test software. This code may break your machine, randomly fail to work with new * releases, misbehave and/or generally screw up. It might even work. @@ -63,7 +63,7 @@ void ax25_set_timer(ax25_cb *ax25) ax25->timer.data = (unsigned long)ax25; ax25->timer.function = &ax25_timer; - ax25->timer.expires = 10; + ax25->timer.expires = jiffies + 10; add_timer(&ax25->timer); } @@ -78,7 +78,7 @@ static void ax25_reset_timer(ax25_cb *ax25) ax25->timer.data = (unsigned long)ax25; ax25->timer.function = &ax25_timer; - ax25->timer.expires = 10; + ax25->timer.expires = jiffies + 10; add_timer(&ax25->timer); } @@ -111,7 +111,7 @@ static void ax25_timer(unsigned long param) if (ax25->sk != NULL) { if (ax25->sk->rmem_alloc < (ax25->sk->rcvbuf / 2) && (ax25->condition & OWN_RX_BUSY_CONDITION)) { ax25->condition &= ~OWN_RX_BUSY_CONDITION; - ax25_send_control(ax25, RR, C_RESPONSE); + ax25_send_control(ax25, RR, POLLOFF, C_RESPONSE); ax25->condition &= ~ACK_PENDING_CONDITION; break; } @@ -152,21 +152,30 @@ static void ax25_timer(unsigned long param) switch (ax25->state) { case AX25_STATE_1: if (ax25->n2count == ax25->n2) { + if (ax25->modulus == MODULUS) { #ifdef CONFIG_NETROM - nr_link_failed(&ax25->dest_addr, ax25->device); + nr_link_failed(&ax25->dest_addr, ax25->device); #endif - ax25_clear_tx_queue(ax25); - ax25->state = AX25_STATE_0; - if (ax25->sk != NULL) { - ax25->sk->state = TCP_CLOSE; - ax25->sk->err = ETIMEDOUT; - if (!ax25->sk->dead) - ax25->sk->state_change(ax25->sk); - ax25->sk->dead = 1; + ax25_clear_queues(ax25); + ax25->state = AX25_STATE_0; + if (ax25->sk != NULL) { + ax25->sk->state = TCP_CLOSE; + ax25->sk->err = ETIMEDOUT; + if (!ax25->sk->dead) + ax25->sk->state_change(ax25->sk); + ax25->sk->dead = 1; + } + } else { + ax25->modulus = MODULUS; + ax25->n2count = 0; } } else { ax25->n2count++; - ax25_send_control(ax25, SABM | PF, C_COMMAND); + if (ax25->modulus == MODULUS) { + ax25_send_control(ax25, SABM, POLLON, C_COMMAND); + } else { + ax25_send_control(ax25, SABME, POLLON, C_COMMAND); + } } break; @@ -175,7 +184,7 @@ static void ax25_timer(unsigned long param) #ifdef CONFIG_NETROM nr_link_failed(&ax25->dest_addr, ax25->device); #endif - ax25_clear_tx_queue(ax25); + ax25_clear_queues(ax25); ax25->state = AX25_STATE_0; if (ax25->sk != NULL) { ax25->sk->state = TCP_CLOSE; @@ -186,7 +195,7 @@ static void ax25_timer(unsigned long param) } } else { ax25->n2count++; - ax25_send_control(ax25, DISC | PF, C_COMMAND); + ax25_send_control(ax25, DISC, POLLON, C_COMMAND); } break; @@ -201,8 +210,8 @@ static void ax25_timer(unsigned long param) #ifdef CONFIG_NETROM nr_link_failed(&ax25->dest_addr, ax25->device); #endif - ax25_clear_tx_queue(ax25); - ax25_send_control(ax25, DM | PF, C_RESPONSE); + ax25_clear_queues(ax25); + ax25_send_control(ax25, DM, POLLON, C_RESPONSE); ax25->state = AX25_STATE_0; if (ax25->sk != NULL) { ax25->sk->state = TCP_CLOSE; diff --git a/net/ethernet/pe2.c b/net/ethernet/pe2.c index 30756461b391..8668949631dd 100644 --- a/net/ethernet/pe2.c +++ b/net/ethernet/pe2.c @@ -9,12 +9,8 @@ pEII_datalink_header(struct datalink_proto *dl, struct sk_buff *skb, unsigned char *dest_node) { struct device *dev = skb->dev; - unsigned long len = skb->len; - unsigned long hard_len = dev->hard_header_len; - - dev->hard_header(skb, dev, ETH_P_IPX, - dest_node, NULL, len - hard_len); - skb->h.raw = skb->data + hard_len; + + dev->hard_header(skb, dev, ETH_P_IPX, dest_node, NULL, skb->len); } struct datalink_proto * diff --git a/net/ipv4/arp.c b/net/ipv4/arp.c index 9fe0d60d92bc..82b15daa50cc 100644 --- a/net/ipv4/arp.c +++ b/net/ipv4/arp.c @@ -232,7 +232,7 @@ static void arp_check_expire(unsigned long dummy) */ del_timer(&arp_timer); - arp_timer.expires = ARP_CHECK_INTERVAL; + arp_timer.expires = jiffies + ARP_CHECK_INTERVAL; add_timer(&arp_timer); } @@ -411,7 +411,7 @@ static void arp_expire_request (unsigned long arg) /* Set new timer. */ del_timer(&entry->timer); - entry->timer.expires = ARP_RES_TIME; + entry->timer.expires = jiffies + ARP_RES_TIME; add_timer(&entry->timer); restore_flags(flags); arp_send(ARPOP_REQUEST, ETH_P_ARP, ip, dev, dev->pa_addr, @@ -962,7 +962,7 @@ int arp_find(unsigned char *haddr, u32 paddr, struct device *dev, init_timer(&entry->timer); entry->timer.function = arp_expire_request; entry->timer.data = (unsigned long)entry; - entry->timer.expires = ARP_RES_TIME; + entry->timer.expires = jiffies + ARP_RES_TIME; arp_tables[hash] = entry; add_timer(&entry->timer); entry->retries = ARP_MAX_TRIES; diff --git a/net/ipv4/igmp.c b/net/ipv4/igmp.c index a92fe9afc2d5..a92e3b47b276 100644 --- a/net/ipv4/igmp.c +++ b/net/ipv4/igmp.c @@ -69,7 +69,7 @@ extern __inline__ void igmp_start_timer(struct ip_mc_list *im) if(im->tm_running) return; tv=random()%(10*HZ); /* Pick a number any number 8) */ - im->timer.expires=tv; + im->timer.expires=jiffies+tv; im->tm_running=1; add_timer(&im->timer); } diff --git a/net/ipv4/ip.c b/net/ipv4/ip.c index de1949ce6be9..56dfbce957d8 100644 --- a/net/ipv4/ip.c +++ b/net/ipv4/ip.c @@ -523,7 +523,7 @@ static struct ipq *ip_create(struct sk_buff *skb, struct iphdr *iph, struct devi qp->dev = dev; /* Start a timer for this entry. */ - qp->timer.expires = IP_FRAG_TIME; /* about 30 seconds */ + qp->timer.expires = jiffies + IP_FRAG_TIME; /* about 30 seconds */ qp->timer.data = (unsigned long) qp; /* pointer to queue */ qp->timer.function = ip_expire; /* expire function */ add_timer(&qp->timer); @@ -682,7 +682,7 @@ static struct sk_buff *ip_defrag(struct iphdr *iph, struct sk_buff *skb, struct if (qp != NULL) { del_timer(&qp->timer); - qp->timer.expires = IP_FRAG_TIME; /* about 30 seconds */ + qp->timer.expires = jiffies + IP_FRAG_TIME; /* about 30 seconds */ qp->timer.data = (unsigned long) qp; /* pointer to queue */ qp->timer.function = ip_expire; /* expire function */ add_timer(&qp->timer); @@ -1974,7 +1974,7 @@ int ip_mc_procinfo(char *buffer, char **start, off_t offset, int length) len+=sprintf(buffer+len, "\t\t\t%08lX %5d %d:%08lX\n", im->multiaddr, im->users, - im->tm_running, im->timer.expires); + im->tm_running, im->timer.expires-jiffies); pos=begin+len; if(possport = htons(port); /* derived from PORT cmd */ ms->dst = iph->daddr; ms->dport = htons(20); /* ftp-data */ - ms->timer.expires = MASQUERADE_EXPIRE_TCP_FIN; + ms->timer.expires = jiffies+MASQUERADE_EXPIRE_TCP_FIN; add_timer(&ms->timer); /* @@ -724,7 +724,7 @@ void ip_fw_masquerade(struct sk_buff **skb_ptr, struct device *dev) if (iph->protocol==IPPROTO_UDP) { - ms->timer.expires = MASQUERADE_EXPIRE_UDP; + ms->timer.expires = jiffies+MASQUERADE_EXPIRE_UDP; recalc_check((struct udphdr *)portptr,iph->saddr,iph->daddr,size); } else @@ -744,10 +744,10 @@ void ip_fw_masquerade(struct sk_buff **skb_ptr, struct device *dev) */ if (ms->sawfin || th->fin) { - ms->timer.expires = MASQUERADE_EXPIRE_TCP_FIN; + ms->timer.expires = jiffies+MASQUERADE_EXPIRE_TCP_FIN; ms->sawfin = 1; } - else ms->timer.expires = MASQUERADE_EXPIRE_TCP; + else ms->timer.expires = jiffies+MASQUERADE_EXPIRE_TCP; tcp_send_check(th,iph->saddr,iph->daddr,size,skb->sk); } @@ -1482,13 +1482,13 @@ int ip_msqhst_procinfo(char *buffer, char **start, off_t offset, int length) { int timer_active = del_timer(&ms->timer); if (!timer_active) - ms->timer.expires = 0; + ms->timer.expires = jiffies; len+=sprintf(buffer+len,"%s %08lX:%04X %08lX:%04X %04X %08X %5d %lu\n", strProt[ms->protocol==IPPROTO_TCP], ntohl(ms->src),ntohs(ms->sport), ntohl(ms->dst),ntohs(ms->dport), ntohs(ms->mport), - ms->init_seq,ms->delta,ms->timer.expires); + ms->init_seq,ms->delta,ms->timer.expires-jiffies); if (timer_active) add_timer(&ms->timer); diff --git a/net/ipv4/proc.c b/net/ipv4/proc.c index e7124a42de6b..e61dc0e43e24 100644 --- a/net/ipv4/proc.c +++ b/net/ipv4/proc.c @@ -111,7 +111,7 @@ get__netinfo(struct proto *pro, char *buffer, int format, char **start, off_t of i, src, srcp, dest, destp, sp->state, format==0?sp->write_seq-sp->rcv_ack_seq:sp->rmem_alloc, format==0?sp->acked_seq-sp->copied_seq:sp->wmem_alloc, - timer_active, timer_expires, (unsigned) sp->retransmits, + timer_active, timer_expires-jiffies, (unsigned) sp->retransmits, sp->socket?SOCK_INODE(sp->socket)->i_uid:0, timer_active?sp->timeout:0); if (timer_active1) add_timer(&sp->retransmit_timer); diff --git a/net/ipv4/tcp.c b/net/ipv4/tcp.c index efe97857301c..b2359acc4e0a 100644 --- a/net/ipv4/tcp.c +++ b/net/ipv4/tcp.c @@ -596,7 +596,7 @@ static void reset_xmit_timer(struct sock *sk, int why, unsigned long when) when=3; printk("Error: Negative timer in xmit_timer\n"); } - sk->retransmit_timer.expires=when; + sk->retransmit_timer.expires=jiffies+when; add_timer(&sk->retransmit_timer); } @@ -749,7 +749,7 @@ static void retransmit_timer(unsigned long data) if (sk->inuse || in_bh) { /* Try again in 1 second */ - sk->retransmit_timer.expires = HZ; + sk->retransmit_timer.expires = jiffies+HZ; add_timer(&sk->retransmit_timer); sti(); return; @@ -1302,7 +1302,7 @@ void tcp_enqueue_partial(struct sk_buff * skb, struct sock * sk) /* * Wait up to 1 second for the buffer to fill. */ - sk->partial_timer.expires = HZ; + sk->partial_timer.expires = jiffies+HZ; sk->partial_timer.function = (void (*)(unsigned long)) tcp_send_partial; sk->partial_timer.data = (unsigned long) sk; add_timer(&sk->partial_timer); @@ -1956,7 +1956,7 @@ static void cleanup_rbuf(struct sock *sk) { /* Force it to send an ack soon. */ int was_active = del_timer(&sk->retransmit_timer); - if (!was_active || TCP_ACK_TIME < sk->timer.expires) + if (!was_active || jiffies+TCP_ACK_TIME < sk->timer.expires) { reset_xmit_timer(sk, TIME_WRITE, TCP_ACK_TIME); } diff --git a/net/ipv4/timer.c b/net/ipv4/timer.c index ebaa00d70be0..aa1c5afc2def 100644 --- a/net/ipv4/timer.c +++ b/net/ipv4/timer.c @@ -72,7 +72,7 @@ void reset_timer (struct sock *t, int timeout, unsigned long len) if ((int) len < 0) /* prevent close to infinite timers. THEY _DO_ */ len = 3; /* happen (negative values ?) - don't ask me why ! -FB */ #endif - t->timer.expires = len; + t->timer.expires = jiffies+len; add_timer (&t->timer); } @@ -95,7 +95,7 @@ void net_timer (unsigned long data) cli(); if (sk->inuse || in_bh) { - sk->timer.expires = 10; + sk->timer.expires = jiffies+10; add_timer(&sk->timer); sti(); return; diff --git a/net/ipx/af_ipx.c b/net/ipx/af_ipx.c index cfe35b853499..d8f8f605ec6a 100644 --- a/net/ipx/af_ipx.c +++ b/net/ipx/af_ipx.c @@ -425,7 +425,7 @@ static struct sk_buff * ipxitf_adjust_skbuff(ipx_interface *intrfc, struct sk_buff *skb) { struct sk_buff *skb2; - int in_offset = skb->h.raw - skb->data; + int in_offset = skb->h.raw - skb->head; int out_offset = intrfc->if_ipx_offset; #if 0 char *oldraw; @@ -533,6 +533,12 @@ ipxitf_send(ipx_interface *intrfc, struct sk_buff *skb, char *node) skb->sk->wmem_alloc += skb->truesize; } +#if 0 + /* Now log the packet just before transmission */ + dump_pkt("IPX snd:", (ipx_packet *)skb->h.raw); + dump_data("ETH hdr:", skb->data, skb->h.raw - skb->data); +#endif + /* Send it out */ dev_queue_xmit(skb, dev, SOPRI_NORMAL); return 0; @@ -1588,20 +1594,31 @@ static int ipx_getname(struct socket *sock, struct sockaddr *uaddr, /* * User to dump IPX packets (debugging) */ -void dump_data(char *str,unsigned char *d) { +void dump_data(char *str,unsigned char *d, int len) { static char h2c[] = "0123456789ABCDEF"; int l,i; char *p, b[64]; - for (l=0;l<16;l++) { + for (l=0;len > 0 && l<16;l++) { p = b; - for (i=0; i < 8 ; i++) { - *(p++) = h2c[d[i] & 0x0f]; - *(p++) = h2c[(d[i] >> 4) & 0x0f]; + for (i=0; i < 8 ; i++, --len) { + if (len > 0) { + *(p++) = h2c[(d[i] >> 4) & 0x0f]; + *(p++) = h2c[d[i] & 0x0f]; + } + else { + *(p++) = ' '; + *(p++) = ' '; + } *(p++) = ' '; } *(p++) = '-'; *(p++) = ' '; - for (i=0; i < 8 ; i++) *(p++) = ' '<= d[i] && d[i]<'\177' ? d[i] : '.'; + len += 8; + for (i=0; i < 8 ; i++, --len) + if (len > 0) + *(p++) = ' '<= d[i] && d[i]<'\177' ? d[i] : '.'; + else + *(p++) = ' '; *p = '\000'; d += i; printk("%s-%04X: %s\n",str,l*8,b); @@ -1623,8 +1640,10 @@ void dump_hdr(char *str,ipx_packet *p) { } void dump_pkt(char *str,ipx_packet *p) { + int len = ntohs(p->ipx_pktsize); dump_hdr(str,p); - dump_data(str,(unsigned char *)p); + if (len > 30) + dump_data(str,(unsigned char *)p + 30, len - 30); } #endif diff --git a/net/netrom/af_netrom.c b/net/netrom/af_netrom.c index e04c8d85ee81..be1c5a5ad024 100644 --- a/net/netrom/af_netrom.c +++ b/net/netrom/af_netrom.c @@ -18,6 +18,7 @@ * Jonathan(G4KLX) Complete bind re-think. * Alan(GW4PTS) Trivial tweaks into new format. * NET/ROM 003 Jonathan(G4KLX) Added G8BPQ extensions. + * Added NET/ROM routing ioctl. * * To do: * Fix non-blocking connect failure. @@ -95,6 +96,27 @@ static void nr_remove_socket(struct sock *sk) restore_flags(flags); } +/* + * Kill all bound sockets on a dropped device. + */ +static void nr_kill_by_device(struct device *dev) +{ + struct sock *s; + + for (s = nr_list; s != NULL; s = s->next) { + if (s->nr->device == dev) { + s->nr->state = NR_STATE_0; + s->nr->device = NULL; + s->state = TCP_CLOSE; + s->err = ENETUNREACH; + s->state_change(s); + s->dead = 1; + } + } + + nr_rt_device_down(dev); +} + /* * Handle device status changes. */ @@ -103,7 +125,7 @@ static int nr_device_event(unsigned long event, void *ptr) if (event != NETDEV_DOWN) return NOTIFY_DONE; - nr_rt_device_down(ptr); + nr_kill_by_device(ptr); return NOTIFY_DONE; } @@ -223,7 +245,7 @@ void nr_destroy_socket(struct sock *sk) /* Not static as its used by the timer * del_timer(&sk->timer); nr_remove_socket(sk); - nr_clear_tx_queue(sk); /* Flush the send queue */ + nr_clear_queues(sk); /* Flush the queues */ while ((skb = skb_dequeue(&sk->receive_queue)) != NULL) { if (skb->sk != sk) { /* A pending connection */ @@ -237,7 +259,7 @@ void nr_destroy_socket(struct sock *sk) /* Not static as its used by the timer * if (sk->wmem_alloc || sk->rmem_alloc) { /* Defer: outstanding buffers */ init_timer(&sk->timer); - sk->timer.expires = 10 * HZ; + sk->timer.expires = jiffies + 10 * HZ; sk->timer.function = nr_destroy_timer; sk->timer.data = (unsigned long)sk; add_timer(&sk->timer); @@ -446,6 +468,7 @@ static int nr_create(struct socket *sock, int protocol) skb_queue_head_init(&nr->ack_queue); skb_queue_head_init(&nr->reseq_queue); + skb_queue_head_init(&nr->frag_queue); nr->my_index = 0; nr->my_id = 0; @@ -471,7 +494,9 @@ static int nr_create(struct socket *sock, int protocol) nr->my_id = 0; nr->bpqext = 1; + nr->fraglen = 0; nr->state = NR_STATE_0; + nr->device = NULL; memset(&nr->source_addr, '\0', sizeof(ax25_address)); memset(&nr->user_addr, '\0', sizeof(ax25_address)); @@ -514,7 +539,6 @@ static struct sock *nr_make_new(struct sock *osk) init_timer(&sk->timer); - sk->rmem_alloc = 0; sk->dead = 0; sk->next = NULL; sk->priority = osk->priority; @@ -545,13 +569,16 @@ static struct sock *nr_make_new(struct sock *osk) skb_queue_head_init(&nr->ack_queue); skb_queue_head_init(&nr->reseq_queue); + skb_queue_head_init(&nr->frag_queue); nr->rtt = osk->nr->rtt; nr->t1 = osk->nr->t1; nr->t2 = osk->nr->t2; nr->n2 = osk->nr->n2; + nr->device = osk->nr->device; nr->bpqext = osk->nr->bpqext; + nr->fraglen = 0; nr->t1timer = 0; nr->t2timer = 0; @@ -606,7 +633,7 @@ static int nr_release(struct socket *sock, struct socket *peer) break; case NR_STATE_3: - nr_clear_tx_queue(sk); + nr_clear_queues(sk); sk->nr->n2count = 0; nr_write_internal(sk, NR_DISCREQ); sk->nr->t1timer = sk->nr->t1 = nr_calculate_t1(sk); @@ -635,6 +662,7 @@ static int nr_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len) { struct sock *sk; struct full_sockaddr_ax25 *addr = (struct full_sockaddr_ax25 *)uaddr; + struct device *dev; ax25_address *user, *source; sk = (struct sock *)sock->data; @@ -653,7 +681,7 @@ static int nr_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len) } #endif - if (nr_dev_get(&addr->fsa_ax25.sax25_call) == NULL) { + if ((dev = nr_dev_get(&addr->fsa_ax25.sax25_call)) == NULL) { if (sk->debug) printk("NET/ROM: bind failed: invalid node callsign\n"); return -EADDRNOTAVAIL; @@ -680,6 +708,7 @@ static int nr_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len) memcpy(&sk->nr->source_addr, source, sizeof(ax25_address)); } + sk->nr->device = dev; nr_insert_socket(sk); sk->zapped = 0; @@ -999,6 +1028,9 @@ static int nr_sendto(struct socket *sock, void *ubuf, int len, int noblock, if (sk->zapped) return -EADDRNOTAVAIL; + + if (sk->nr->device == NULL) + return -ENETUNREACH; if (usax) { if (addr_len < sizeof(sax)) @@ -1022,7 +1054,7 @@ static int nr_sendto(struct socket *sock, void *ubuf, int len, int noblock, if (sk->debug) printk("NET/ROM: sendto: building packet.\n"); - size = len + AX25_BPQ_HEADER_LEN + AX25_MAX_HEADER_LEN + 2 + NR_NETWORK_LEN + NR_TRANSPORT_LEN; + size = len + AX25_BPQ_HEADER_LEN + AX25_MAX_HEADER_LEN + 3 + NR_NETWORK_LEN + NR_TRANSPORT_LEN; if ((skb = sock_alloc_send_skb(sk, size, 0, &err)) == NULL) return err; @@ -1218,6 +1250,7 @@ static int nr_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg) case SIOCADDRT: case SIOCDELRT: case SIOCNRDECOBS: + case SIOCNRRTCTL: if (!suser()) return -EPERM; return nr_rt_ioctl(cmd, (void *)arg); @@ -1254,22 +1287,29 @@ static int nr_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg) int nr_get_info(char *buffer, char **start, off_t offset, int length) { struct sock *s; + struct device *dev; + char *devname; int len = 0; off_t pos = 0; off_t begin = 0; cli(); - len += sprintf(buffer, "user_addr dest_node src_node my your st vs vr va t1 t2 n2 rtt wnd Snd-Q Rcv-Q\n"); + len += sprintf(buffer, "user_addr dest_node src_node dev my your st vs vr va t1 t2 n2 rtt wnd Snd-Q Rcv-Q\n"); for (s = nr_list; s != NULL; s = s->next) { + if ((dev = s->nr->device) == NULL) + devname = "???"; + else + devname = dev->name; + len += sprintf(buffer + len, "%-9s ", ax2asc(&s->nr->user_addr)); len += sprintf(buffer + len, "%-9s ", ax2asc(&s->nr->dest_addr)); - len += sprintf(buffer + len, "%-9s %02X/%02X %02X/%02X %2d %2d %2d %2d %3d/%03d %2d/%02d %2d/%02d %3d %3d %5ld %5ld\n", + len += sprintf(buffer + len, "%-9s %-3s %02X/%02X %02X/%02X %2d %2d %2d %2d %3d/%03d %2d/%02d %2d/%02d %3d %3d %5ld %5ld\n", ax2asc(&s->nr->source_addr), - s->nr->my_index, s->nr->my_id, + devname, s->nr->my_index, s->nr->my_id, s->nr->your_index, s->nr->your_id, s->nr->state, s->nr->vs, s->nr->vr, s->nr->va, diff --git a/net/netrom/nr_dev.c b/net/netrom/nr_dev.c index e9a4ede95754..34cae068f010 100644 --- a/net/netrom/nr_dev.c +++ b/net/netrom/nr_dev.c @@ -79,14 +79,14 @@ static int nr_header(struct sk_buff *skb, struct device *dev, unsigned short typ memcpy(buff, (saddr != NULL) ? saddr : dev->dev_addr, dev->addr_len); buff[6] &= ~LAPB_C; buff[6] &= ~LAPB_E; - buff[6] |= SSID_SPARE; + buff[6] |= SSSID_SPARE; buff += AX25_ADDR_LEN; if (daddr != NULL) memcpy(buff, daddr, dev->addr_len); buff[6] &= ~LAPB_C; buff[6] |= LAPB_E; - buff[6] |= SSID_SPARE; + buff[6] |= SSSID_SPARE; buff += AX25_ADDR_LEN; *buff++ = nr_default.ttl; @@ -119,12 +119,12 @@ static int nr_rebuild_header(void *buff, struct device *dev, bp[6] &= ~LAPB_C; bp[6] &= ~LAPB_E; - bp[6] |= SSID_SPARE; + bp[6] |= SSSID_SPARE; bp += AX25_ADDR_LEN; bp[6] &= ~LAPB_C; bp[6] |= LAPB_E; - bp[6] |= SSID_SPARE; + bp[6] |= SSSID_SPARE; if (!nr_route_frame(skb, NULL)) { skb->free = 1; diff --git a/net/netrom/nr_in.c b/net/netrom/nr_in.c index 1e9697e89d20..2585262748b5 100644 --- a/net/netrom/nr_in.c +++ b/net/netrom/nr_in.c @@ -20,6 +20,7 @@ * * History * NET/ROM 001 Jonathan(G4KLX) Cloned from ax25_in.c + * NET/ROM 003 Jonathan(G4KLX) Added NET/ROM fragment reception. */ #include @@ -47,6 +48,40 @@ #include #include +static int nr_queue_rx_frame(struct sock *sk, struct sk_buff *skb, int more) +{ + struct sk_buff *skbo, *skbn = skb; + + if (more) { + sk->nr->fraglen += skb->len; + skb_queue_tail(&sk->nr->frag_queue, skb); + return 0; + } + + if (!more && sk->nr->fraglen > 0) { /* End of fragment */ + sk->nr->fraglen += skb->len; + skb_queue_tail(&sk->nr->frag_queue, skb); + + if ((skbn = alloc_skb(sk->nr->fraglen, GFP_ATOMIC)) == NULL) + return 1; + + skbn->free = 1; + skbn->arp = 1; + skbn->sk = sk; + sk->rmem_alloc += skb->truesize; + + while ((skbo = skb_dequeue(&sk->nr->frag_queue)) != NULL) { + memcpy(skb_put(skbn, skbo->len), skbo->data, skbo->len); + + kfree_skb(skbo, FREE_READ); + } + + sk->nr->fraglen = 0; + } + + return sock_queue_rcv_skb(sk, skbn); +} + /* * State machine for state 1, Awaiting Connection State. * The handling of the timer(s) is in file nr_timer.c. @@ -76,8 +111,8 @@ static int nr_state1_machine(struct sock *sk, struct sk_buff *skb, int frametype sk->state_change(sk); break; - case NR_CONNACK + NR_CHOKE_FLAG: - nr_clear_tx_queue(sk); + case NR_CONNACK | NR_CHOKE_FLAG: + nr_clear_queues(sk); sk->nr->state = NR_STATE_0; sk->state = TCP_CLOSE; sk->err = ECONNREFUSED; @@ -153,7 +188,7 @@ static int nr_state3_machine(struct sock *sk, struct sk_buff *skb, int frametype break; case NR_DISCREQ: - nr_clear_tx_queue(sk); + nr_clear_queues(sk); nr_write_internal(sk, NR_DISCACK); sk->nr->state = NR_STATE_0; sk->state = TCP_CLOSE; @@ -164,7 +199,7 @@ static int nr_state3_machine(struct sock *sk, struct sk_buff *skb, int frametype break; case NR_DISCACK: - nr_clear_tx_queue(sk); + nr_clear_queues(sk); sk->nr->state = NR_STATE_0; sk->state = TCP_CLOSE; sk->err = ECONNRESET; @@ -174,7 +209,7 @@ static int nr_state3_machine(struct sock *sk, struct sk_buff *skb, int frametype break; case NR_INFOACK: - case NR_INFOACK + NR_CHOKE_FLAG: + case NR_INFOACK | NR_CHOKE_FLAG: if (frametype & NR_CHOKE_FLAG) { sk->nr->condition |= PEER_RX_BUSY_CONDITION; sk->nr->t4timer = nr_default.busy_delay; @@ -194,8 +229,8 @@ static int nr_state3_machine(struct sock *sk, struct sk_buff *skb, int frametype } break; - case NR_INFOACK + NR_NAK_FLAG: - case NR_INFOACK + NR_NAK_FLAG + NR_CHOKE_FLAG: + case NR_INFOACK | NR_NAK_FLAG: + case NR_INFOACK | NR_NAK_FLAG | NR_CHOKE_FLAG: if (frametype & NR_CHOKE_FLAG) { sk->nr->condition |= PEER_RX_BUSY_CONDITION; sk->nr->t4timer = nr_default.busy_delay; @@ -213,9 +248,9 @@ static int nr_state3_machine(struct sock *sk, struct sk_buff *skb, int frametype break; case NR_INFO: - case NR_INFO + NR_CHOKE_FLAG: - case NR_INFO + NR_MORE_FLAG: - case NR_INFO + NR_CHOKE_FLAG + NR_MORE_FLAG: + case NR_INFO | NR_CHOKE_FLAG: + case NR_INFO | NR_MORE_FLAG: + case NR_INFO | NR_CHOKE_FLAG | NR_MORE_FLAG: if (frametype & NR_CHOKE_FLAG) { sk->nr->condition |= PEER_RX_BUSY_CONDITION; sk->nr->t4timer = nr_default.busy_delay; @@ -243,7 +278,7 @@ static int nr_state3_machine(struct sock *sk, struct sk_buff *skb, int frametype while ((skbn = skb_dequeue(&sk->nr->reseq_queue)) != NULL) { ns = skbn->data[2]; if (ns == sk->nr->vr) { - if (sock_queue_rcv_skb(sk, skbn) == 0) { + if (nr_queue_rx_frame(sk, skbn, frametype & NR_MORE_FLAG) == 0) { sk->nr->vr = (sk->nr->vr + 1) % NR_MODULUS; } else { sk->nr->condition |= OWN_RX_BUSY_CONDITION; diff --git a/net/netrom/nr_out.c b/net/netrom/nr_out.c index 92ebe7fb297a..5469d172ad5e 100644 --- a/net/netrom/nr_out.c +++ b/net/netrom/nr_out.c @@ -14,6 +14,7 @@ * * History * NET/ROM 001 Jonathan(G4KLX) Cloned from ax25_out.c + * NET/ROM 003 Jonathan(G4KLX) Added NET/ROM fragmentation. */ #include @@ -40,19 +41,64 @@ #include #include -int nr_output(struct sock *sk, struct sk_buff *skb) +/* + * This is where all NET/ROM frames pass, except for IP-over-NET/ROM which + * cannot be fragmented in this manner. + */ +void nr_output(struct sock *sk, struct sk_buff *skb) { - skb_queue_tail(&sk->write_queue, skb); /* Throw it on the queue */ + struct sk_buff *skbn; + unsigned char transport[NR_TRANSPORT_LEN]; + int err, frontlen, len, mtu; + + mtu = sk->nr->device->mtu; + + if (skb->len - NR_TRANSPORT_LEN > mtu) { + /* Save a copy of the Transport Header */ + memcpy(transport, skb->data, NR_TRANSPORT_LEN); + skb_pull(skb, NR_TRANSPORT_LEN); + + frontlen = skb_headroom(skb); + + while (skb->len > 0) { + if ((skbn = sock_alloc_send_skb(sk, frontlen + mtu, 0, &err)) == NULL) + return; + + skbn->sk = sk; + skbn->free = 1; + skbn->arp = 1; + + skb_reserve(skbn, frontlen); + + len = (mtu > skb->len) ? skb->len : mtu; + + /* Copy the user data */ + memcpy(skb_put(skbn, len), skb->data, len); + skb_pull(skb, len); + + /* Duplicate the Transport Header */ + skb_push(skbn, NR_TRANSPORT_LEN); + memcpy(skbn->data, transport, NR_TRANSPORT_LEN); + + if (skb->len > 0) + skbn->data[4] |= NR_MORE_FLAG; + + skb_queue_tail(&sk->write_queue, skbn); /* Throw it on the queue */ + } + + skb->free = 1; + kfree_skb(skb, FREE_WRITE); + } else { + skb_queue_tail(&sk->write_queue, skb); /* Throw it on the queue */ + } if (sk->nr->state == NR_STATE_3) nr_kick(sk); - - return 0; } /* - * This procedure is passed a buffer descriptor for an iframe. It builds - * the rest of the control part of the frame and then writes it out. + * This procedure is passed a buffer descriptor for an iframe. It builds + * the rest of the control part of the frame and then writes it out. */ static void nr_send_iframe(struct sock *sk, struct sk_buff *skb) { @@ -62,6 +108,9 @@ static void nr_send_iframe(struct sock *sk, struct sk_buff *skb) skb->data[2] = sk->nr->vs; skb->data[3] = sk->nr->vr; + if (sk->nr->condition & OWN_RX_BUSY_CONDITION) + skb->data[4] |= NR_CHOKE_FLAG; + nr_transmit_buffer(sk, skb); } @@ -154,13 +203,13 @@ void nr_transmit_buffer(struct sock *sk, struct sk_buff *skb) memcpy(dptr, &sk->nr->source_addr, sizeof(ax25_address)); dptr[6] &= ~LAPB_C; dptr[6] &= ~LAPB_E; - dptr[6] |= SSID_SPARE; + dptr[6] |= SSSID_SPARE; dptr += AX25_ADDR_LEN; memcpy(dptr, &sk->nr->dest_addr, sizeof(ax25_address)); dptr[6] &= ~LAPB_C; dptr[6] |= LAPB_E; - dptr[6] |= SSID_SPARE; + dptr[6] |= SSSID_SPARE; dptr += AX25_ADDR_LEN; *dptr++ = nr_default.ttl; @@ -207,10 +256,10 @@ void nr_enquiry_response(struct sock *sk) int frametype = NR_INFOACK; if (sk->nr->condition & OWN_RX_BUSY_CONDITION) { - frametype += NR_CHOKE_FLAG; + frametype |= NR_CHOKE_FLAG; } else { if (skb_peek(&sk->nr->reseq_queue) != NULL) { - frametype += NR_NAK_FLAG; + frametype |= NR_NAK_FLAG; } } diff --git a/net/netrom/nr_route.c b/net/netrom/nr_route.c index bb629dfe2971..24f63b1eea98 100644 --- a/net/netrom/nr_route.c +++ b/net/netrom/nr_route.c @@ -53,6 +53,7 @@ #include static int nr_neigh_no = 1; +static int nr_route_on = 1; static struct nr_node *nr_node_list = NULL; static struct nr_neigh *nr_neigh_list = NULL; @@ -564,6 +565,7 @@ int nr_rt_ioctl(unsigned int cmd, void *arg) struct nr_route_struct nr_route; struct device *dev; int err; + long opt = 0; switch (cmd) { @@ -606,6 +608,13 @@ int nr_rt_ioctl(unsigned int cmd, void *arg) case SIOCNRDECOBS: return nr_dec_obs(); + + case SIOCNRRTCTL: + if ((err = verify_area(VERIFY_READ, arg, sizeof(int))) != 0) + return err; + opt = get_fs_long((void *)arg); + nr_route_on = opt ? 1 : 0; + return 0; } return 0; @@ -652,6 +661,9 @@ int nr_route_frame(struct sk_buff *skb, ax25_cb *ax25) if ((dev = nr_dev_get(nr_dest)) != NULL) /* Its for me */ return nr_rx_frame(skb, dev); + if (!nr_route_on && ax25 != NULL) + return 0; + /* Its Time-To-Live has expired */ if (--skb->data[14] == 0) return 0; diff --git a/net/netrom/nr_subr.c b/net/netrom/nr_subr.c index b67145afbaaa..30bdaeaa53af 100644 --- a/net/netrom/nr_subr.c +++ b/net/netrom/nr_subr.c @@ -42,9 +42,9 @@ #include /* - * This routine purges the input queue of frames. + * This routine purges all of the queues of frames. */ -void nr_clear_tx_queue(struct sock *sk) +void nr_clear_queues(struct sock *sk) { struct sk_buff *skb; @@ -61,7 +61,10 @@ void nr_clear_tx_queue(struct sock *sk) } while ((skb = skb_dequeue(&sk->nr->reseq_queue)) != NULL) { - skb->free = 1; + kfree_skb(skb, FREE_READ); + } + + while ((skb = skb_dequeue(&sk->nr->frag_queue)) != NULL) { kfree_skb(skb, FREE_READ); } } @@ -153,7 +156,7 @@ void nr_write_internal(struct sock *sk, int frametype) unsigned char *dptr; int len, timeout; - len = AX25_BPQ_HEADER_LEN + AX25_MAX_HEADER_LEN + 2 + NR_NETWORK_LEN + NR_TRANSPORT_LEN; + len = AX25_BPQ_HEADER_LEN + AX25_MAX_HEADER_LEN + 3 + NR_NETWORK_LEN + NR_TRANSPORT_LEN; switch (frametype & 0x0F) { case NR_CONNREQ: @@ -194,12 +197,12 @@ void nr_write_internal(struct sock *sk, int frametype) memcpy(dptr, &sk->nr->user_addr, sizeof(ax25_address)); dptr[6] &= ~LAPB_C; dptr[6] &= ~LAPB_E; - dptr[6] |= SSID_SPARE; + dptr[6] |= SSSID_SPARE; dptr += AX25_ADDR_LEN; memcpy(dptr, &sk->nr->source_addr, sizeof(ax25_address)); dptr[6] &= ~LAPB_C; dptr[6] &= ~LAPB_E; - dptr[6] |= SSID_SPARE; + dptr[6] |= SSSID_SPARE; dptr += AX25_ADDR_LEN; *dptr++ = timeout % 256; *dptr++ = timeout / 256; @@ -248,7 +251,7 @@ void nr_transmit_dm(struct sk_buff *skb) unsigned char *dptr; int len; - len = AX25_BPQ_HEADER_LEN + AX25_MAX_HEADER_LEN + 2 + NR_NETWORK_LEN + NR_TRANSPORT_LEN + 1; + len = AX25_BPQ_HEADER_LEN + AX25_MAX_HEADER_LEN + 3 + NR_NETWORK_LEN + NR_TRANSPORT_LEN + 1; if ((skbn = alloc_skb(len, GFP_ATOMIC)) == NULL) return; @@ -260,13 +263,13 @@ void nr_transmit_dm(struct sk_buff *skb) memcpy(dptr, skb->data + 7, AX25_ADDR_LEN); dptr[6] &= ~LAPB_C; dptr[6] &= ~LAPB_E; - dptr[6] |= SSID_SPARE; + dptr[6] |= SSSID_SPARE; dptr += AX25_ADDR_LEN; memcpy(dptr, skb->data + 0, AX25_ADDR_LEN); dptr[6] &= ~LAPB_C; dptr[6] |= LAPB_E; - dptr[6] |= SSID_SPARE; + dptr[6] |= SSSID_SPARE; dptr += AX25_ADDR_LEN; *dptr++ = nr_default.ttl; @@ -275,7 +278,7 @@ void nr_transmit_dm(struct sk_buff *skb) *dptr++ = skb->data[16]; *dptr++ = 0; *dptr++ = 0; - *dptr++ = NR_CONNACK + NR_CHOKE_FLAG; + *dptr++ = NR_CONNACK | NR_CHOKE_FLAG; *dptr++ = 0; skbn->free = 1; @@ -295,6 +298,8 @@ unsigned short nr_calculate_t1(struct sock *sk) for (t = 2, n = 0; n < sk->nr->n2count; n++) t *= 2; + if (t > 8) t = 8; + return t * sk->nr->rtt; } diff --git a/net/netrom/nr_timer.c b/net/netrom/nr_timer.c index 6ccfe3998faf..958e96aa78b3 100644 --- a/net/netrom/nr_timer.c +++ b/net/netrom/nr_timer.c @@ -58,7 +58,7 @@ void nr_set_timer(struct sock *sk) sk->timer.data = (unsigned long)sk; sk->timer.function = &nr_timer; - sk->timer.expires = 10; + sk->timer.expires = jiffies+10; add_timer(&sk->timer); } @@ -73,7 +73,7 @@ static void nr_reset_timer(struct sock *sk) sk->timer.data = (unsigned long)sk; sk->timer.function = &nr_timer; - sk->timer.expires = 10; + sk->timer.expires = jiffies+10; add_timer(&sk->timer); } @@ -140,7 +140,7 @@ static void nr_timer(unsigned long param) switch (sk->nr->state) { case NR_STATE_1: if (sk->nr->n2count == sk->nr->n2) { - nr_clear_tx_queue(sk); + nr_clear_queues(sk); sk->nr->state = NR_STATE_0; sk->state = TCP_CLOSE; sk->err = ETIMEDOUT; @@ -155,7 +155,7 @@ static void nr_timer(unsigned long param) case NR_STATE_2: if (sk->nr->n2count == sk->nr->n2) { - nr_clear_tx_queue(sk); + nr_clear_queues(sk); sk->nr->state = NR_STATE_0; sk->state = TCP_CLOSE; sk->err = ETIMEDOUT; @@ -170,7 +170,7 @@ static void nr_timer(unsigned long param) case NR_STATE_3: if (sk->nr->n2count == sk->nr->n2) { - nr_clear_tx_queue(sk); + nr_clear_queues(sk); sk->nr->state = NR_STATE_0; sk->state = TCP_CLOSE; sk->err = ETIMEDOUT; -- 2.39.5